网易首页 > 网易号 > 正文 申请入驻

three.js新手入门教程

0
分享至

three.js就是使用javascript 来写3D程序。
在浏览器端,WebGL 是一个底层的标准,在这些标准被定义之后,Chrome、Firefox之类的浏览器实现了这些标准。然后,就能通过 JavaScript 代码,在网页上实现三维图形的渲染了。ThreeJS则是封装了底层的图形接口,更容易来实现3D程序。

核心

WebGL 的渲染是需要 HTML5 Canvas 元素的,所以需要在 部分中定义Canvas 元素,或者使用 js 生成。
一个典型的 Three.js 程序至少要包括渲染器(Renderer)、场景(Scene)、照相机(Camera),以及你在场景中创建的物体。

渲染器

渲染器将和 Canvas 元素进行绑定,如果在 HTML 中手动定义了Canvas 元素,那么 Renderer 可以这样写:

var renderer = new THREE.WebGLRenderer({canvas: document.getElementById('#mainCanvas')});

如果想要 Three.js 生成 Canvas 元素,在 HTML 中就不需要定义 Canvas 元素,在JavaScript 代码中可以这样写:

var renderer = new THREE.WebGLRenderer();renderer.setSize(400, 300); // 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度document.getElementsByTagName('body')[0].appendChild(renderer.domElement);

场景

在 Three.js 中添加的物体都是添加到场景中的,因此它相当于一个大容器。在程序最开始的时候进行实例化,然后将物体添加到场景中即可。

var scene = new THREE.Scene();

也就是说,场景是光源,相机和所有物体的父容器,通过:

scene.children

可以访问到这些子物体。这些物体在创建的时候是没有名字的,可以通过name属性指定名字,这样就可以通过:

scene.getChildByMName(name)

来访问具体的子物体。
通过:

scene.traverse(function)

可以遍历该父场景中的所有子物体来执行回调函数。

相机

WebGL 和 Three.js 使用的坐标系是右手坐标系,即右手伸开,拇指为X,四指为Y,手心为Z。


相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。在Threejs中有多种相机,透视相机(THREE.PerspectiveCamera)用的最多。定义透视投影的照相机:

var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);camera.position.set(0, 0, 5);scene.add(camera);

注意,照相机也需要被添加到场景中

总结
Three.js中的场景是一个物体的容器,开发者将需要的物体放入场景中。
相机的作用就是指向场景,在场景中取一个合适的景,把它拍下来。
渲染器的作用就是将相机拍摄下来的图片,放到浏览器中去显示。
在定义了场景中的物体,设置好的照相机之后,渲染器就知道如何渲染出二维的结果了。这时候,只需要调用渲染器的渲染函数,就能使其渲染一次了。

renderer.render(scene, camera);

照相机

根据投影方式的不同,照相机又分为正交投影照相机与透视投影照相机。使用透视投影照相机获得的结果是类似人眼看到的有“近大远小”的效果;而使用正交投影照相机获得的结果就像平面画3D的效果,在三维空间内平行的线,投影到二维空间中也一定是平行的。

正交投影照相机

正交投影照相机的构造函数是:

THREE.OrthographicCamera(left, right, top, bottom, near, far)

这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,其为视景体(Frustum)。只有在视景体内部的物体才可能显示在屏幕上,而视景体外的物体会在显示之前被裁减掉。
为了保持照相机的横竖比例,需要保证 (right - left) 与 (top - bottom) 的比例与 Canvas宽度与高度的比例一致。

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 100);camera.position.set(0, 0, 5);scene.add(camera);

其中,第二句是设定照相机的位置。照相机默认都是沿 z 轴负方向观察的,可以通过 lookAt 函数指定它看着其他方向:

camera.lookAt(new THREE.Vector3(0, 0, 0));

这样就改变照相机观察方向由当前位置指向原点。注意, lookAt 函数接受的是一个 THREE.Vector3 的实例。

透视投影相机

透视投影是更符合人眼视觉的投影,构造函数是:

PerspectiveCamera( fov, aspect, near, far )


fov:为视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。
aspect:为实际窗口的纵横比,即宽度除以高度。通常设为Canvas 的横纵比例。

var camera = new THREE.PerspectiveCamera(45, 400 / 300, 1, 100);camera.position.set(0, 0, 5);scene.add(camera);

形状

threejs封装了一些常见的几何形状,在使用时,就只需要定义threejs设定好需要的值即可,如果想要自定义形状,就需要手动创造顶点和面。

立方体

THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)

这里, width 是 x 方向上的长度; height 是 y 方向上的长度; depth 是 z 方向上的长度;后三个参数分别是在三个方向上的分段数,如 widthSegments 为 3 的话,代表 x 方向上水平分为三份。一般情况下不需要分段的话,可以不设置后三个参数,后三个参数的默认值为 1 。
如: new THREE.CubeGeometry(1, 2, 3); 可以创建一个 x 方向长度为 1 ,y 方向长度为 2 ,z 方向长度为 3 的立方体。


物体的几何中心默认在原点的位置。若设置了分段,会对六个面进行分段,而不是对立方体分段,因此在立方体的中间是不分段的,只有六个侧面被分段。

平面

THREE.PlaneGeometry(width, height, widthSegments, heightSegments)

width 是 x 方向上的长度; height 是 y 方向上的长度;后两个参数同样表示分段。

球体

THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength)

其中, radius 是半径; segmentsWidth 表示经度上的切片数; segmentsHeight 表示纬度上的切片数; phiStart 表示经度开始的弧度; phiLength 表示经度跨过的弧度;thetaStart 表示纬度开始的弧度; thetaLength 表示纬度跨过的弧度。
使用 var sphere = new THREE.SphereGeometry(3, 8, 6) 可以创建一个半径为 3,经度划分成 8 份,纬度划分成 6份的球体,如下图所示:


segmentsWidth 相当于经度被切成了几瓣,而 segmentsHeight 相当于纬度被切成了几层。对于球
体而言,当这两个值较大的时候,形成的多面体就可以近似看做是球体了。

圆形

THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)

这四个参数和球体中的是类似的。

柱体

THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded)

其中, radiusTop 与 radiusBottom 分别是顶面和底面的半径,由此可知,当这两个参数设置为不同的值时,实际上创建的是一个圆台; height 是圆柱体的高度;radiusSegments 与 heightSegments 可类比球体中的分段; openEnded 是一个布尔值,表示是否没有顶面和底面,默认为 false ,表示有顶面和底面。

圆环

THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)

其中, radius 是圆环半径; tube 是管道半径; radialSegments 与 tubularSegments 分
别是两个分段数,详见上图; arc 是圆环面的弧度,默认为 Math.PI * 2 。

材质

材质(Material)是与渲染效果相关的属性。通过设置材质可以改变物体的颜色、纹理贴图、光照模式等。材质的共有属性包括:
基础属性
id:用来标识材质。
name:赋予材质名称。
opacity:定义物体透明度,取值范围0~1
side:设定在几何体的哪个面应用材质,默认值为THREE.FrontSide,即外面。也可以设置为THREE.BackSide(内面)或THREE.DoubleSide(双面)。

基本材质

用基本材质(BasicMaterial)的物体渲染后的颜色始终为该材质的颜色,不会由于光照产生明暗、阴影效果。如果没有指定材质的颜色,则颜色是随机的。

THREE.MeshBasicMaterial(opt)

其中, opt 为包含各属性的值。如新建一个不透明度为 0.75 的黄色材质:

new THREE.MeshBasicMaterial({color: 0xffff00,opacity: 0.75});

常用的属性包括:

  1. visible :是否可见,默认为 true
    2.side :渲染面片正面或是反面,默认为正面 THREE.FrontSide ,可设置为反面THREE.BackSide ,或双面 THREE.DoubleSide
  2. wireframe :是否渲染线而非面,默认为 false
  3. color :十六进制 RGB 颜色,如红色表示为 0xff0000
    5.map :使用纹理贴图

Lambert 材质

Lambert 光照模型的主要特点是只考虑漫反射而不考虑镜面反射的效果,因而对于金属、镜子等需要镜面反射效果的物体就不适应,对于其他大部分物体的漫反射效果都是适用的。

new THREE.MeshLambertMaterial(opt)

color 是用来表现材质对散射光的反射能力,也是最常用来设置材质颜色的属性。除此之外,还可以用 ambient 和 emissive 控制材质的颜色。
ambient 表示对环境光的反射能力,只有当设置了 AmbientLight 后,该值才是有效的,材质对环境光的反射能力与环境光强相乘后得到材质实际表现的颜色。
emissive 是材质的自发光颜色,可以用来表现光源的颜色。
如果同时使用红色的自发光与黄色的散射光:

new THREE.MeshLambertMaterial({color: 0xffff00,emissive: 0xff0000})

Phong 材质

Phong 模型考虑了镜面反射的效果,因此对于金属、镜面的表现尤为适合。

new THREE.MeshPhongMaterial(opt);

可以通过 shininess 属性控制光照模型中的 n 值,当 shininess 值越大时,高光的光斑越小,默认值为 30 。
使用黄色的镜面光,红色的散射光:

material = new THREE.MeshPhongMaterial({color: 0xff0000,specular: 0xffff00,shininess: 100});

Depth材质

这种材质的特点在于,不控制物体的渲染效果,外观根据物体到相机的距离变化。一般与其他材质结合形成远处逐渐消失的效果。

联合材质

var depthMaterial=new new THREE.MeshDepthMaterial;var basicMaterial=new new THREE.MeshBasicMaterial(opt);var cube=new THREE.SceneUtils.createMaterialObject(cubeGeometry,[depthMaterial,basicMaterial]);cube.children[1].scale.set(0.99,0.99,0.99);

对于要进行融合的材质,需要添加属性transparent:true开启融合模式。
createMaterialObject()创建网格时,几何体·会被复制,返回一个网格组,内部的网格完全一样。渲染时画面会闪烁。所以需要最后一行代码来缩小带有depth材质的网格,避免出现闪烁。

物体

使用几何形状和材质就能创建物体了。最常用的一种物体就是网格(Mesh),网格是由顶点、边、面等组成的物体;其他物体包括线段(Line)、骨骼(Bone)、粒子系统(ParticleSystem)等。
创建物体需要指定几何形状和材质,其中,几何形状决定了物体的顶点位置等信息,材质决定了物体的颜色、纹理等信息。

创建网格

Mesh(geometry, material)

创建网格要把几何形状与材质传入其构造函数。

var material = new THREE.MeshLambertMaterial({color: 0xffff00});var geometry = new THREE.CubeGeometry(1, 2, 3);var mesh = new THREE.Mesh(geometry, material);scene.add(mesh);

若不设置属性material ,则每次会随机分配一种 wireframe 为 true 的材质,每次刷新页面后的颜色是不同的。除了在构造函数中指定材质,在网格被创建后,也能对材质进行修改。

mesh.material = new THREE.MeshLambertMaterial({color: 0xff0000});

几何变换

平移、缩放、旋转是物体三个常用属性。即为 translate 、scale 、 rotate 三个属性。

平移

mesh.translateX(100);//沿着x轴正方向平移距离100

沿着向量(0,1,0)方向平移

var axis = new THREE.Vector3(0,1,0);//向量axismesh.translateOnAxis(axis,100);//沿着向量axis方向平移100

旋转

mesh.rotateX(Math.PI/4);//绕x轴旋转π/4//绕(0,1,0)向量轴旋转π/8var axis = new THREE.Vector3(0,1,0);//向量axismesh.rotateOnAxis(axis,Math.PI/8);//绕axis向量轴旋转π/8

缩放

mesh.scale.x = 2.0;//x轴方向放大2倍mesh.scale.set(0.5,0.5,0.5);//缩小为原来0.5倍

加载几何模型

Three.js 有一系列导入外部文件的辅助函数,是在 three.js 之外的,使用前需要额外下载。*.obj 是最常用的模型格式,导入 *.obj 文件需要 OBJLoader.js ;导入带 .mtl 材质的.obj 文件需要 MTLLoader.js 以及 OBJMTLLoader.js 。

无材质模型

创建 loader 变量,用于导入模型:

var loader = new THREE.OBJLoader();

接受两个参数,第一个表示模型路径,第二个表示完成导入后的回调函数,一般我们需要在这个回调函数中将导入的模型添加到场景中。

loader.load('../lib/port.obj', function(obj) {mesh = obj; //储存到全局变量中scene.add(obj);});

默认的情况下,只有正面的面片被绘制,模型中部分可能穿模。而如果需要双面绘制,需要这样设置:

var loader = new THREE.OBJLoader();loader.load('../lib/port.obj', function(obj) {obj.traverse(function(child) {if (child instanceof THREE.Mesh) {child.material.side = THREE.DoubleSide; }});mesh = obj;scene.add(obj);});

有材质模型

代码中设置材质
在回调函数中设置模型的材质:

var loader = new THREE.OBJLoader();loader.load('../lib/port.obj', function(obj) {obj.traverse(function(child) {if (child instanceof THREE.Mesh) {child.material = new THREE.MeshLambertMaterial({color: 0xffff00,side: THREE.DoubleSide});}});mesh = obj;scene.add(obj);});

建模软件导出材质
在建模软件导出 port.obj模型文件以及 port.mtl 材质文件,就需要使用 MTLLoader.js 与OBJMTLLoader.js ,并且要按改顺序引用:

调用方法:

var loader = new THREE.OBJMTLLoader();loader.addEventListener('load', function(event) {var obj = event.content;mesh = obj;scene.add(obj);});loader.load('../lib/port.obj', '../lib/port.mtl');

光线

环境光

环境光是指场景整体的光照效果,环境光没有明确的光源位置,在各处形成的亮度也是一致的。

THREE.AmbientLight(hex)

在设置环境光时,只需要指定光的颜色。使用环境光渲染时,环境光并不在乎物体材质的 color 属性,而是 ambient 属性。 ambient 属性的默认值是 0xffffff 。
当环境光使用的颜色比较明亮,渲染的颜色往往会过饱和。因此,环境光通常使用白色或者灰色,作为整体光照的基础。

点光源

点光源是一种单点发光,照射所有方向的光源。点光源照到不同物体表面的亮度是线性递减的。

THREE.PointLight(hex, intensity, distance)

其中, hex 是光源十六进制的颜色值; intensity 是亮度,默认值为 1 ,表示 100%亮度; distance 是光源最远照射到的距离,默认值为 0 。

var light = new THREE.PointLight(0xffffff, 2, 100);light.position.set(0, 1.5, 2);scene.add(light);

聚光灯

聚光灯是一种特殊的点光源,它能够朝着一个方向投射光线。聚光灯投射出的是类似圆锥形的光线,与现实中看到的聚光灯是一致的。

THREE.SpotLight(hex, intensity, distance, angle, exponent)

angle 是聚光灯的张角,默认值是Math.PI / 3 ,最大值是 Math.PI / 2 ; exponent 是光强在偏离 target ( target 需要在之后定义,默认值为 (0, 0, 0) )的衰减指数,默认值是 10 。
在调用构造函数之后,除了设置光源本身的位置,一般还需要设置目标点 target :

light.position.set(x1, y1, z1);light.target.position.set(x2, y2, z2);

除了设置 light.target.position 的方法外,如果想让聚光灯跟着某一物体移动(真正的聚光灯),可以 target 指定为该物体:

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),new THREE.MeshLambertMaterial({color: 0x00ff00}));var light = new THREE.SpotLight(0xffff00, 1, 100, Math.PI / 6, 25);light.target = cube;

平行光

对于任意平行的平面,平行光照射的亮度都是相同的,而与平面所在位置无关。

THREE.DirectionalLight(hex, intensity)

对于平行光而言,设置光源位置尤为重要。

var light = new THREE.DirectionalLight();light.position.set(2, 5, 3);scene.add(light);

注意,这里设置光源位置并不意味着所有光从 (2, 5, 3) 点射出(如果是的话,就成了点光源),而是意味着,平行光将以矢量 (-2, -5, -3) 的方向照射到所有平面。因此,平面亮度与平面的位置无关,而只与平面的法向量相关。只要平面是平行的,那么得到的光照也一定是相同的。

阴影

阴影的形成也就是因为比周围获得的光照更少。因此,要形成阴影,光源必不可少。
在 Three.js 中,能形成阴影的光源只有平行光 THREE.DirectionalLight 与聚光灯 THREE.SpotLight ;而相对地,能表现阴影效果的材质只有 THREE.LambertMaterial 与 THREE.PhongMaterial 。

初始化

首先告诉渲染器渲染阴影:

renderer.shadowMapEnabled = true;

然后,对于光源以及所有要产生阴影的物体调用:

xxx.castShadow = true;

对于接收阴影的物体调用:

xxx.receiveShadow = true;

这就是产生阴影效果的前置条件。

创建阴影

为了看到阴影照相机的位置,通常可以在调试时开启 light.shadowCameraVisible =true 。

对于聚光灯,需要设置 shadowCameraNear 、 shadowCameraFar 、 shadowCameraFov 三个值,类比我们在第二章学到的透视投影照相机,只有介于 shadowCameraNear 与shadowCameraFar 之间的物体将产生阴影, shadowCameraFov 表示张角。

对于平行光,需要设置 shadowCameraNear 、 shadowCameraFar 、 shadowCameraLeft 、shadowCameraRight 、 shadowCameraTop 以及 shadowCameraBottom 六个值,相当于正交投影照相机的六个面。同样,只有在这六个面围成的长方体内的物体才会产生阴影效果。

light.castShadow = true;light.shadow.camera.top = 180;light.shadow.camera.bottom = - 100;light.shadow.camera.left = - 120;light.shadow.camera.right = 120;

动作渲染

原理

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

检测当前场景的渲染帧率和显存占用情况;

stats = new Stats();stats.domElement.style.position = 'absolute';stats.domElement.style.top = '0px';stats.domElement.style.left = '0px';document.body.appendChild(_stats.domElement);

使用时,需要添加入渲染函数内:

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

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
大反转!顺德渔村驱赶母子避雨后续:监控视频公布,宝妈骗了全网

大反转!顺德渔村驱赶母子避雨后续:监控视频公布,宝妈骗了全网

李晚书
2026-06-23 09:56:58
Shams:凯尔特人对字母哥的交易报价为杰伦-布朗+两个首轮签

Shams:凯尔特人对字母哥的交易报价为杰伦-布朗+两个首轮签

懂球帝
2026-06-23 12:32:08
惨!冯小刚新片5天票房仅6700万,时代抛弃你,连句再见都不会说

惨!冯小刚新片5天票房仅6700万,时代抛弃你,连句再见都不会说

八卦南风
2026-06-23 10:16:09
世界杯两场4球!哈兰德场外有最强后盾:青梅竹马女友一路陪伴,闲暇爱玩《我的世界》

世界杯两场4球!哈兰德场外有最强后盾:青梅竹马女友一路陪伴,闲暇爱玩《我的世界》

红星新闻
2026-06-23 12:08:58
安徽广德2死1伤车祸:黄毛女社交账号扒出,闺蜜发声庇护,求宽恕

安徽广德2死1伤车祸:黄毛女社交账号扒出,闺蜜发声庇护,求宽恕

李晚书
2026-06-22 18:19:19
“埃及失联6天”,21岁女孩被判15年监禁

“埃及失联6天”,21岁女孩被判15年监禁

中国新闻周刊
2026-06-23 12:10:07
项立刚:EUV光刻机,中国不仅可以做出来,还会把它搞成白菜价

项立刚:EUV光刻机,中国不仅可以做出来,还会把它搞成白菜价

混沌录
2026-06-22 17:48:16
兰德尔+28号签倒贴换来篮网33号签!你之前换的可是唐斯啊!

兰德尔+28号签倒贴换来篮网33号签!你之前换的可是唐斯啊!

篮球大图
2026-06-23 10:35:15
不撤案杀你全家,山西运城13岁女孩被强奸,不予立案后又调查了

不撤案杀你全家,山西运城13岁女孩被强奸,不予立案后又调查了

汉史趣闻
2026-06-23 08:23:52
台湾方面不接受“一国两制”,王毅回应:往后台湾只有一个称呼

台湾方面不接受“一国两制”,王毅回应:往后台湾只有一个称呼

人生录
2026-06-22 15:37:48
因模仿老师爆火的19岁网红“钟美美”被波士顿大学录取

因模仿老师爆火的19岁网红“钟美美”被波士顿大学录取

大象新闻
2026-06-23 08:53:21
6月23日,人社部关于上调退休人员基本养老金通知正式发布了吗?

6月23日,人社部关于上调退休人员基本养老金通知正式发布了吗?

小彬说事
2026-06-23 08:45:40
周冬雨回应“演话剧不背台词”:导演跟我说不用背台词,舞台上可以随意发挥;此前其出演话剧《文城》被指不背台词、对着剧本还读错

周冬雨回应“演话剧不背台词”:导演跟我说不用背台词,舞台上可以随意发挥;此前其出演话剧《文城》被指不背台词、对着剧本还读错

极目新闻
2026-06-23 09:41:38
世界杯争议!梅西破纪录进球不该算!曼联传奇怒喷:VAR 全瞎了!

世界杯争议!梅西破纪录进球不该算!曼联传奇怒喷:VAR 全瞎了!

奶盖熊本熊
2026-06-23 06:22:09
SpaceX连跌3天,市值较高点跌超6000亿美元

SpaceX连跌3天,市值较高点跌超6000亿美元

第一财经资讯
2026-06-23 07:50:56
这家官方媒体,突破了人伦下限!

这家官方媒体,突破了人伦下限!

汉唐光辉
2026-06-23 07:41:51
娜然辱华言论曝光,霍家婚讯紧急刹车,郭晶晶一句话把门堵死了

娜然辱华言论曝光,霍家婚讯紧急刹车,郭晶晶一句话把门堵死了

李橑在北漂
2026-06-22 16:20:54
三部门:支持外资企业参与提振消费行动

三部门:支持外资企业参与提振消费行动

证券时报
2026-06-22 14:35:50
二婚带娃女子要了40万彩礼、116克黄金和80万婚房,现在不结婚也不退钱!在杭打工父子求助都市快报:怎么办?

二婚带娃女子要了40万彩礼、116克黄金和80万婚房,现在不结婚也不退钱!在杭打工父子求助都市快报:怎么办?

都市快报橙柿互动
2026-06-23 01:56:17
一种被严重低估的“增肌运动”!每天5分钟,肌肉多了,心情也好了

一种被严重低估的“增肌运动”!每天5分钟,肌肉多了,心情也好了

人民日报健康客户端
2026-06-23 07:36:20
2026-06-23 13:24:49
javascript知识园
javascript知识园
javascript编程知识分享,JS加密、JS混淆等等。
209文章数 423关注度
往期回顾 全部

科技要闻

48名中国开发者联名举报苹果

头条要闻

公安局原副局长出狱后公开举报信访局长 最新进展来了

头条要闻

公安局原副局长出狱后公开举报信访局长 最新进展来了

体育要闻

哈兰德国家队52场59球 世界杯狂刷6大纪录

娱乐要闻

喜剧大师曝光肖战拍戏状态!

财经要闻

智谱万亿市值,国产Anthropic真来了?

汽车要闻

华为智驾ADS限时优惠月底结束 7月1日前下订立省3000元

态度原创

手机
本地
时尚
数码
公开课

手机要闻

苹果屏幕供应链:三星LG瓜分iPhone18 Pro面板,折叠屏独锁三星

本地新闻

吃一次广东龙舟饭,才懂什么是豪华盛宴

今年夏天一定要拥有的6条绝美裙子,太好看了!

数码要闻

三星发布UFS 5.0闪存 速度翻倍加载速度更快

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版