three实现三维粒子跟随音乐跳动音频可视化效果代码
代码语言:html
所属分类:三维
代码描述:three实现三维粒子跟随音乐跳动音频可视化效果代码
代码标签: three 三维 粒子 跟随 音乐 跳动 音频 可视化
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> html, body { margin: 0; overflow: hidden; font-family: sans-serif; background: #13091B; height: 100%; } #three-container { position: absolute; left: 0; top: 0; } .container { display: flex; align-items: center; justify-content: center; height: 100%; } .play-btn { color: #13091B; background: #007A99; display: inline-block; padding: 16px 48px; font-size: 18px; cursor: pointer; border-radius: 4px; letter-spacing: 0.1em; z-index: 1; } </style> </head> <body > <audio id="song" src="" style="display:none;"></audio> <div class="container"> <div class="play-btn">PLAY</div> </div> <div id="three-container"></div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.72.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/OrbitControls.72.js"></script> <script > var mContainer; var mCamera, mRenderer; var mControls; var mShadowColor = 0x13091B; //0x1B0914 var mScene; var mLight; var mLight2; var mLight3; var mUseAA = true; var mParticleCount = 250000; var mParticleSystem; var mDuration; var mPathLength = 32; var mAudioElement = document.getElementById('song'); var mAnalyser; var mPlayBtn = document.querySelector('.play-btn'); var mPlayBtnContainer = document.querySelector('.container'); mPlayBtn.addEventListener('click', function () { mAnalyser.context.resume().then(() => { console.log('Playback resumed successfully'); }); mPlayBtnContainer.style.display = 'none'; mAudioElement.currentTime = 0; mAudioElement.play(); mCamera.position.set(0, 0, 1200); }); mAudioElement.addEventListener('ended', function () { mPlayBtnContainer.style.display = 'flex'; }); window.onload = function () { init(); }; function init() { initAudio(); initTHREE(); initControls(); initParticleSystem(); requestAnimationFrame(tick); window.addEventListener('resize', resize, false); } function initAudio() { mAudioElement.crossOrigin = "anonymous"; mAudioElement.src = '//repo.bfw.wiki/bfwrepo/sound/63e1f2ab02799.mp3'; mAnalyser = new SpectrumAnalyzer(mPathLength * 0.5, 0.80); mAnalyser.setSource(mAudioElement); } function initTHREE() { mRenderer = new THREE.WebGLRenderer({ antialias: mUseAA }); mRenderer.setSize(window.innerWidth, window.innerHeight); //mRenderer.setClearColor(0xffffff); mRenderer.setClearColor(mShadowColor); mContainer = document.getElementById('three-container'); mContainer.appendChild(mRenderer.domElement); mCamera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 5000); mCamera.position.set(0, 0, 1200); mScene = new THREE.Scene(); mLight = new THREE.PointLight(0xffffff, 1, 1200, 2); mLight.position.set(0, 0, 0); mScene.add(mLight); mLight2 = new THREE.DirectionalLight(0xFF311F, 0.25); mLight2.position.set(0, 1, 1); mScene.add(mLight2); mLight3 = new THREE.DirectionalLight(0x007A99, 0.25); mLight3.position.set(0, 1, -1); mScene.add(mLight3); } function initControls() { mControls = new THREE.OrbitControls(mCamera, mRenderer.domElement); mControls.autoRotate = true; mControls.enableZoom = true; mControls.enablePan = false; mControls.constraint.minDistance = 10; mControls.constraint.maxDistance = 1200; mControls.constraint.minPolarAngle = Math.PI * 0.4; mControls.constraint.maxPolarAngle = Math.PI * 0.6; } function initParticleSystem() { var prefabGeometry = new THREE.PlaneGeometry(4, 4); var bufferGeometry = new THREE.BAS.PrefabBufferGeometry(prefabGeometry, mParticleCount); //bufferGeometry.computeVertexNormals(); // generate additional geometry data var aDelayDuration = bufferGeometry.createAttribute('aDelayDuration', 2); var aPivot = bufferGeometry.createAttribute('aPivot', 3); var aAxisAngle = bufferGeometry.createAttribute('aAxisAngle', 4); var aColor = bufferGeometry.createAttribute('color', 3); var i, j, offset; // buffer time offset var delay; var duration; var prefabDelay = 0.00015; var vertexDelay = 0.0175; var minDuration = 32.0; var maxDuration = 56.5; mDuration = maxDuration + prefabDelay * mParticleCount + vertexDelay * prefabGeometry.vertices.length; for (i = 0, offset = 0; i < mParticleCount; i++) { delay = i * prefabDelay; duration = THREE.Math.randFloat(minDuration, maxDuration); for (j = 0; j < prefabGeometry.vertices.length; j++) { aDelayDuration.array[offset++] = delay + j * vertexDelay; aDelayDuration.array[offset++] = duration; } } // buffer pivot var pivot = new THREE.Vector3(); for (i = 0, offset = 0; i < mParticleCount; i++) { pivot.x = THREE.Math.randFloat(0, 2); pivot.y = THREE.Math.randFloat(0, 2); pivot.z = THREE.Math.randFloat(0, 2); for (j = 0; j < prefabGeometry.vertices.length; j++) { aPivot.array[offset++] = pivot.x; aPivot.array[offset++] = pivot.y; aPivot.array[offset++] = pivot.z; } } // buffer axis angle var axis = new THREE.Vector3(); var angle = 0; for (i = 0, offset = 0; i < mParticleCount; i++) { axis.x = THREE.Math.randFloatSpread(2); axis.y = THREE.Math.randFloatSpread(2); axis.z = THREE.Math.randFloatSpread(2); axis.normalize(); angle = Math.PI * THREE.Math.randInt(48, 64); for (j = 0; j < prefabGeometry.vertices.length; j++) { aAxisAngle.array[offset++] = axis.x; aAxisAngle.array[offset++] = axis.y; aAxisAngle.array[offset++] = axis.z; aAxisAngle.array[offset++] = angle; } } // buffer color var color = new THREE.Color(); var h, s, l; for (i = 0, offset = 0; i < mParticleCount; i++) { //h = i / mParticleCount; h = THREE.Math.randFloat(0.5, 1.00); s = THREE.Math.randFloat(0.5, 0.75); l = THREE.Math.randFloat(0.25, 0.5); color.setHSL(h, s, l); for (j = 0; j < prefabGeometry.vertices.length; j++) { aColor.array[offset++] = color.r; aColor.array[offset++] = color.g; aColor.array[offset++] = color.b; } } // buffer spline (uniform) var pathArray = []; var radiusArray = []; var length = mPathLength; var x, y, z; for (i = 0; i < length; i++) { if (!i) { x = 0; y = -1400; z = 0; } else if (!(i - length + 1)) { x = 0; y = 1200; z = 0; } else { x = THREE.Math.randFloatSpread(600); y = -400 + 800 / length * i + THREE.Math.randFloatSpread(200); z = THREE.Math.randFloatSpread(600); } pathArray.push(x, y, z); radiusArray.push(0); } var material = new THREE.BAS.PhongAnimationMaterial( // custom parameters & THREE.MeshPhongMaterial parameters { vertexColors: THREE.VertexColors, shading: THREE.FlatShading, side: THREE.DoubleSide, defines: { PATH_LENGTH: pathArray.length / 3 }, uniforms: { uTime: { type: 'f', value: 0 }, uPath: { type: 'fv', value: pathArray }, uRadius: { type: 'fv1', value: radiusArray }, uRoundness: { type: 'v2', value: new THREE.Vector2(2, 2) } }, shaderFunctions: [ THREE.BAS.ShaderChunk['quaternion_rotation'], THREE.BAS.ShaderChunk['catmull-rom'], THREE.BAS.ShaderChunk['ease_in_out_cubic']], shaderParameters: [ 'uniform float uTime;', 'uniform vec3 uPath[PATH_LENGTH];', 'uniform float uRadius[PATH_LENGTH];', 'uniform vec2 uRoundness;', 'attribute vec2 aDelayDuration;', 'attribute vec3 aPivot;', 'attribute vec4 aAxisAngle;'], shaderVertexInit: [ 'float tDelay = aDelayDuration.x;', 'float tDuration = aDelayDuration.y;', 'float tTime = clamp(uTime - tDelay, 0.0, tDuration);', 'float tProgress = tTime / tDuration;', 'float angle = aAxisAngle.w * tProgress;', 'vec4 tQuat = quatFromAxisAngle(aAxisAngle.xyz, angle);'], shaderTransformNormal: [ 'objectNormal = rotateVector(tQuat, objectNormal);'], shaderTransformPosition: [ 'float tMax = float(PATH_LENGTH - 1);', 'float tPoint = tMax * tProgress;', 'float tIndex = floor(tPoint);', 'float tWeight = tPoint - tIndex;', 'int i0 = int(max(0.0, tIndex - 1.0));', 'int i1 = int(tIndex);', 'int i2 = int(min(tIndex + 1.0, tMax));', 'int i3 = int(min(tIndex + 2.0, tMax));', 'vec3 p0 = uPath[i0];', 'vec3 p1 = uPath[i1];', 'vec3 p2 = uPath[i2];', 'vec3 p3 = uPath[i3];', 'float radius = catmullRom(uRadius[i0], uRadius[i1], uRadius[i2], uRadius[i3], tWeight);', 'transformed += aPivot * radius;', 'transformed = rotateVector(tQuat, transformed);', 'transformed += catmullRom(p0, p1, p2, p3, uRoundness, tWeight);'] }, // THREE.MeshPhongMaterial uniforms { shininess: 16, specular: 0xffd700, emissive: mShadowColor }); mParticleSystem = new THREE.Mesh(bufferGeometry, material); mParticleSystem.frustumCulled = false; mScene.add(mParticleSystem); } function tick() { update(); render(); requestAnimationFrame(tick); } function update() { mControls.update(); mAnalyser.updateSample(); var uniform = mParticleSystem.material.uniforms['uRadius'].value; var data = mAnalyser.frequencyByteData; var dataArray = []; var cap = data.length * 0.5; var i; //for (i = cap - 1; i >= 0; i--) { for (i = 0; i < cap; i++) { dataArray.push(data[i]); } for (i = cap - 1; i >= 0; i--) { //for (i = 0; i < cap; i++) { dataArray.push(data[i]); } //for (i = cap - 1; i >= 0; i--) { for (i = 0; i < cap; i++) { dataArray.push(data[i]); } for (i = cap - 1; i >= 0; i--) { //for (i = 0; i < cap; i++) { dataArray.push(data[i]); } for (i = 0; i < dataArray.length; i++) { if (i && dataArray.length - i > 1) { var val = dataArray[i] / 255; uniform[i] = Math.max(1, val * val * val * 48); } else { uniform[i] = 128; } } var a0 = mAnalyser.getAverageFloat(); var r = 8 * a0 * a0 * a0 + 1; mParticleSystem.material.uniforms['uRoundness'].value.set(r, r); var a1 = mAnalyser.getAverageFloat() * 2; mLight.intensity = a1 * a1; mLight2.intensity = a1 * a1 * a1 * a1 * 0.5; mLight3.intensity = a1 * a1 * a1 * a1 * 0.5; mParticleSystem.material.uniforms['uTime'].value = mAudioElement.currentTime || 0; } function render() { mRenderer.render(mScene, mCamera); } function resize() { mCamera.aspect = window.innerWidth / window.innerHeight; mCamera.updateProjectionMatrix(); mRenderer.setSize(window.innerWidth, window.innerHeight); } ///////////////////////////////// // Spectrum Analyser ///////////////////////////////// // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode function SpectrumAnalyzer(binCount, smoothingTimeConstant) { var Context = window["AudioContext"] || window["webkitAudioContext"]; this.context = new Context(); this.analyzerNode = this.context.createAnalyser(); this.setBinCount(binCount); this.setSmoothingTimeConstant(smoothingTimeConstant); } SpectrumAnalyzer.prototype = { setSource: function (source) { //this.source = source; this.source = this.context.createMediaElementSource(source); this.source.connect(this.analyzerNode); this.analyzerNode.connect(this.context.destination); }, setBinCount: function (binCount) { this.binCount = binCount; this.analyzerNode.fftSize = binCount * 2; this.frequencyByteData = new Uint8Array(binCount); // frequency this.timeByteData = new Uint8Array(binCount); // waveform }, setSmoothingTimeConstant: function (smoothingTimeConstant) { this.analyzerNode.smoothingTimeConstant = smoothingTimeConstant; }, getFrequencyData: function () { return this.frequencyByteData; }, getTimeData: function () { return this.timeByteData; }, // not save if out of bounds getAverage: function (index, count) { var total = 0; var start = index || 0; var end = start + (count || this.binCount); for (var i = start; i < end; i++) { total += this.frequencyByteData[i]; } return total / (end - start); }, getAverageFloat: function (index, count) { return this.getAverage(index, count) / 255; }, updateSample: function () { this.analyzerNode.getByteFrequencyData(this.frequencyByteData); this.analyzerNode.getByteTimeDomainData(this.timeByteData); } }; /////////////// // buffer animation system /////////////// THREE.BAS = {}; THREE.BAS.ShaderChunk = {}; THREE.BAS.ShaderChunk["animation_time"] = "float tDelay = aAnimation.x;\nfloat tDuration = aAnimation.y;\nfloat tTime = clamp(uTime - tDelay, 0.0, tDuration);\nfloat tProgress = ease(tTime, 0.0, 1.0, tDuration);\n"; THREE.BAS.ShaderChunk["catmull-rom"] = "vec3 catmull.........完整代码请登录后点击上方下载按钮下载查看
网友评论0