超酷炫的Three.js示例

今天寫一個超級酷炫的Three.js示例,以下是文件源代碼:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Cool Three.js Page with Stars, Interactions, and Audio</title><style>body { margin: 0; overflow: hidden; background-color: black; }canvas { display: block; }#info {position: absolute;top: 20px;left: 20px;color: white;font-family: Arial, sans-serif;font-size: 20px;z-index: 1;}audio {position: fixed;top: 20px;right: 20px;z-index: 10;width: 300px;}</style>
</head>
<body><div id="info">🚀 Three.js Demo with Stars ? + Click/Audio FX</div><audio id="audio" src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" controls autoplay loop></audio><!-- 使用兼容非模塊版本的three.js和OrbitControls --><script src="https://cdn.jsdelivr.net/npm/three@0.140.0/build/three.min.js"></script><script src="https://cdn.jsdelivr.net/npm/three@0.140.0/examples/js/controls/OrbitControls.js"></script><script>const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,2000);camera.position.z = 100;const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);// 注意這里用 THREE.OrbitControls(舊版寫法)const controls = new THREE.OrbitControls(camera, renderer.domElement);// 著色器材質代碼(glow效果)const vertexShader = `varying vec3 vNormal;void main() {vNormal = normalize(normalMatrix * normal);gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const fragmentShader = `varying vec3 vNormal;void main() {float intensity = pow(0.6 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0) * intensity;}`;const shaderMaterial = new THREE.ShaderMaterial({vertexShader,fragmentShader,blending: THREE.AdditiveBlending,side: THREE.FrontSide,  // 改為 FrontSidetransparent: true});const geometry = new THREE.IcosahedronGeometry(2, 1);const glowGroup = new THREE.Group();for (let i = 0; i < 200; i++) {const mesh = new THREE.Mesh(geometry, shaderMaterial);mesh.scale.multiplyScalar(1.5);mesh.position.set((Math.random() - 0.5) * 400,(Math.random() - 0.5) * 400,(Math.random() - 0.5) * 400);glowGroup.add(mesh);}scene.add(glowGroup);// 星空背景粒子const starGeometry = new THREE.BufferGeometry();const starCount = 5000;const starVertices = [];for (let i = 0; i < starCount; i++) {starVertices.push((Math.random() - 0.5) * 2000);starVertices.push((Math.random() - 0.5) * 2000);starVertices.push((Math.random() - 0.5) * 2000);}starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3));const starMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.7 });const starField = new THREE.Points(starGeometry, starMaterial);scene.add(starField);// 燈光const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);scene.add(ambientLight);const pointLight = new THREE.PointLight(0xffffff, 1);camera.add(pointLight);scene.add(camera);// 鼠標點擊爆炸效果const raycaster = new THREE.Raycaster();const mouse = new THREE.Vector2();window.addEventListener('click', event => {mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;raycaster.setFromCamera(mouse, camera);const intersects = raycaster.intersectObjects(glowGroup.children);if (intersects.length > 0) {const mesh = intersects[0].object;const explosion = new THREE.Vector3((Math.random() - 0.5) * 100,(Math.random() - 0.5) * 100,(Math.random() - 0.5) * 100);mesh.position.add(explosion);}});// 音頻分析器const audio = document.getElementById('audio');const listener = new THREE.AudioListener();camera.add(listener);const sound = new THREE.Audio(listener);const audioLoader = new THREE.AudioLoader();audioLoader.load(audio.src, buffer => {sound.setBuffer(buffer);sound.setLoop(true);sound.setVolume(0.5);sound.play();});const analyser = new THREE.AudioAnalyser(sound, 32);function animate() {requestAnimationFrame(animate);const data = analyser.getAverageFrequency();glowGroup.children.forEach((mesh, i) => {const scale = 1.5 + Math.sin(Date.now() * 0.001 + i) * 0.3 + data / 256;mesh.scale.set(scale, scale, scale);});glowGroup.rotation.y += 0.002;starField.rotation.y += 0.0005;renderer.render(scene, camera);}animate();window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});</script>
</body>
</html>

一、整體思路

  • 使用非模塊版 Three.js(r140)與老寫法的 THREE.OrbitControls
  • 場景里有兩類物體:
    1. 200 個“發光”小多面體(用自定義 Shader 做到類似輝光的視覺)
    2. 5000 顆 Points 形式的星空粒子
  • 交互:點擊“發光體”會被隨機“炸開”移動一下。
  • 音頻:加載一段 MP3,用 AudioAnalyser 得到頻率均值,驅動 200 個發光體按音樂節奏伸縮。
  • 動畫:群組及星空做緩慢自轉,形成空間流動感。

二、HTML/CSS & 庫加載

  • body { overflow: hidden; background:black } 全屏 WebGL 背景。
  • 右上角是 <audio> 播放器。
  • 通過 CDN 引入: three@0.140.0/build/three.min.js three@0.140.0/examples/js/controls/OrbitControls.js 這兩者匹配“舊式全局 THREE”寫法。

三、場景基礎

scene / camera / renderer 標準三件套:

  • 透視相機 FOV 75,near=0.1 / far=2000,Z=100。

  • 抗鋸齒渲染器,填滿窗口。
    -(可優化)建議:renderer.setPixelRatio(window.devicePixelRatio) 讓高 DPI 更清晰(性能充裕時)。

  • 軌道控制器: const controls = new THREE.OrbitControls(camera, renderer.domElement); 允許鼠標旋轉/縮放觀察。
    想要“絲滑阻尼”,可: controls.enableDamping = true; // 并在動畫循環里加 controls.update();

四、自定義 Shader“發光體”

  • 頂點著色器:把法線變換到視圖空間,傳給片元: vNormal = normalize(normalMatrix * normal);
  • 片元著色器:根據與視線方向(z 軸)夾角計算強度: float intensity = pow(0.6 - dot(vNormal, vec3(0.0,0.0,1.0)), 2.0); gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0) * intensity; 視覺效果:面向鏡頭的區域更亮,形成“邊緣輝光/自發光”的感覺。
  • 材質參數: blending: THREE.AdditiveBlending, side: THREE.FrontSide, transparent: true 使用加色混合以疊加高亮。
    改進建議:加色+透明一般配 depthWrite:false 避免透明深度寫入帶來的排序偽影: depthWrite: false
  • 幾何體:IcosahedronGeometry(2, 1)(二十面體細分一級)。
    批量實例:創建 200 個網格,隨機分布在 [-200,200]3(因乘 400 再減半)。
    性能評估:每個約百來個三角形,200 個共 ~幾萬三角,WebGL 輕松應付;共享同一個 ShaderMaterial,節省材質開銷。
    (更進一步)可用 InstancedMesh 把 200 次 draw call 合并為 1 次,但要改為實例化方案。

五、星空粒子

  • BufferGeometry + Float32BufferAttribute 存 5000 個隨機頂點。
  • PointsMaterial({ color: 0xffffff, size: 0.7 }) 形成星點。
    (可選)可以加 sizeAttenuation:true(默認就是 true),基于透視縮放更自然;或改用帶紋理的點精靈實現更“星星”的感覺。

六、燈光

  • 有環境光和跟隨相機的點光,但

    當前兩類物體都“幾乎不吃光”

    • ShaderMaterial 未開啟 lights,著色完全自定義,不受燈光影響;
    • PointsMaterial 也是“自發光色”,不受燈光影響。
  • 因此這兩盞燈“視覺貢獻≈0”,可留作以后加其他受光物體時使用,也可以刪掉減一點場景狀態切換。

七、點擊“爆炸”交互(Raycaster)

  • 鼠標點擊 → 歸一化設備坐標 → raycaster.setFromCamera()intersectObjects(glowGroup.children)
  • 若命中,隨機向量把該網格位置抖走 50~100 單位。
    (可選)可改成給它一個速度,在 animate 中逐幀衰減,效果會更“物理”。

八、音頻與可視化

  • 頁面上有 <audio id="audio" controls autoplay loop>,同時 Three.js 里又:

    1. 創建 AudioListener 并掛相機;
    2. AudioLoader.load(audio.src, ...) 再次下載同一路徑音頻,塞進 THREE.Audioplay()
    3. AudioAnalyser(sound, 32) 獲取頻域數據均值 getAverageFrequency(),驅動縮放。
  • 潛在問題與改進

    1. 重復播放/重復下載
      頁面 <audio> 播放一次、AudioLoader 又播一次,音頻可能重疊。
      ? 選一種即可。最簡方案:復用 <audio> 元素作音源const sound = new THREE.Audio(listener); sound.setMediaElementSource(audioElement); // 直接用 <audio> 的流 const analyser = new THREE.AudioAnalyser(sound, 32); 這樣不再重復下載,播放器的播放/暫停也直接影響可視化。

    2. 自動播放策略

      現代瀏覽器通常禁止帶聲音的自動播放 。

      • 你雖然寫了 autoplaysound.play(),但往往會被攔下,除非用戶先有手勢(點擊等)。
      • 兼容做法:在第一次 pointerdown/click 時執行: const ac = listener.context; if (ac.state === 'suspended') ac.resume(); audioElement.play().catch(()=>{ /* 顯示提示或忽略 */ });
    3. 跨域 (CORS)
      若用 AudioLoader加遠程 MP3,需要服務器響應 Access-Control-Allow-Origin:*,否則 WebAudio 可能拿不到頻譜數據。

      • 復用 <audio crossorigin="anonymous"> + setMediaElementSource 可以更穩。
    4. FFT 分辨率
      new THREE.AudioAnalyser(sound, 32) 頻段較少,變化較“鈍”。

      • 想要更豐富的律動,可用 128/256,再用 getFrequencyData() 做更細粒度的驅動。
  • 動畫里用: const data = analyser.getAverageFrequency(); // 0~255 const scale = 1.5 + Math.sin(time + i) * 0.3 + data / 256; 疊加了“個體相位差的正弦擺動 + 音量項”,既保留群體呼吸感又隨音樂起伏。

九、動畫循環與窗口自適應

  • requestAnimationFrame(animate) 驅動渲染;群組與星空各自緩慢自轉。
  • 監聽 resize 更新相機投影與渲染尺寸,屬于標準寫法。
    (可優化)把 const t = performance.now()*0.001; 放循環開頭,少做一次 Date.now()
    若啟用 enableDamping,記得每幀 controls.update()

十、數值與視覺小建議

  • Shader 里這句: float intensity = pow(0.6 - dot(vNormal, vec3(0,0,1)), 2.0);dot(...) > 0.6 時底數為負,指數是 2.0(整數),在 GLSL 里通常仍能得到正值,但不同平臺精度可能不一致。
    更穩:夾取到非負區間: float intensity = pow(max(0.0, 0.6 - dot(vNormal, vec3(0,0,1))), 2.0);
  • 透明加色材質建議: const shaderMaterial = new THREE.ShaderMaterial({ vertexShader, fragmentShader, blending: THREE.AdditiveBlending, transparent: true, side: THREE.FrontSide, depthWrite: false // ★ 推薦 });
  • 畫質/性能開關: renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); 在 4K 屏上能避免過高像素負擔。

十一、一步到位的音頻改造示例(可直接替換你原來的音頻段)

目的:不重復下載,不觸發自動播放攔截時的黑屏“無響應”,并讓頻譜與播放器同步。

<audio id="audio" crossorigin="anonymous"src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"controls loop></audio>
// 音頻(替換原有 AudioLoader 部分)
const audioEl = document.getElementById('audio');
const listener = new THREE.AudioListener();
camera.add(listener);const sound = new THREE.Audio(listener);
sound.setMediaElementSource(audioEl); // 直接復用 <audio> 元素
const analyser = new THREE.AudioAnalyser(sound, 128);// 解決自動播放限制:用戶首次點擊頁面時恢復 AudioContext 并嘗試播放
let audioInit = false;
function initAudioOnce() {if (audioInit) return;audioInit = true;const ctx = listener.context;if (ctx.state === 'suspended') ctx.resume();audioEl.play().catch(() => {/* 可以提示“請點擊播放” */});
}
window.addEventListener('pointerdown', initAudioOnce, { once: true });

你可以直接用復制開頭的代碼到記事本并另存為.html格式然后在瀏覽器里跑,實現效果:
在這里插入圖片描述
該代碼可通過鼠標進行交互。


最后推薦一個超酷的ThreeJS網站:https://ykob.github.io/sketch-threejs/
在這里插入圖片描述

重拾編程的樂趣和無盡的探索欲在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93585.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93585.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93585.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從零開始大模型之實現GPT模型

從零開始大模型之從頭實現GPT模型1.大語言模型整體架構2 大語言的Transformer模塊2.1 層歸一化2.2 GELU激活函數2.3 前饋神經網絡2.4 快捷連接3 附錄3.1 anacondapython環境搭建1.數據預處理&#xff1a;原始數據進行詞元化&#xff0c;以及通過&#xff0c;依據詞匯表生成ID編…

[1Prompt1Story] 滑動窗口機制 | 圖像生成管線 | VAE變分自編碼器 | UNet去噪神經網絡

鏈接&#xff1a;https://github.com/byliutao/1Prompt1Story 這個項目是一個基于單個提示生成一致文本到圖像的模型。它在ICLR 2025會議上獲得了聚焦論文的地位。該項目提供了生成一致圖像的代碼、Gradio演示代碼以及基準測試代碼。 主要功能點: 使用單個提示生成一致的文本…

【GitHub開源AI精選】Sitcom-Crafter:北航聯合港中文等高校打造的劇情驅動3D動作生成系統

系列篇章&#x1f4a5; No.文章1【GitHub開源AI精選】LLM 驅動的影視解說工具&#xff1a;Narrato AI 一站式高效創作實踐2【GitHub開源AI精選】德國比勒費爾德大學TryOffDiff——高保真服裝重建的虛擬試穿技術新突破3【GitHub開源AI精選】哈工大&#xff08;深圳&#xff09;…

智和信通全棧式運維平臺落地深圳某學院,賦能運維管理提質提效

深圳某學院校園內信息化設備眾多&#xff0c;網絡環境復雜&#xff0c;使得網絡管理工作面臨著諸多難題與挑戰。為保障校園網絡能夠穩定、高效地運行&#xff0c;學院亟須構建一套集高效、智能、協同于一體的網絡運維平臺。 對運維平臺的期望包括&#xff1a; 實現校園內教學…

開疆智能Ethernet轉ModbusTCP網關連接測聯無紙記錄儀配置案例

本案例是通過Ethernet轉ModbusTCP網關將記錄儀數據傳送到歐姆龍PLC&#xff0c;具體操作過程如下。歐姆龍PLC配置首先打開主站組態軟件“Sysmac Studio”并新建項目。設置PLC的IP地址點擊工具-Ethernet/IP連接設置&#xff0c;在彈出的選個框內選擇顯示EDS庫添加網關eds文件開始…

Eureka故障處理大匯總

#作者&#xff1a;Unstopabler 文章目錄1. Eureka 服務啟動故障處理1.1 端口占用導致啟動失敗1.2 配置文件錯誤導致啟動失敗1.3 依賴沖突與類加載錯誤2. 服務注冊與發現異常2.1 服務無法注冊到 Eureka2.2 Eureka 控制臺看不到注冊的服務2.3 服務注冊后立即被剔除3. Eureka 集群…

基于Transformer的機器翻譯——模型篇

1.模型結構 本案例整體采用transformer論文中提出的結構&#xff0c;部分設置做了調整。transformer網絡結構介紹可參考博客——入門級別的Transformer模型介紹&#xff0c;這里著重介紹其代碼實現。 模型的整體結構&#xff0c;包括詞嵌入層&#xff0c;位置編碼&#xff0c;…

上位機TCP/IP通信協議層常見問題匯總

以太網 TCP 通信是上位機開發中常用的通信方式&#xff0c;西門子 S7 通信、三菱 MC 通信以及 MQTT、OPC UA、Modbus TCP 等都是其典型應用。為幫助大家更好地理解 TCP 通信&#xff0c;我整理了一套常見問題匯總。一、OSI參考模型與TCP/IP參考模型基于TCP/IP的參考模型將協議分…

搭建ktg-mes

項目地址 該安裝事項&#xff0c;基于當前最新版 2025年8月16日 之前的版本 下載地址&#xff1a; 后端JAVA 前端VUE 后端安裝&#xff1a; 還原數據表 路徑&#xff1a;根目錄/sql/ry_20210908.sql、根目錄/sql/quartz.sql、根目錄/doc/實施文檔/ktgmes-202505180846.sql.g…

uniapp純前端繪制商品分享圖

效果如圖// useMpCustomShareImage.ts interface MpCustomShareImageData {canvasId: stringprice: stringlinePrice: stringgoodsSpecFirmName: stringimage: string }const CANVAS_WIDTH 500 const CANVAS_HEIGHT 400 const BG_IMAGE https://public-scjuchuang.oss-cn-ch…

醋酸鑭:看不見的科技助力

雖然我們每天都在使用各種科技產品&#xff0c;但有些關鍵的化學物質卻鮮為人知。醋酸鑭&#xff0c;就是這樣一種默默為科技進步貢獻力量的“幕后英雄”。它不僅是稀土元素鑭的一種化合物&#xff0c;還在許多高科技領域中發揮著重要作用。今天&#xff0c;讓我們一起來了解這…

蒼穹外賣日記

day 1 windows系統啟動nginx報錯: The system cannot find the path specified 在啟動nginx的時候報錯&#xff1a; /temp/client_body_temp" failed (3: The system cannot find the path specified) 解決辦法&#xff1a; 1.檢查nginx的目錄是否存在中文 &#xff0c;路…

樓宇自控系統賦能建筑全維度管理,實現環境、安全與能耗全面監管

隨著城市化進程加速和綠色建筑理念普及&#xff0c;現代樓宇管理正經歷從粗放式運營向精細化管控的轉型。樓宇自控系統&#xff08;BAS&#xff09;作為建筑智能化的核心載體&#xff0c;通過物聯網、大數據和人工智能技術的深度融合&#xff0c;正在重構建筑管理的全維度框架&…

【HarmonyOS】Window11家庭中文版開啟鴻蒙模擬器失敗提示未開啟Hyoer-V

【HarmonyOS】Window11家庭中文版開啟鴻蒙模擬器失敗提示未開啟Hyoer-V一、問題背景 當鴻蒙模擬器啟動時&#xff0c;提示如下圖所示&#xff1a;因為Hyper-V 僅在 Windows 11 專業版、企業版和教育版中作為預裝功能提供&#xff0c;而家庭版&#xff08;包括中文版&#xff09…

vscode遠程服務器出現一直卡在正在打開遠程和連接超時解決辦法

項目場景&#xff1a; 使用ssh命令或者各種軟件進行遠程服務器之后&#xff0c;結果等到幾分鐘之后自動斷開連接問題解決。vscode遠程服務器一直卡在正在打開遠程狀態問題解決。問題描述 1.連接超時 2.vscode遠程一直卡在正在打開遠程...原因分析&#xff1a;需要修改設置超時斷…

Maven下載和配置-IDEA使用

目錄 一 MAVEN 二 三個倉庫 1. 本地倉庫&#xff08;Local Repository&#xff09; 2. 私有倉庫&#xff08;Private Repository&#xff0c;公司內部倉庫&#xff09; 3. 遠程倉庫&#xff08;Remote Repository&#xff09; 依賴查找流程&#xff08;優先級&#xff09…

Dify實戰應用指南(上傳需求稿生成測試用例)

一、Dify平臺簡介 Dify是一款開源的大語言模型&#xff08;LLM&#xff09;應用開發平臺&#xff0c;融合了“Define&#xff08;定義&#xff09; Modify&#xff08;修改&#xff09;”的設計理念&#xff0c;通過低代碼/無代碼的可視化界面降低技術門檻。其核心價值在于幫助…

學習日志35 python

1 Python 列表切片一、切片完整語法列表切片的基本格式&#xff1a; 列表[start:end:step]start&#xff1a;起始索引&#xff08;包含該位置元素&#xff0c;可省略&#xff09;end&#xff1a;結束索引&#xff08;不包含該位置元素&#xff0c;可省略&#xff09;step&#…

Linux -- 文件【下】

目錄 一、EXT2文件系統 1、宏觀認識 2、塊組內部構成 2.1 Data Block 2.2 i節點表(Inode Table) 2.3 塊位圖&#xff08;Block Bitmap&#xff09; 2.4 inode位圖&#xff08;Inode Bitmap&#xff09; 2.5 GDT&#xff08;Group Descriptor Table&#xff09; 2.6 超…

谷歌手機刷機和面具ROOT保姆級別教程

#比較常用的谷歌輸入root面具教程,逆向工程師必修課程# 所需工具與材料清單 真機設備 推薦使用 Google Pixel 4 或其他兼容設備&#xff0c;確保硬件支持刷機操作。 ADB 環境配置 通過安裝 Android Studio 自動配置 ADB 和 Fastboot 工具。安裝完成后&#xff0c;需在系統環境…