侧边栏壁纸
  • 累计撰写 225 篇文章
  • 累计创建 275 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

给新手的three.js入门讲解(二)

DGF
DGF
2022-09-13 / 0 评论 / 0 点赞 / 33 阅读 / 0 字

动作渲染

原理

对于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 delta=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

Animationaction = 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坐标。

当计算这条射线是否和物体相交的时候,Ray
caster将传入的对象委托给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是任意某平面的法线的单位向量,不考虑平移,其变换矩阵:

post194-1.png

0
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新手入门教程,推荐收藏。

0

评论区