Three.js + HTML5 Audio API 打造3D音乐频谱,Let’s ROCK!
继续玩味之前写的音乐频谱作品,将原来在Canvas标签上的 作图利用Three.js让它通过WebGL呈现,这样就打造出了一个全立体感的频谱效果了。
项目详情及源码
项目GitHub地址:https://github.com/Wayou/3D_Audio_Spectrum_VIsualizer/tree/master
在线演示地址:http://wayou.github.io/3D_Audio_Spectrum_VIsualizer
如果你想的话,可以从这里下载示例音乐:http://pan.baidu.com/s/1eQqqSfS
Note:
- 可以直接点击'play default' 播放自带的音乐,神探夏洛克插曲,如果你也看了的话,听着应该会有感的
- 支持文件拖拽进行播放,将音频文件拖拽到页面即可
- 也可以通过文件上传按钮选择一个音频文件进行播放
- 鼠标拖拽可以移动镜头变换视野
- 鼠标滚轮可以进行缩放
- 右上角的控制面板可以进行一些外观及镜头上的设置,可以自己探索玩玩
利用Three.js呈现
关于音频处理方面的逻辑基本和之前介绍HTML5 Audio API那篇博客里讲的差不多,差别只在这个项目里面将频谱的展示从2d的canvas换成3d的WebGL进行展示,使用的是Three.js。所以只简单介绍关于3d场景方面的构建,具体实现可以访问项目GitHub页面下载源码。
构建跃动的柱条
每根绿色柱条是一个CubeGeometry,柱条上面的盖子也是CubeGeometry,只是长度更短而以,同时使用的是白色。
//创建绿色柱条的形状
var cubeGeometry = new THREE.CubeGeometry(MWIDTH, , MTHICKNESS);
//创建绿色柱条的材质
var cubeMaterial = new THREE.MeshPhongMaterial({
color: 0x01FF00,
ambient: 0x01FF00,
specular: 0x01FF00,
shininess: ,
reflectivity: 5.5
});
//创建白色盖子的形状
var capGeometry = new THREE.CubeGeometry(MWIDTH, 0.5, MTHICKNESS);
//创建白色盖子的材质
var capMaterial = new THREE.MeshPhongMaterial({
color: 0xffffff,
ambient: 0x01FF00,
specular: 0x01FF00,
shininess: ,
reflectivity: 5.5
});
上面只是创建了形状及材质,需要将这两者组合在一起形成一个模型,才是我们看到的实际物体。下面通过一个循环创建了一字排开的柱条和对应的盖子,然后添加到场景中。
//创建一字排开的柱条和盖子,并添加到场景中
for (var i = METERNUM - ; i >= ; i--) {
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = - + (MWIDTH + GAP) * i;
cube.position.y = -;
cube.position.z = 0.5;
cube.castShadow = true;
cube.name = 'cube' + i;
scene.add(cube);
var cap = new THREE.Mesh(capGeometry, capMaterial);
cap.position.x = - + (MWIDTH + GAP) * i;
cap.position.y = 0.5;
cap.position.z = 0.5;
cap.castShadow = true;
cap.name = 'cap' + i;
scene.add(cap);
};
注意到我们为每个物体指定了名称以方便之后获取该物体。
添加动画
动画部分同时是使用requestAnimation,根据传入的音频分析器(analyser)的数据来更新每根柱条的长度。
var renderAnimation = function() {
if (analyser) {
//从音频分析器中获取数据
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var step = Math.round(array.length / METERNUM);
//更新每根柱条的高度
for (var i = ; i < METERNUM; i++) {
var value = array[i * step] / ;
value = value < ? : value;
var meter = scene.getObjectByName('cube' + i, true);
meter.scale.y = value;
}
};
//重新渲染画面
render.render(scene, camera);
requestAnimationFrame(renderAnimation);
};
requestAnimationFrame(renderAnimation);
对于白色盖子的处理稍微不同,因为它是缓慢下落的,不能使用及时送达的音频数据来更新它。实现的方式是每次动画更新中检查当前柱条的高度与前一时刻盖子的高度,看谁大,如果柱条更高,则盖子使用新的高度,否则盖子高度减1,这样就实现了缓落的效果。
var renderAnimation = function() {
if (analyser) {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var step = Math.round(array.length / METERNUM);
for (var i = ; i < METERNUM; i++) {
var value = array[i * step] / ;
value = value < ? : value;
var meter = scene.getObjectByName('cube' + i, true),
cap = scene.getObjectByName('cap' + i, true);
meter.scale.y = value;
//计算柱条边沿尺寸以获得高度
meter.geometry.computeBoundingBox();
height = (meter.geometry.boundingBox.max.y - meter.geometry.boundingBox.min.y) * value;
//将柱条高度与盖子高度进行比较
if (height / > cap.position.y) {
cap.position.y = height / ;
} else {
cap.position.y -= controls.dropSpeed;
};
}
};
//重新渲染画面
render.render(scene, camera);
requestAnimationFrame(renderAnimation);
};
requestAnimationFrame(renderAnimation);
镜头控制
镜头的控制使用的是与Three.js搭配的一个插件ObitControls.js,如果你下载了Three.js的源码可以在里面找到。只需获取一个鼠标拖动的前后时间差,然后在动画循环中调用插件进行画面更新即可。
var orbitControls = new THREE.OrbitControls(camera);
orbitControls.minDistance = ;
orbitControls.maxDistance = ;
orbitControls.maxPolarAngle = 1.5;
var renderAnimation = function() {
var delta = clock.getDelta();
orbitControls.update(delta);
if (analyser) {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var step = Math.round(array.length / METERNUM);
for (var i = ; i < METERNUM; i++) {
var value = array[i * step] / ;
value = value < ? : value;
var meter = scene.getObjectByName('cube' + i, true),
cap = scene.getObjectByName('cap' + i, true);
meter.scale.y = value;
//计算柱条边沿尺寸以获得高度
meter.geometry.computeBoundingBox();
height = (meter.geometry.boundingBox.max.y - meter.geometry.boundingBox.min.y) * value;
//将柱条高度与盖子高度进行比较
if (height / > cap.position.y) {
cap.position.y = height / ;
} else {
cap.position.y -= controls.dropSpeed;
};
}
};
//重新渲染画面
render.render(scene, camera);
requestAnimationFrame(renderAnimation);
};
requestAnimationFrame(renderAnimation);
注意到在实例化一个ObitControls后,进行了一些角度和镜头伸缩方面的设置,限制了用户把画面翻转到平面的底部,也保证了镜头在伸缩时不会太远及太近。
参数控制
右上角的控制面板可以进行画面的一些参数更改,使用的是谷歌员工创建的一个插件dat.gui.js 。
首先需要定义一个包含全部需要控制的参数的对象:
var controls = new function() {
this.capColor = 0xFFFFFF;
this.barColor = 0x01FF00;
this.ambientColor = 0x0c0c0c;
this.dropSpeed = 0.1;
this.autoRotate = false;
};
然后实例化一个控制器,将这个对象及相应参数进行绑定:
var gui = new dat.GUI();
//添加盖子下降速度的控制
gui.add(controls, 'dropSpeed', 0.1, 0.5);
//盖子颜色控制
gui.addColor(controls, 'capColor').onChange(function(e) {
scene.children.forEach(function(child) {
if (child.name.indexOf('cap') > -) {
child.material.color.setStyle(e);
child.material.ambient = new THREE.Color(e)
child.material.emissive = new THREE.Color(e)
child.material.needsUpdate = true;
}
});
});
//柱条颜色控制
gui.addColor(controls, 'barColor').onChange(function(e) {
scene.children.forEach(function(child) {
if (child.name.indexOf('cube') > -) {
child.material.color.setStyle(e);
child.material.ambient = new THREE.Color(e)
child.material.emissive = new THREE.Color(e)
child.material.needsUpdate = true;
}
});
});
//镜头自动移动控制
gui.add(controls, 'autoRotate').onChange(function(e) {
orbitControls.autoRotate = e;
});
总结
完成了主要功能,但没达到我预期的效果,我想的是把柱条做成发光的,调研了一下,需要用更复杂的材质,同时也不能用WebGL来渲染画面了,性能是一方面,同时也还没研究得那么深入,所以就先出了这个版本先。以后或许弄个水波效果。
REFERENCE
Offical Documentation: http://threejs.org/docs/
A Demo: http://srchea.com/blog/2013/05/experimenting-with-web-audio-api-three-js-webgl/
Another Example: https://github.com/arirusso/three-audio-spectrum
A Working Demo: http://badassjs.com/post/27056714305/plucked-html5-audio-editor-and-threeaudio-js
Dat GUI plugin: https://code.google.com/p/dat-gui/
Three.js + HTML5 Audio API 打造3D音乐频谱,Let’s ROCK!的更多相关文章
- 【HTML5】Web Audio API打造超炫的音乐可视化效果
HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我! 源码已经挂到github上了,有兴趣的同学也可以去st ...
- 开大你的音响,感受HTML5 Audio API带来的视听盛宴
话说HTML5的炫酷真的是让我爱不释手,即使在这个提到IE就伤心不完的年代.但话又说回来,追求卓越Web创造更美世界这样高的追求什么时候又与IE沾过边儿呢?所以当你在看本文并且我们开始讨论HTML5等 ...
- html5 audio标签切换播放音乐的方法
html5 audio标签切换播放音乐的方法<pre><audio id="music1" preload loop="loop">&l ...
- HTML5 Audio时代的MIDI音乐文件播放
大家都知道,HTML5 Audio标签能够支持wav, webm, mp3, ogg, acc等格式,但是有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持,因为mid文 ...
- HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- 使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- HTML5 ——web audio API 音乐可视化(二)
上一篇 web audio API 音乐可视化(一)介绍了一些基本的API,以及如何简单的播放一个音频,本篇介绍一下怎么对获取到的音频进行分析,并将分析后的数据绘制成图像. 最终效果请戳这里; 完整版 ...
- HTML5 ——web audio API 音乐可视化(一)
使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...
- HTML5 Audio标签方法和函数API介绍
问说网 > 文章教程 > 网页制作 > HTML5 Audio标签方法和函数API介绍 Audio APIHTML5HTML5 Audio预加载 HTML5 Audio标签方法和函数 ...
随机推荐
- MVC5项目中添加Wep API
一.查看MVC版本,决定你有没有必要看这篇文章 打开web.config,看到以下内容 <dependentAssembly> <assemblyIdentity name=&quo ...
- BZOJ4742 : [Usaco2016 Dec]Team Building
如果我们将两个人拥有的牛混在一起,并按照战斗力从小到大排序,同时把第一个人选的牛看成$)$,第二个人选的牛看成$($的话,那么我们会发现一个合法的方案对应了一个长度为$2k$的括号序列. 于是DP即可 ...
- 【贪心】HDU 1257
HDU 1257 最少拦截系统 题意:中文题不解释. 思路:网上有说贪心有说DP,想法就是开一个数组存每个拦截系统当前最高能拦截的导弹高度.输入每个导弹高度的时候就开始处理,遍历每一个拦截系统,一旦最 ...
- NoSql basic knowledge
The big picture to keep in mind first is: There are lots of articles and resources out there: http:/ ...
- HDU 5976 数学,逆元
1.HDU 5976 Detachment 2.题意:给一个正整数x,把x拆分成多个正整数的和,这些数不能有重复,要使这些数的积尽可能的大,输出积. 3.总结:首先我们要把数拆得尽可能小,这样积才会更 ...
- winform控件在Enable=false的情况下改变它的字体颜色
[System.Runtime.InteropServices.DllImport("user32.dll ")] public static extern int ...
- elasticsearch常用的概念整理
节点node 节点(node)是一个运行着的Elasticsearch实例 集群中一个节点会被选举为主节点(master),它将临时管理集群级别的一些变更,例如新建或删除索引.增加或移除节点等.主节点 ...
- pythonchallenge 解谜 Level 5
第五关的确很坑爹... 不过,根据之前的思路,我想着是把信息放在了 “源码” 中. 翻了下源码.有用的东西在以下部分. <html><head> <title>pe ...
- SQL执行效率2-执行计划
以下语句可以进行SQL 语句执行时间分析,两个Go之间就是SQL查询语句 use Work--数据库名 go set statistics profile on set statistics io o ...
- sqlmap用户手册 | WooYun知识库
sqlmap用户手册 说明:本文为转载,对原文中一些明显的拼写错误进行修正,并标注对自己有用的信息. 原文:http://drops.wooyun.org/tips/143 ============ ...