以下文章即Learn Threejs 第三版英文翻译学习记录,可以到正版书店购买对应书籍。
如果你想在场景种功能使用动画,那第一件要做的事情就是先找到绘制场景的时间间隔(就是已特定的周期渲染场景)。在HTML5 和JavaScript Api 出来之前,使用setInterval方法去处理这件事情,这个方法定义了,我们可以100 毫秒去执行一个方法(就是周期函数,约定某个周期调用某个函数一次),但是这个方法没有考虑到浏览器的一些问题,如果你浏览其他的页面,这个函数依然会按照时间周期执行。而且,setInterval方法不是异步刷新屏幕,它需要更高的CPU使用率、频率、获得较差的性能。
介绍 RequestAnimationFrame
幸运的是,我们可以通过requestAnimationFrame这个函数来解决问题,通过这个函数,你可以按照时间间隔调用,而且不用定义这个时间。这个时间间隔有浏览器定义。你可以在将你的函数传入到这个方法中去处理你的绘制任务,浏览器会尽可能平滑、高效的处理这个绘制任务。
function renderScene() {
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
(就是一个while循环 / 也类似递归调用)
在这个renderScene 函数中,我们调用了requestAnimationFrame函数,来保证动画的正常运行。你仅需要在创建场景完成后调用一次rendererScene函数来启动函数。
...
document.getElementById("webgl-output").appendChild(renderer.domElement);
renderScene();
如果你运行这个示例,你会发现,和我们之前提供的示例,没有任何区别,因为我们还没有开始设置任何动画。在我们添加动画之前,我们需要添加一个小的插件,它会为我们提供有关动画帧率的相关信息。这个库是Threejs同一个作者开发的,渲染一个小的界面,为我们提供相关信息。
添加这个静态库,我们需要在head里引入,例如:
<script type="text/javascript" src="../../libs/util/Stats.js"></script>
(我在demo中只发现了一个stats.min.js)
唯一需要做的事情就是将这个库初始化,并添加到页面中;
function initStats(type) {
var stats = new Stats();
stats.showPanel(type);// 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);
return stats;
}
(这个我试过,有一个小窗口,能显示fps ms mb,3+什么都没有,setMode和showPanel都可以)
通过函数初始化统计试图信息,并根据传入类型变量显示对应的视图,可以显示每秒渲染帧数(FPS)、渲染需要的时间(MS)、内存分配相关信息(MB), 在我们的初始化函数之前调用initStats函数,例如:
function init(){
var stats = initStats(); ...
}
Tip:说的意思是他将这些工具类的函数放到了util.js中,说你要用的话,就直接引入util.js
<script type="text/javascript" src="../js/util.js"></script>
我们现在唯一要做的事情就是在循环执行的方法中调用stats的update方法,在renderScene 函数中,例如:
function renderScene() {
stats.update();
......
equestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
如果你运行了添加的代码,你将会看到在左上角有一个统计图,如截图所示(略,自己试吧);
开始 立方体 动画
我们写好了requestAnimationFrame和状态提示插件,我们现在找到一个地方写我们的动画代码。在这部分,我们将扩展renderScene方法,通过旋转各个坐标轴来执行立方体旋转动画,我们开始,下边是代码:
function renderScene() { ...
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
... requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
看起来很简单,是吧?我们要做的是,在每次renderScene函数调用刷新的时候,将每个坐标轴属性增加0.02,它显示是一个围绕所有轴平滑旋转的立方体。将蓝色的球执行弹性动画也不难。
(https://www.cnblogs.com/jaycethanks/p/12032947.html 这篇文章详细介绍了,球的切面什么的,会解决你做出来的球不圆的问题)
开始 球 动画
弹球动画,我们再次向rebderScene函数中添加了几行代码,例如:
var step=0;
function renderScene() {
...
step+=0.04;
sphere.position.x = 20 + 10*(Math.cos(step));
sphere.position.y = 2 + 10*Math.abs(Math.sin(step)); ...
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
在场景中,立方体,我们不断设置了它的rotation属性,球体我们设置了position属性。我们希望球体从一个点完美的运动到场景的另一个点,而且是一个平滑的曲线,下面是我的算法介绍:(图略)
运动轨迹图可以看到,我们需要修改x轴和y轴的值,数学函数Math.cos,Math.sin 函数可以帮助我们创建一个生成平滑的轨迹可供使用的一个值(就是通过函数的计算能够得到平滑曲线上的点的值),在这里我们不需要知道详细的工作流程。现在,你只需知道 step+=0.4 定义了球体运动的速度,在第8节中,Creating and Loading Advanced Meshes and Geometries (应该是一节内容,就是高级使用技巧),我们可以通过章节了解如何使用这些动画函数,而且会解释这些。下班就是球在空中弹跳的样子:(略 自己做就好了 没什么);
在结束本章之前,我们需要在场景中再添加一些物体,在使用3D场景、动画、颜色和属性的时候,它通常需要一些实验来验证颜色或者是速度这些。如果你能有一个简单的GUI,允许你动态地改变这些属性,那做实验就更容易了。
使用GUI 体验更加
谷歌的几位员工开发了一个dat.GUI库(你可以通过http://code.google.com/p/dat-gui/查看文档),你可以在代码中很容易的使用用户界面组件,在本章的队后一部分,在示例中添加一个用户界面,允许我们执行以下操作:控制弹跳球的速度、控制立方体旋转。
就像我们做统计一样,第一步将开源库添加html的<head>标签中,如:
<script type="text/javascript" src="../../libs/util/dat.gui.js"></script>
接下来需要配置JavaScript对象,使用dat.GUI来保存属性。在JavaScript主方法中,我们添加以下JavaScript对象,例如:
var controls = new function() {
this.rotationSpeed = 0.02;
this.bouncingSpeed = 0.03;
}
在这个JavaScript对象中,我们定义了两个属性:this.rotationSpeed 和 this.bouncingSpeed,而且给他们赋值,下一步,我们将这个对象传递到dat.GUI 对象中,并定义这两个属性的范围,如下所示:
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
gui.add(controls, 'bouncingSpeed', 0, 0.5);
rotationSpeed 和 bouncingSpeed 属性都是设置了0-0.5区间,现在我们只需要将操作放入到renderScene 渲染循环中。(后边说的比较复杂,意思就是将你之前加入GUI的两个属性,立刻就会生效了)
function renderScene() {
...
cube.rotation.x += controls.rotationSpeed;
cube.rotation.y += controls.rotationSpeed;
cube.rotation.z += controls.rotationSpeed;
step += controls.bouncingSpeed;
sphere.position.x = 20 +(10 * (Math.cos(step)));
sphere.position.y = 2 +(10 * Math.abs(Math.sin(step)));
...
}
现在,我们运行示例 05-control-gui.html,你可以看到一个简单的用户界面,用来控制弹性系数和旋转速度
GUI 控制(其实咋说呢就是提供了一个GUI用户操作界面,操作控制项,还是比较好用的,新版的需要导入dat.gui.min.js)
我们之前几章写的HTML代码,我们导入TrackballControls.js JavaScriypt文件。在这个文件中,我们可以控制camera 影响渲染结果,我们会在第9章详细介绍Camera的动画和移动。我们只需要添加几行JavaScript代码就可以添加这个组件,初始化球运动的轨迹...(接下来说的意思就是一定要记住将randerer添加到document中)。
document.getElementById("webgl-output").appendChild(renderer.domElement); // add the two lines below
var trackballControls = initTrackballControls(camera, renderer);
var clock = new THREE.Clock();
initTrackballControls 方法在utils.js中已经被定义了,这个我们之前提到过。在接下来的章节种功能,我们会介绍更多细节来说明它是怎么工作的,现在我们只需要更新render方法,例如:
function render() {
trackballControls.update(clock.getDelta());
...
}
现在已经做完了,如果你再次打开05-control-gui.html 示例,你可以移动你的鼠标,或者左击鼠标来移动视角camera,如果你在移动的时候点击 ‘s’键,你可以放大和缩小;如果按下‘d’,你可以拖拽那个场景。(我没找见这个文件)
以后的demo将默认使用这些动画控制组件,一边您能够更容易的查看渲染结果。
如果你在你的浏览器上查看,你可能注意到当你缩放浏览器的大小时,渲染界面不会跟着缩放,在下一个章节中,我们将会添加这个(就是想说下几节中,解决上述问题)。
当浏览器尺寸改变时,渲染结果跟着改变
当浏览器尺寸发生改变的时候,更改camera的操作是很简单的。第一件事情就是注册添加时间监听,如下:
window.addEventListener('resize', onResize, false);
现在,当浏览器i尺寸发生变化时,就会调用onResize方法,下一步我们需要做的是,当onResize方法调用时,我们需要更新camera和渲染,例如:
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
对于camera来说,我们需要改变aspect属性,让他始终保持浏览器横纵比;对于renderer,我们需要改变它的渲染尺寸;(接下来说的意思就是:把这些代码封装到一个init方法中,以便我们更好的使用它);
var camera;
var scene;
var renderer;
function init() { ...
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth /
window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer(); ...
}
总结
第一章到此结束,在这一节中,我们为您展示了如何设置你的开发环境、如何获取程序代码、如何从提供的示例中开始。您进一步了解到Three.js是如何渲染的,第一步创建THREE.Scene 对象,添加camera、光线light、你想渲染的模型。我们也向您介绍了如何在基础的场景里显示阴影(我就没加出来,估计日后能加出来吧)、显示动画等,最后,我们添加了一些小组件。我们使用dat.GUI 它可以很快速的为我们创建用户界面来控制渲染属性,添加了stats.js(用来观察渲染情况,如内存、刷新频率等)
在下一章节中,进一步了解Three.js的其他功能。
网友评论