动作渲染
原理
对于Three.js 程序而言,动作渲染的实现是通过在秒中多次重绘画面实现的。FPS(Frames Per Second)指每秒画面重绘的次数。FPS 越大,则渲染效果越平滑,当 FPS 小于 20 时,一般就能明显感受到画面的卡滞现象。当 FPS 足够大(比如达到 60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源。
setInterval 方法
如果要设置特定的 FPS,可以使用该方法:
setInterval(func, msec)其中, func 是每过 msec 毫秒执行的函数,如果将 func 定义为重绘画面的函数,就能实现动画效果。
var id = setInterval(draw, 20); function draw() { mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2); renderer.render(scene, camera); }
这样,每 20 毫秒就会调用一次 draw 函数,改变长方体的旋转值,然后进行重绘。最终得到的效果就是 FPS 为 50 的旋转长方体。
requestAnimationFrame 方法
不在意多久重绘一次,就适合用 requestAnimationFrame 方法。它告诉浏览器在合适的时候调用指定函数,通常可能达到 60FPS。requestAnimationFrame 同样有对应的 cancelAnimationFrame 取消动画,使用方法类似clearInterval。
由于 requestAnimationFrame 只请求一帧画面,与settimeout很相似。因此,除了在init 函数中需要调用,在被其调用的函数中需要再次调用 requestAnimationFrame :
function draw() { mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2); renderer.render(scene, camera); var id = requestAnimationFrame(draw); }
可以使用renderer.setAnimationLoop(callback)来代替requestAnimationFrame()。.callback 为每个可用帧都会调用的函数。 如果传入‘null’,所有正在进行的动画都会停止。对于WebVR项目,必须使用此函数。
相机控件
threejs 包括多个相机控件,每个控制都必须加载对应的控制器插件后才能使用。
控制器要生效必须在renderer中使用代码更新
var clock=new THREE.Clock(); function render(){ var delte=clock.getDelta(); trackballControls.update(delta); requestAnimationFrame(render); webGLRenderder.render(scene,camera); }
其中, THREE.Clock()对象可以获取一次渲染耗费的时间,调用clock.getDelta()会返回此次调用和上次调用之间的时间。
OrbitControls
可以使得相机围绕目标进行轨道运动。以舞台中心为中点,左右拖动屏幕会让镜头围绕着中心点旋转,镜头会看着中心点。
OrbitControls( object : Camera, domElement : HTMLDOMElement )
object: (必须)将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身。
domElement: (可选)用于事件监听的HTML元素,其默认值为整个文档, 但是如果你只希望在特定的元素上(例如Canvas上)进行控制,在这里进行指定即可。
TrackballControls
以模型或者点为中心, 围绕中心来展示。拖动模型后, 模型位置会变化, 但是摄像机 LookAt 的位置不会变化, 导致再次旋转模型将不再以模型为中心点。
注意:使用相机控件,会导致相机lookAt()失效,需要设置OrbitControls.target为目标向量,比如
controls.target = new THREE.Vector3(0,-1000,0);
这样就可以看到视角更新为想要的视角啦。
渲染
WebGLRender
使用WebGLRender对象能调动计算机显卡,计算指定相机角度下的scene样子进行渲染。
var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(0xEEEEEE); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio);
调用setClearColor(0xEEEEEE)将渲染器的背景色设置为白色,调用setSize()来控制渲染器渲染scene的范围。
//将渲染的结果输出到指定页面元素中 document.getElementById("WebGL-output").appendChild(renderer.domElement); //渲染场景 renderer.render(scene, camera);
渲染机制
threejs的渲染器是基于webGL的。它的渲染机制是根据物体离照相机的距离来控制和进行渲染的。也就是说,它根据物体的空间位置进行排序,然后根据这个顺序来渲染物体。对于透明的物体,是按照从最远到最近的顺序进行渲染。
控制渲染顺序
1.设置
renderer.sortObjects = false;
这样,物体的渲染顺序将会由他们添加到场景中的顺序所决定。
2.设置
renderer.sortObjects = true;
并且给特定的物体设置object.renderOrder 指定它的渲染顺序。默认renderOrder = 0;
3.遍历设置
material1.depthWrite = false; material2.depthWrite = false;
辅助
坐标轴AxesHelper
用于简单模拟3个坐标轴的对象.
红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
var axesHelper = new THREE.AxesHelper( length ); scene.add( axesHelper );
length(可选的) 表示代表轴的线段长度. 默认为 1。
性能检测stats
检测当前场景的渲染帧率和显存占用情况;
使用时,需要添加入渲染函数内:
function Animate(){ requestAnimationFrame(Animate); Render(); } function Render(){ stats.update(); render.render(scene,camera); }
动画
动画混合器AnimationMixer
动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。
AnimationMixer( Object3D )
Object3D为混合器播放的动画所属的对象。
属性
.time : Number全局的混合器时间(单位秒; 混合器创建的时刻记作0时刻)
.timeScale : Number全局时间(mixer time)的比例因子
说明: 将混合器的时间比例设为0/1,可以暂停/取消暂停由该混合器控制的所有动作。
方法
clipAction (clip : AnimationClip, optionalRoot : Object3D) : AnimationAction//返回传入 AnimationActionAnimationaction = mixer.clipAction(clip);
clip是动画剪辑(AnimationClip)对象或者动画剪辑的名称(导入的模型的动作信息保存在object.animations[ ]数组内)。根对象Object3D可选,默认值为混合器的默认根对象。
如果不存在符合传入的剪辑和根对象这两个参数的动作, 该方法将会创建一个。
AnimationActions 用来调度存储在AnimationClips中的动画。动画剪辑AnimationClip是一个可重用的关键帧轨道集,它代表动画。
AnimationAction的大多数方法都可以链式调用。
点击交互
原理
浏览器是一个2D视口,在里面显示threejs的内容是3D场景,从浏览器观测3D场景时,眼睛就相当于是threejs内的摄像机点,鼠标在屏幕的点击位置是另一个点。这两个点会在threejs内连接成一条直线raycaster,直线穿过的threejs内的物体就是鼠标所点击的物体。
实现
Raycaster( origin : Vector3, direction : Vector3, near : Float, far : Float )
origin —— 光线投射的原点向量。
direction —— 向射线提供方向的方向向量,应当被标准化。
near —— 返回的所有结果比near远。near不能为负值,其默认值为0。
far —— 返回的所有结果都比far近。far不能小于near,其默认值为Infinity(正无穷)。
方法
.setFromCamera ( coords : Vector2, camera : Camera ) : null
coords —— 在标准化设备坐标中鼠标的二维坐标 。
camera —— 射线所来源的摄像机。
使用一个新的原点和方向来更新射线。
.intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
objects —— 检测和射线相交的一组物体。
recursive —— 若为true,则同时也会检测所有物体的后代。否则将只会检测对象本身的相交部分。默认值为false。
optionalTarget —— (可选)(可选)设置结果的目标数组。如果不设置这个值,则一个新的Array会被实例化;如果设置了这个值,则在每次调用之前必须清空这个数组(例如:array.length = 0;)。
检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),相交部分返回一个包含有交叉部分的数组:
[ { distance, point, face, faceIndex, object }, ... ]
distance —— 射线投射原点和相交部分之间的距离。
point —— 相交部分的点(世界坐标)
face —— 相交的面
faceIndex —— 相交的面的索引
object —— 相交的物体
uv —— 相交部分的点的UV坐标。
当计算这条射线是否和物体相交的时候,Raycaster将传入的对象委托给raycast方法。 这将可以让mesh对于光线投射的响应不同于lines和pointclouds。
注意:对于网格来说,面必须朝向射线的原点,以便其能够被检测到。 用于交互的射线穿过面的背侧时,将不会被检测到。如果需要对物体中面的两侧进行光线投射, 需要将material中的side属性设置为THREE.DoubleSide。
var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); function onMouseMove( event ) { // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1) mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; } function render() { // 通过摄像机和鼠标位置更新射线 raycaster.setFromCamera( mouse, camera ); // 计算物体和射线的焦点 var intersects = raycaster.intersectObjects( scene.children ); for ( var i = 0; i < intersects.length; i++ ) { intersects[ i ].object.material.color.set( 0xff0000 ); } renderer.render( scene, camera ); } window.addEventListener( 'mousemove', onMouseMove, false ); window.requestAnimationFrame(render);
基础库
颜色
构造器(Constructor)
Color( r , g , b )
.r : Float
红色通道的值在0到1之间。默认值为1。
.g : Float
绿色通道的值在0到1之间。默认值为1。
.b : Float
蓝色通道的值在0到1之间。默认值为1。
var color = new THREE.Color( 1, 0, 0 );
使用十六进制定义一个颜色在three.js中是标准的方法
var color = new THREE.Color( 0xff0000 );
欧拉角
欧拉角描述一个旋转变换,通过指定轴顺序和指定各轴旋转角度来旋转一个物体。
构造器(Constructor)
Euler( x : Float, y : Float, z : Float, order : String )
x - (optional) 用弧度表示x轴旋转量。 默认值是 0。
y - (optional) 用弧度表示y轴旋转量。 默认值是 0。
z - (optional) 用弧度表示z轴旋转量。 默认值是 0。
order - (optional) 表示旋转顺序的字符串,默认为'XYZ'(必须是大写)。
var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); var b = new THREE.Vector3( 1, 0, 1 ); b.applyEuler(a);
三维几何线段
构造器(Constructor)
Line3( start : Vector3, end : Vector3 )
start - 线段的起始点。默认值为 (0, 0, 0)。
end - 线段的终点。默认值为 (0, 0, 0)。
二维向量
表示2D vector(二维向量),是一对有顺序的数字(标记为x和y)。
Vector2( x : Float, y : Float )
x - 向量的x值,默认为0。
y - 向量的y值,默认为0。
三维向量
表示的是一个三维向量,是一个有顺序的、三个为一组的数字组合(标记为x、y和z)。
构造函数
Vector3( x : Float, y : Float, z : Float )
x - 向量的x值,默认为0。
y - 向量的y值,默认为0。
z - 向量的z值,默认为0。
四维矩阵
在3D计算机图形学中,4x4矩阵最常用的用法是作为一个变换矩阵。三维空间中的向量Vector3通过乘以矩阵来进行转换,如平移、旋转、剪切、缩放、反射、正交或透视投影等。
构造器(Constructor)
Matrix4()
平面
在三维空间中无限延伸的二维平面
构造器(Constructor)
Plane( normal : Vector3, constant : Float )
normal - (可选参数) 定义单位长度的平面法向量Vector3。默认值为 (1, 0, 0)。
constant - (可选参数) 从原点到平面的有符号距离。 默认值为 0.
射线
构造函数
Ray( origin : Vector3, direction : Vector3 )
origin - (可选)Ray(射线)的原点,默认值是一个位于(0, 0, 0)的Vector3。
direction - Vector3 Ray(射线)的方向。该向量必须经过标准化(使用Vector3.normalize),这样才能使方法正常运行。 默认值是一个位于(0, 0, 0)的Vector3。
镜像
在三维世界中,物体是经过某平面呈镜像的。同样的,设向量n是任意某平面的法线的单位向量,不考虑平移,其变换矩阵:
var m = new THREE.Matrix4(); var vec=new THREE.Vector3(0,0,1); m.set( 1-2*vec.x*vec.x, -2*vec.x*vec.y, -2*vec.x*vec.z, 0,-2*vec.x*vec.y, 1-2*vec.y*vec.y, -2*vec.y*vec.z, 0,-2*vec.x*vec.z, -2*vec.y*vec.z, 1-2*vec.z*vec.z, 0,0, 0, 0, 1 ); mesh.applyMatrix(m); mesh.translateZ(300);
代码安全
以上是three.js入门全部知识,至此已可使用three.js进行开发,h5游戏、微信小游戏、数字孪生、三维可视化,都可以使用three.js进行开发。
Js是公开透明的代码,当使用three.js开发产品后,如要进行发布或交付,应当对js代码进行混淆加密,防止自己辛苦开发的产品被复制、盗用、攻击。
JShaman是专业的js代码混淆加密工具,可以对js代码进行平展控制流、字符串阵列化加密、僵尸代码植入、AST重建等,加密后的代码安全、不可逆。
结束
本文是完整的three.js新手入门教程,推荐收藏。