three实现三维音频可视化跳动动画效果代码
代码语言:html
所属分类:三维
代码描述:three实现三维音频可视化跳动动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> @import url('https://fonts.googleapis.com/css?family=Architects+Daughter|Orbitron'); * { margin: 0; padding: 0; } html, body { overflow: hidden; font-family:'Orbitron',sans-serif; font-size:14px; } /* dat.gui align to left */ .lil-gui.autoPlace{ right:auto !important; left:15px !important; } .Experience { position:relative; width:100vw; height:100vh; } .Experience > .Experience_Canvas { top:0; left:0; position:absolute; outline: none; filter:grayscale(0%); transition:filter 1s; } .Experience[loading = "true"] > .Experience_Canvas { filter:grayscale(90%); } .Experience_Panel { position:relative; border:1px solid #000022; background-color: rgba(30, 30, 90, 0.75); color:#FFFFFF; border-radius: 6px; box-shadow: 5px 5px 5px rgba(0,0,0, 0.5); } .Experience > .Experience_Loading { padding:0.6em; /* width:4em;*/ margin:auto; top: calc(50vh - 10px); height: 18px; display:none; font-family:'Orbitron',sans-serif; font-size:max(1.5vw, 1.5vh); } .Experience[loading = "true"] > .Experience_Loading { display:table; } /* Group of controls (fps, button logo, button full screen) */ .Experience_Controls { position:fixed; bottom :0; right:0; z-index:10000; } .Experience_Static { user-select: none; } .Experience_Static, .Experience_Control { position:relative; width:48px; /*max(3.2vw, 3.2vh);*/ height:48px; /*max(3.2vw, 3.2vh);*/ margin-bottom:max(0.5vw, 0.5vh); margin-right:max(0.5vw, 0.5vh); padding:6px; /* padding:max(0.4vw, 0.4vh);*/ text-align: center; border:2px solid transparent; display: block; margin-left: auto; transition:border 0.4s; } .Experience_FPS { font-size:24px; } .Experience_TxtFPS { font-size:14px; } .Experience_Control:hover { border:2px solid rgb(234, 80, 78); cursor:pointer; } .Experience_Control > img { transition:transform 0.4s; width:48px; height:48px; position:relative; } .Experience_Control:hover > img { transform: scale(1.5, 1.5); } #restoreScreen { display:none; } #Logo { display: block; transition: width 0.33s ease-in; } /* Logo svg need to be fixed on the right, because of the letter logo animation */ #Logo img { position:absolute; right: 6px; } #Logo > * { pointer-events: none; } #Logo:hover { width:280px; } #Logo > #LogoText { position:absolute; bottom:14px; margin-top:3px; transition:0.4s; width:230px; /* 12 caracters * 400px */ font-size:24px; } #Logo > #LogoText > span { transition:0.33s cubic-bezier(.17,-0.42,0,1.15); opacity:0; position: relative; display: inline-block; color:#FFF; } #Logo:hover > #LogoText > span { position:relative; opacity:1; left:230px; animation: LogoAnimation 0.33s 0.33s cubic-bezier(.17,-0.42,0,1.15); animation-fill-mode:forwards; } /* Color rojo del 33 */ #Logo > #LogoText > span:nth-child(11), #Logo > #LogoText > span:nth-child(12) { color: rgb(234, 80, 78); } #Logo:hover > #LogoText > span:nth-child(1) { animation-delay: 0.55s; } #Logo:hover > #LogoText > span:nth-child(2) { animation-delay: 0.50s; } #Logo:hover > #LogoText > span:nth-child(3) { animation-delay: 0.45s; } #Logo:hover > #LogoText > span:nth-child(4) { animation-delay: 0.40s; } #Logo:hover > #LogoText > span:nth-child(5) { animation-delay: 0.35s; } #Logo:hover > #LogoText > span:nth-child(6) { animation-delay: 0.30s; } #Logo:hover > #LogoText > span:nth-child(7) { animation-delay: 0.25s; } #Logo:hover > #LogoText > span:nth-child(8) { animation-delay: 0.20s; } #Logo:hover > #LogoText > span:nth-child(9) { animation-delay: 0.15s; } #Logo:hover > #LogoText > span:nth-child(10) { animation-delay: 0.10s; } #Logo:hover > #LogoText > span:nth-child(11) { animation-delay: 0.05s; } #Logo:hover > #LogoText > span:nth-child(12) { animation-delay: 0.0s; } @keyframes LogoAnimation { 0% { left:230px; } 100% { left:0px; } } /* * Audio controls */ .Experience_AudioControls { user-select: none; position:fixed; display:flex; flex-flow: row; flex-direction:column; /* flex-wrap: wrap;*/ bottom:1vh; /* height:80px;*/ width:75vw; left:12.5vw; /* padding:0 0 min(1vw, 1vh) 0 0;*/ pointer-events: none; } .Experience_AudioControls label, .Experience_AudioControls button { font-size:14px !important; font-family:'Orbitron',sans-serif; } .Experience_AC_Play { /* margin:max(0.5vw, 0.5vh);*/ flex-basis:32px; } .Experience_AC_Play > button { width:62px; height:62px; border-radius: 100px; background-color: rgba(30, 30, 150, 1.0); cursor:pointer; color:#fff; transition:background-color 0.5s; pointer-events:all; } .Experience_AC_Play > button:hover { background-color: rgb(49, 49, 255); } .Experience_AC_Songs { flex: 3 0 10%; /* margin:max(0.5vw, 0.5vh);*/ position:relative; /* top:6px;*/ /* flex-basis:176px;*/ flex-basis:32px; } .Experience_AC_Songs > select { position:relative; left:5px; height: 22px; pointer-events:all; } .Experience_AC_Volume { flex-basis:32px; /* margin:max(0.5vw, 0.5vh);*/ /* flex-basis:150px;*/ } .Experience_AC_Volume > input { position:relative; left:5px; top:5px; pointer-events:all; } .Experience_AC_Time { flex-basis:32px; /* margin:max(0.5vw, 0.5vh);*/ } .Experience_AC_Time > input { position:relative; left:5px; top:5px; width: calc(100% - 10px); pointer-events:all; } .Experience td { color:#ffffff; text-shadow: 1px 1px #000000; } /* Pay & Pause buttons */ .Experience_Play, .Experience_Pause { position: fixed; margin-bottom: max(0.5vw, 0.5vh); margin-left: max(0.5vw, 0.5vh); bottom:0; } /* when play is true, play button is enabled, and pause button is disabled, when is false is the oposite */ .Experience_Play[play="false"], .Experience_Pause[play="true"] { display:none; } .Experience_SongInfo { position:fixed; margin-bottom: max(0.5vw, 0.5vh); margin-left: max(0.5vw, 0.5vh); bottom:70px; padding:12px; left:-500px; transition:left 0.4s cubic-bezier(.17,-0.42,0,1.15); } .Experience_SongInfo[visible="false"] { left:0px; animation: SongInfoAnimation 0.4s 5s cubic-bezier(.17,-0.42,0,1.15); animation-fill-mode:forwards; } .Experience_SongInfo td { padding: 4px; color:#CCCCCC; } .Experience_SongInfo a, .Experience_SongInfo a:visited { color:#FFFFFF; } @keyframes SongInfoAnimation { 0% { opacity:1; left:0px; } 100% { opacity:0; left:-300px; } } </style> </head> <body > <!-- import THREE.js cdn --> <script type="importmap"> { "imports": { "three": "//repo.bfw.wiki/bfwrepo/js/module/three/build/151/three.module.js", "three/addons/": "//repo.bfw.wiki/bfwrepo/js/module/three/examples/151/jsm/" } } </script> <!-- lil.gui --> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/lil-gui.umd.min.js"></script> <link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/lil-gui.min.css"> <!-- Osciloscope vertex shader--> <script id="OsciloscopeCircularVertexShader" type="x-shader/x-vertex"> varying vec2 vUv; void main() { vec4 modelPosition = modelMatrix * vec4(position , 1.0); vec4 viewPosition = viewMatrix * modelPosition; vec4 projectionPosition = projectionMatrix * viewPosition; gl_Position = projectionPosition; vUv = uv; } </script> <!-- Osciloscope fragment shader--> <script id="OsciloscopeCircularFragmentShader" type="x-shader/x-fragment"> uniform sampler2D uAudioTexture; // AUdio data values uniform float uAudioStrength; // Audio strength uniform float uAudioZoom; // Audio Zoom uniform vec3 uColor; // Color uniform float uSize; // Line size uniform float uRadius; // Radius size varying vec2 vUv; #define PI 3.14159265 void main() { float thickness = uSize; float space = 0.5 - (thickness * 2.0) - uRadius; vec2 center = vec2(vUv.x - 0.5, vUv.y - 0.5); float dist = length(center); float rad = atan(vUv.y - 0.5, vUv.x - 0.5); // normalize angle 0 to 1 float normAngle = 0.0; // rad its greater than 0 if (rad < 0.0) { normAngle = (rad + PI) / PI; } // rad its below 0 else { // Invert the normalized angle normAngle = 1.0 - (1.0 + ((rad - PI) / PI)); } // Get the audio value from linear audio data texture (1024*1) // Red channel has the frequency that starts from 0 to 1 float audioValue = ((texture2D(uAudioTexture, vec2(vUv.x / uAudioZoom, 0.0)).g - .5) * uAudioStrength) + .5; dist -= audioValue * uAudioStrength; vec4 color = vec4(0.0, 0.0, 0.0, 0.0); if (dist > uRadius - thickness && dist < uRadius) { color = vec4(uColor, 1.0); } gl_FragColor = color; } </script> <!-- Default depth vertex shader--> <script id="DepthVertexShader" type="x-shader/x-vertex"> varying vec2 vUv; #include <common> #include <uv_pars_vertex> #include <displacementmap_pars_vertex> #include <morphtarget_pars_vertex> #include <skinning_pars_vertex> #include <logdepthbuf_pars_vertex> #include <clipping_planes_pars_vertex> varying vec2 vHighPrecisionZW; void main() { #include <uv_vertex> #include <skinbase_vertex> #ifdef USE_DISPLACEMENTMAP #include <beginnormal_vertex> #include <morphnormal_vertex> #include <skinnormal_vertex> #endif #include <begin_vertex> vUv = uv; #include <morphtarget_vertex> #include <skinning_vertex> #include <displacementmap_vertex> #include <project_vertex> #include <logdepthbuf_vertex> #include <clipping_planes_vertex> vHighPrecisionZW = gl_Position.zw; } </script> <!-- Osciloscope depth fragment shader--> <script id="OsciloscopeCircularDepthFragmentShader" type="x-shader/x-fragment"> uniform float uSize; uniform sampler2D uAudioTexture; uniform float uAudioStrength; uniform float uAudioZoom; uniform float uRadius; varying vec2 vUv; // Coordenadas UV del fragmento #if DEPTH_PACKING == 3200 uniform float opacity; #endif #include <common> #include <packing> #include <uv_pars_fragment> #include <map_pars_fragment> #include <alphamap_pars_fragment> #include <alphatest_pars_fragment> #include <logdepthbuf_pars_fragment> #include <clipping_planes_pars_fragment> varying vec2 vHighPrecisionZW; void main() { #include <clipping_planes_fragment> vec4 diffuseColor = vec4( 1.0 ); #if DEPTH_PACKING == 3200 diffuseColor.a = opacity; #endif float thickness = uSize; float space = 0.5 - (thickness * 2.0) - uRadius; vec2 center = vec2(vUv.x - 0.5, vUv.y - 0.5); float dist = length(center); float rad = atan(vUv.y - 0.5, vUv.x - 0.5); // normalize angle 0 to 1 float normAngle = 0.0; // rad its greater than 0 if (rad < 0.0) { normAngle = (rad + PI) / PI; } // rad its below 0 else { // Invert the normalized angle normAngle = 1.0 - (1.0 + ((rad - PI) / PI)); } // Get the audio value from linear audio data texture (1024*1) // Red channel has the frequency that starts from 0 to 1 float audioValue = ((texture2D(uAudioTexture, vec2(vUv.x / uAudioZoom, 0.0)).g - .5) * uAudioStrength) + .5; dist -= audioValue * uAudioStrength; vec4 color = vec4(0.0, 0.0, 0.0, 0.0); if (dist > uRadius - thickness && dist < uRadius) { color = vec4(0.0, 0.75, 0.0, 1.0); } else { discard; } diffuseColor = color; // gl_FragColor = vec4(color.r); // if (color.a == 0.0) discard; #include <map_fragment> #include <alphamap_fragment> #include <alphatest_fragment> #include <logdepthbuf_fragment> float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; #if DEPTH_PACKING == 3200 gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); #elif DEPTH_PACKING == 3201 gl_FragColor = packDepthToRGBA( fragCoordZ ); #endif } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; /* Experience created by Josep Antoni Bover for https://devildrey33.es. * This Audio shader is a part of my Audio-PlayGround experience : * https://github.com/devildrey33/Audio-PlayGround * * #2 a circular osciloscope. * - Play with Audio Strength, Line size, and radius to achieve different effects * - This script creates an audio data texture with the getByteTimeDomainData values * on the green channel. (Its more easy than creating extra attributes, and looks better) * - Then this texture is sent to the osciloscope shader and the osciloscope depth shader. * - You can drag & drop any song of your computer to play it. * - Song name : After Us * Song artist : From Sky To Abyss * URL : https://www.jamendo.com/track/1594018/after-us * * Created on : 20/04/2023 * Last modification : 26/04/2023 */ // Clamp number between two values Math.clamp = (value, min, max) => { return Math.min(Math.max(value, min), max); } // Simple 2d buffer canvas class BufferCanvas { constructor(width, height) { this.canvas = document.createElement("canvas"); this.canvas.setAttribute("width", width); this.canvas.setAttribute("height", height); this.context = this.canvas.getContext("2d", { willReadFrequently : true }); this.width = width; this.height = height; } } export default class CodepenThreeAudio { // Default options options = { // Y position. Use 'auto' to center canvas horizontaly to the view port top : 0, // X position. Use 'auto' to center canvas verticaly to the view port left : 0, // Width in pixels. Use 'auto' to fit all viewport width width : "auto", // Height in pixels. Use 'auto' to fit all viewport height height : "auto", // Show framerate inside the butons frame showFPS : true, // Show full screen buton in the buttons frame buttonFullScreen : true, // Show my logo buton in the buttons frame (that redirects to devildrey33.es) buttonLogo : true, // Show a github icon to go to the example repository buttonGitHub : true, // GitHub url for this project (only used if buttonGitHub is true) urlGitHub : "https://github.com/devildrey33/Audio-PlayGround", // Element where canvas is inserted (by default is document.body) // For example you can use document.getElementById() to retrieve tag inside you want to create the canvas rootElement : document.body, // Anti alias (by default true) antialias : true, // OrbitControls enabled by default orbitControls : true, // Song path songPath : "//repo.bfw.wiki/bfwrepo/sound/61b1c68d5cad6.mp3" }; constructor(options) { // Merge options this.options = { ...this.options, ...options }; // Create basic html elements this.createHtml(); // Setup sizes this.setupSizes(); // Setup audio texture this.bufferCanvasLinear = new BufferCanvas(1024, 1); this.bufferCanvasLinear.texture = new THREE.CanvasTexture(this.bufferCanvasLinear.canvas); this.imageDataLinear = this.bufferCanvasLinear.context.createImageData(1024, 1); this.bufferCanvasLinear.texture.generateMipMaps = false; this.bufferCanvasLinear.texture.minFilter = THREE.NearestFilter; this.bufferCanvasLinear.texture.magFilter = THREE.NearestFilter; // Setup buffers for audio data this.fftSize = 2048; this.square = Math.sqrt(this.fftSize * 0.5); this.analizerData = new Uint8Array(this.fftSize * 0.5); this.analizerDataSin = new Uint8Array(this.fftSize * 0.5); // Fill the sin array with 128, because its the central point for (let i = 0; i < this.fftSize * 0.5; i++) { this.analizerDataSin[i] = 128; } // Setup a basic scene with camera this.setupBasicScene(); // Time values this.timeStart = Date.now(); this.timeCurrent = this.timeStart; this.timeElapsed = 0; this.timeDelta = 16; // Time from this second this.timeActualFrame = this.timeStart + 1000; // Number of frames during this second this.timeFrameCounter = 0; // actual framerate this.fps = 0; // Drag & drop events this.hEventDragEnter = this.eventDragEnter.bind(this); this.hEventDragOver = this.eventDragOver.bind(this); this.hEventDrop = this.eventDrop.bind(this); this.elementCanvas.addEventListener("dragenter", this.hEventDragEnter); this.elementCanvas.addEventListener("dragover" , this.hEventDragOver); this.elementCanvas.addEventListener("drop" , this.hEventDrop); // song loaded this.songLoaded = false; // default song true (not a drag & drop song) this.defaultSong = true; // Setup a Three.js renderer this.setupRenderer(); // Create the update loop window.requestAnimationFrame(() => { this.basicUpdate(); }); } /* * Create basic html elements (canvas, loading, framerate, fullscreen, github, and my web page button) */ createHtml() { // Create an empty div element outside of the doom, to make it our root element const preElementExperience = document.createElement("div"); // Id of this canvas (i need it for compatibility with my web page) this.id = 0; preElementExperience.id = "Experience" + this.id; preElementExperience.className = "Experience"; // Add the Experience element to the options root element this.options.rootElement.appendChild(preElementExperience); this.elementExperience = document.getElementById(preElementExperience.id); // Setup the loading atribute this.elementExperience.setAttribute("loading", true); // String that has all the tags to be added let strHTML = "" // Add the canvas element strHTML += '<canvas id="Experience' + this.id + '_Canvas" class="Experience_Canvas"></canvas>'; // Add the loading element strHTML += '<div class="Experience_Loading Experience_Panel"><span>Loading...</span></div>'; // Add the main controls element strHTML += '<div class="Experience_Controls">'; // Show FPS if (this.options.showFPS === true) { strHTML += "<div class='Experience_Panel Experience_Static' title='Frames Per Second'>" + "<div class='Experience_FPS'>60</div>" + "<div class='Experience_TxtFPS'>fps</div>" + "</div>"; } // Show full screen button if (this.options.buttonFullScreen === true) { strHTML += "<div id='fullScreen' class='Experience_Panel Experience_Control' title='Full screen mode'>" + "<img src='//repo.bfw.wiki/bfwrepo/svg/icos_button.svg#svg-pantalla-completa' />" + "</div>" + "<div id='restoreScreen' class='Experience_Panel Experience_Control' title='Restore screen'>" + "<img src='//repo.bfw.wiki/bfwrepo/svg/icos_button.svg#svg-restaurar-pantalla' />" + "</div>"; } // Closing .Experience_Controls strHTML += '</div>'; // Play button strHTML += '<div class="Experience_Play Experience_Panel Experience_Control" play="true">' + "<img src='//repo.bfw.wiki/bfwrepo/svg/icos_button.svg#svg-play' />" + '</div>'; // Pause button strHTML += '<div class="Experience_Pause Experience_Panel Experience_Control" play="true">' + "<img src='//repo.bfw.wiki/bfwrepo/svg/icos_button.svg#svg-pause' />" + '</div>'; // Song info strHTML .........完整代码请登录后点击上方下载按钮下载查看
网友评论0