继续玩味之前写的音乐频谱作品,将原来在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!的更多相关文章

  1. 【HTML5】Web Audio API打造超炫的音乐可视化效果

    HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我!  源码已经挂到github上了,有兴趣的同学也可以去st ...

  2. 开大你的音响,感受HTML5 Audio API带来的视听盛宴

    话说HTML5的炫酷真的是让我爱不释手,即使在这个提到IE就伤心不完的年代.但话又说回来,追求卓越Web创造更美世界这样高的追求什么时候又与IE沾过边儿呢?所以当你在看本文并且我们开始讨论HTML5等 ...

  3. html5 audio标签切换播放音乐的方法

    html5 audio标签切换播放音乐的方法<pre><audio id="music1" preload loop="loop">&l ...

  4. HTML5 Audio时代的MIDI音乐文件播放

    大家都知道,HTML5 Audio标签能够支持wav, webm, mp3, ogg, acc等格式,但是有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持,因为mid文 ...

  5. HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器

    HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...

  6. 使用Audio API设计绚丽的HTML5音乐播放器

    HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...

  7. HTML5 ——web audio API 音乐可视化(二)

    上一篇 web audio API 音乐可视化(一)介绍了一些基本的API,以及如何简单的播放一个音频,本篇介绍一下怎么对获取到的音频进行分析,并将分析后的数据绘制成图像. 最终效果请戳这里; 完整版 ...

  8. HTML5 ——web audio API 音乐可视化(一)

    使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...

  9. HTML5 Audio标签方法和函数API介绍

    问说网 > 文章教程 > 网页制作 > HTML5 Audio标签方法和函数API介绍 Audio APIHTML5HTML5 Audio预加载 HTML5 Audio标签方法和函数 ...

随机推荐

  1. 通过配置web.config使WCF向外提供HTTPS的Restful Service

    如何通过WCF向外提供Restful的Service请看如下链接 http://www.cnblogs.com/mingmingruyuedlut/p/4223116.html 那么如何通过对web. ...

  2. HTML基础知识

    一个完美的web前端攻城狮,所具备的专业素养有:HTML5.XHTML.CSS3.JavaScript.JQuery.PS.PHP等.所以说,我要学的东西还有很多... 没别得,我也是一个H5的初学者 ...

  3. locky勒索样本分析

    前段时间收到locky样本,分析之后遂做一个分析. 样本如下所示,一般locky勒索的先决条件是一个js的脚本,脚本经过了复杂的混淆,主要用于下载该样本文件并运行,. 解密 样本本身进行了保护,通过i ...

  4. .NET平台常用的框架整理

    基于.NET平台常用的框架整理 DotNet | 2016-03-31 17:13 (点击上方蓝字,可快速关注我们) 来源:天使不哭 链接:http://www.cnblogs.com/hgmyz/p ...

  5. C练习

    int main() { int a; //scanf函数只接受变量的地址 //scanf函数是一个阻塞式的函数,等待用户输入 // 用户输入完成后,就会将用户输入的值赋值给变量a //函数调用完毕 ...

  6. jQuery Validate验证框架详解

    转自:http://www.cnblogs.com/linjiqin/p/3431835.html jQuery校验官网地址:http://bassistance.de/jquery-plugins/ ...

  7. Codeforces Round #366 (Div. 2)

    CF 复仇者联盟场... 水题 A - Hulk(绿巨人) 输出love hate... #include <bits/stdc++.h> typedef long long ll; co ...

  8. 获取终端ip地址

    网上找的,记录下 import java.io.*; import java.net.*; import java.util.*; //import org.apache.http.conn.util ...

  9. Problem of saving images in WPF (RenderTargetBitmap)zz

      To save a visual to an image file need to use RenderTargetBitmap, detail is reference to Save and ...

  10. JAVA实现AES 解密报错Input length must be multiple of 16 when decrypting with padded cipher

    加密代码 /**解密 * @param content 待解密内容 * @param password 解密密钥 * @return */ public static byte[] decrypt(b ...