Three.js的学习(2)—— Three.js 的一些关键特性

181 阅读10分钟

文章同步更新于我的个人博客:松果猿的博客,欢迎访问获取更多技术分享。

同时,您也可以关注我的微信公众号:松果猿的代码工坊,获取最新文章推送和编程技巧。

记录本人three.js的学习之路

在 上一篇文章【Three.js的学习(1)】里,我们已经创建了一个基本的场景。

下面我们对three.js每个特性做一个大致的了解

1. 场景(Scene)

场景是一个容器对象,可以包含物体、摄像机、灯光和渲染器。

操作代码说明
创建场景const scene = new THREE.Scene();创建一个3D场景容器
获取场景中的对象scene.getObjectByName('cube');通过名称查找场景中的对象
遍历场景对象scene.traverse(function(obj) {});遍历场景中的所有对象
添加雾效果scene.fog = new THREE.Fog(0x000000, 1, 1000);为场景添加雾化效果
克隆场景scene.clone();创建场景的副本
检查对象是否在场景中scene.children.includes(object);判断对象是否存在于场景中
获取场景对象数量scene.children.length;获取场景中对象的数量
更新场景矩阵scene.updateMatrix();更新场景的变换矩阵
移除单个对象scene.remove(mesh);从场景中移除指定的3D对象
移除多个对象scene.remove(mesh1, mesh2, mesh3);同时移除多个指定的对象

2. 几何体(Geometry)

几何体定义了物体的形状和结构,例如立方体、球体、圆柱体等。

几何体类型描述创建方法
立方体(Box)一个六面体,每个面都是矩形。var geometry = new THREE.BoxGeometry(width, height, depth);
球体(Sphere)一个圆形的三维几何体。var geometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
圆柱体(Cylinder)一个直的圆柱体。var geometry = new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded);
圆环体(Torus)一个甜甜圈形状的几何体。var geometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc);
平面(Plane)一个无限大的平面。var geometry = new THREE.PlaneGeometry(width, height);
圆(Circle)一个二维圆形。var geometry = new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength);

创建几何体后,通常需要与材料(Material)一起使用来渲染几何体,如下所示:

// 创建一个立方体几何体
var geometry = new THREE.BoxGeometry(1, 1, 1);

// 创建一个材料
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});

// 创建网格(Mesh),网格由几何体和材料组成
var cube = new THREE.Mesh(geometry, material);

// 将网格添加到场景中
scene.add(cube);

主要的方法属性

属性描述
vertices包含几何体所有顶点的数组。
faces包含几何体所有面的数组。
faceVertexUvs包含几何体所有面的纹理坐标的数组。
boundingBox几何体的轴对齐边界框(Axis-Aligned Bounding Box),用于快速剔除和碰撞检测等。
boundingSphere几何体的包围球,用于快速剔除和碰撞检测等。
方法描述
clone()创建当前几何体的一个副本。
dispose()释放几何体的内存,包括所有的属性数组。
computeVertexNormals()计算顶点法线,用于平滑光照。
merge()将参数中的几何体合并到当前几何体中。
rotateX()绕X轴旋转几何体。
rotateY()绕Y轴旋转几何体。
rotateZ()绕Z轴旋转几何体。
translate()平移几何体。
scale()缩放几何体。
center()将几何体居中于原点。

赋值方法

属性/方法描述代码示例
直接赋值直接创建一个新的 Vector3 实例并赋值给对象的属性。javascript<br>sphere.position = new THREE.Vector3(0, 0, 0);<br>sphere.rotation = new THREE.Vector3(0.5 * Math.PI, 0, 0);<br>sphere.scale = new THREE.Vector3(2, 0, 0);<br>
单个赋值直接对 Vector3 对象的 xyz 属性进行赋值。javascript<br>sphere.position.x = 0;<br>sphere.rotation.x = 0.5 * Math.PI;<br>sphere.scale.x = 2;<br>
通过方法赋值使用 Vector3 对象的 set 方法来赋值。javascript<br>sphere.position.set(0, 0, 0);<br>sphere.rotation.set(0.5 * Math.PI, 0, 0);<br>sphere.scale.set(2, 0, 0);<br>

3. 摄像机(Camera)

在 Three.js 中,摄像机(Camera)是用于定义场景视图和投影方式的对象。以下是一些常用的摄像机类型及其属性和方法的概述:

透视摄像机(PerspectiveCamera)

透视摄像机模拟人眼的视觉效果,即远处的物体看起来更小。

正交摄像机提供无透视的视图,即物体的大小不会随着距离变化。

视锥体

PerspectiveCamera( fov, aspect, near, far )
属性/方法描述使用方法
fov视野角度,以度为单位。camera.fov = 75;
aspect摄像机的宽高比,通常是窗口或渲染器的宽度除以高度。camera.aspect = window.innerWidth / window.innerHeight;
near摄像机的近裁剪面,较小的值可以提高性能,但可能导致渲染问题。camera.near = 0.1;
far摄像机的远裁剪面,较大的值可以包含更多的场景,但可能影响性能。camera.far = 1000;
updateProjectionMatrix更新摄像机的投影矩阵。camera.updateProjectionMatrix();
lookAt使摄像机的前方指向指定的点。camera.lookAt(scene.position);

正交摄像机(OrthographicCamera)

正投影可视空间

OrthographicCamera( left, right, top, bottom, near, far )
属性/方法描述使用方法
left摄像机视图的左边界。camera.left = -10;
right摄像机视图的右边界。camera.right = 10;
top摄像机视图的上边界。camera.top = 10;
bottom摄像机视图的下边界。camera.bottom = -10;
near摄像机的近裁剪面。camera.near = -10;
far摄像机的远裁剪面。camera.far = 1000;
updateProjectionMatrix更新摄像机的投影矩阵。camera.updateProjectionMatrix();
lookAt使摄像机的前方指向指定的点。camera.lookAt(scene.position);

摄像机的共同方法

除了特定类型的摄像机属性外,还有一些方法是所有摄像机类型共有的:

属性/方法描述使用方法
position摄像机的位置。camera.position.set(x, y, z);
rotation摄像机的旋转。camera.rotation.set(x, y, z);
scale摄像机的缩放。camera.scale.set(scaleX, scaleY, scaleZ);
updateMatrix更新摄像机的矩阵。camera.updateMatrix();
updateMatrixWorld更新摄像机的世界矩阵。camera.updateMatrixWorld(true);

使用摄像机

以下是如何在 Three.js 中创建和使用摄像机的示例:

// 创建一个透视摄像机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

// 设置摄像机的位置
camera.position.set(0, 0, 5);

// 将摄像机的前方指向场景的中心
camera.lookAt(new THREE.Vector3(0, 0, 0));

// 创建渲染器并添加到 DOM
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 渲染场景
function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}

animate();

在这个示例中,我们创建了一个透视摄像机,设置了它的位置和方向,并在渲染循环中使用它来渲染场景。

4. 光源(Light)

光源类型

光源类型代码示例说明
环境光const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);提供全局光照,不产生阴影。第一个参数为颜色,第二个参数为强度。
点光源const pointLight = new THREE.PointLight(0xffffff, 1, 100);从一个点向各个方向发光,可以产生阴影。第一个参数为颜色,第二个参数为强度,第三个参数为距离。
平行光const directionalLight = new THREE.DirectionalLight(0xffffff, 1);从一个方向发光,可以模拟太阳光,产生阴影。第一个参数为颜色,第二个参数为强度。
聚光灯const spotLight = new THREE.SpotLight(0xffffff, 1);从一个点向特定方向发光,形成锥形光束。第一个参数为颜色,第二个参数为强度。可以设置角度、距离等属性。
半球光const hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);从上半球发光,产生柔和的光照效果。第一个参数为上半球颜色,第二个参数为下半球颜色,第三个参数为强度。
区域光const rectAreaLight = new THREE.RectAreaLight(0xffffff, 1, width, height);从一个矩形区域发光,适合用于室内场景。

常用属性和方法

  • 位置:通过 light.position.set(x, y, z) 设置光源的位置。
  • 强度:通过 light.intensity 属性设置光源的强度。
  • 颜色:通过 light.color.set(0xff0000) 设置光源的颜色。
  • 阴影:通过 light.castShadow = true 启用光源的阴影效果。需要设置阴影属性,如 light.shadow.mapSize.widthlight.shadow.mapSize.height
  • 衰减:点光源和聚光灯可以设置衰减属性,如 light.distancelight.decay

示例代码

// 创建场景
const scene = new THREE.Scene();

// 创建环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

// 创建点光源
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(10, 10, 10);
scene.add(pointLight);

// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);

// 创建聚光灯
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 6; // 设置光束角度
scene.add(spotLight);

5. 材质**(Material)**:

基本材质类型

材质类型代码特点
基础材质new THREE.MeshBasicMaterial()不受光照影响,均匀着色
lambert材质new THREE.MeshLambertMaterial()对光照有反应,漫反射
Phong材质new THREE.MeshPhongMaterial()高光效果,可以模拟金属、塑料等
标准材质new THREE.MeshStandardMaterial()基于物理的渲染(PBR),真实感更强
法线材质new THREE.MeshNormalMaterial()使用法线向量着色

材质常用属性

const material = new THREE.MeshStandardMaterial({
    // 颜色
    color: 0xff0000,  // 红色
    
    // 透明度
    opacity: 0.5,
    transparent: true,
    
    // 纹理
    map: textureLoader.load('texture.jpg'),
    
    // 高光
    shininess: 100,  // Phong材质特有
    
    // 粗糙度和金属感(标准材质)
    roughness: 0.5,  // 0-1之间,表面粗糙程度
    metalness: 0.5,  // 0-1之间,金属感
    
    // 环境贴图
    envMap: envMap,
    
    // 是否显示线框
    wireframe: false
});

纹理贴图示例

// 创建纹理加载器
const textureLoader = new THREE.TextureLoader();

// 加载纹理
const texture = textureLoader.load('texture.jpg');

// 创建材质
const material = new THREE.MeshStandardMaterial({
    // 颜色纹理
    map: texture,
    
    // 法线贴图(凹凸感)
    normalMap: normalTexture,
    
    // 粗糙度贴图
    roughnessMap: roughnessTexture,
    
    // 金属度贴图
    metalnessMap: metalnessTexture
});

高级材质效果

// 多重贴图
const material = new THREE.MeshStandardMaterial({
    // 基础颜色贴图
    map: colorTexture,
    
    // 法线贴图(模拟表面细节)
    normalMap: normalTexture,
    normalScale: new THREE.Vector2(1, 1),
    
    // 环境贴图
    envMap: envMap,
    envMapIntensity: 1
});

// 自发光材质
const emissiveMaterial = new THREE.MeshStandardMaterial({
    color: 0xffff00,
    emissive: 0xffff00,  // 自发光颜色
    emissiveIntensity: 1  // 自发光强度
});

高级技巧

  1. 动态改变材质
// 实时更新材质属性
material.color.set(0x00ff00);  // 改变颜色
material.opacity = 0.8;  // 改变透明度
material.needsUpdate = true;  // 通知渲染器更新
  1. 复制材质
const newMaterial = material.clone();
  1. 材质混合
const material = new THREE.ShaderMaterial({
    uniforms: {
        // 自定义uniform变量
    },
    vertexShader: `...`,
    fragmentShader: `...`
});

6. 纹理(Texture)

纹理(Textures)是用于给3D对象添加外观和细节的关键元素。纹理可以模拟各种材料的表面,如木材、金属、水等。以下是一些常用的纹理类型及其属性和方法:

常用纹理类型及其属性

纹理类型描述主要属性/方法
Texture基础纹理类型,用于添加颜色、图案等。minFilter, magFilter, wrapS, wrapT, offset, repeat, rotation
CanvasTexture用于从 HTML5 <canvas> 元素创建纹理。image, needsUpdate, format, type, anisotropy, colorSpace
DataTexture用于创建自定义数据纹理,如深度图或法线图。image, data, format, type, colorSpace
CubeTexture立方体贴图,用于环境映射和反射。images, format, mapping, minFilter, magFilter
VideoTexture用于从视频元素创建纹理。video, minFilter, magFilter, format, type
CompressedTexture用于创建压缩纹理,减少内存使用。mipmaps, generateMipmaps, premultiplyAlpha

纹理设置属性

属性代码说明
重复texture.repeat.set(2, 2)设置纹理重复次数
偏移texture.offset.set(0.5, 0.5)设置纹理偏移量
旋转texture.rotation = Math.PI/4设置纹理旋转角度
包裹模式texture.wrapS = THREE.RepeatWrapping设置水平包裹模式
过滤方式texture.minFilter = THREE.LinearFilter设置纹理缩小过滤
翻转Y轴texture.flipY = false控制纹理是否垂直翻转
编码texture.encoding = THREE.sRGBEncoding设置纹理编码方式
更新texture.needsUpdate = true标记纹理需要更新

常见贴图类型

**贴图(Map)**是纹理在材质上的具体应用,定义纹理如何影响物体外观

const material = new THREE.MeshStandardMaterial({
    map: colorTexture,          // 颜色贴图
    normalMap: normalTexture,   // 法线贴图
    roughnessMap: roughMap,     // 粗糙度贴图
    bumpMap: bumpTexture,       // 凹凸贴图
    aoMap: aoTexture,          // 环境遮挡贴图
    displacementMap: dispMap    // 置换贴图
});

7. 其他

相机控制器(OrbitControls)

方法/属性代码说明
创建控制器const controls = new OrbitControls(camera, renderer.domElement)初始化轨道控制器
启用阻尼controls.enableDamping = true添加惯性
自动旋转controls.autoRotate = true相机自动围绕目标旋转
缩放限制controls.minDistance = 2; controls.maxDistance = 10设置缩放范围
更新控制器controls.update()在动画循环中更新控制器状态

动画循环

function animate() {
    requestAnimationFrame(animate);
    
    // 更新控制器
    controls.update();
    
    // 更新场景中的对象
    mesh.rotation.x += 0.01;
    
    // 渲染场景
    renderer.render(scene, camera);
}
animate();

交互

交互类型代码说明
射线检测const raycaster = new THREE.Raycaster()创建射线检测器
鼠标事件renderer.domElement.addEventListener('click', onClick)监听鼠标事件
物体选择raycaster.intersectObjects(objects)检测射线与物体的交叉
拖拽控制const dragControls = new DragControls(objects, camera, renderer.domElement)实现物体拖拽
变换控制const transformControls = new TransformControls(camera, renderer.domElement)实现物体的变换控制