文章同步更新于我的个人博客:松果猿的博客,欢迎访问获取更多技术分享。
同时,您也可以关注我的微信公众号:松果猿的代码工坊,获取最新文章推送和编程技巧。
记录本人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)一起使用来渲染几何体,如下所示:
javascript
// 创建一个立方体几何体
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 对象的 x 、y 、z 属性进行赋值。 |
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)
透视摄像机模拟人眼的视觉效果,即远处的物体看起来更小。
正交摄像机提供无透视的视图,即物体的大小不会随着距离变化。
javascript
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)
javascript
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 中创建和使用摄像机的示例:
javascript
// 创建一个透视摄像机
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.width
和light.shadow.mapSize.height
。 - 衰减 :点光源和聚光灯可以设置衰减属性,如
light.distance
和light.decay
。
示例代码
javascript
// 创建场景
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() |
使用法线向量着色 |
材质常用属性
javascript
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
});
纹理贴图示例
javascript
// 创建纹理加载器
const textureLoader = new THREE.TextureLoader();
// 加载纹理
const texture = textureLoader.load('texture.jpg');
// 创建材质
const material = new THREE.MeshStandardMaterial({
// 颜色纹理
map: texture,
// 法线贴图(凹凸感)
normalMap: normalTexture,
// 粗糙度贴图
roughnessMap: roughnessTexture,
// 金属度贴图
metalnessMap: metalnessTexture
});
高级材质效果
javascript
// 多重贴图
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 // 自发光强度
});
高级技巧
- 动态改变材质
javascript
// 实时更新材质属性
material.color.set(0x00ff00); // 改变颜色
material.opacity = 0.8; // 改变透明度
material.needsUpdate = true; // 通知渲染器更新
- 复制材质
javascript
const newMaterial = material.clone();
- 材质混合
javascript
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)**是纹理在材质上的具体应用,定义纹理如何影响物体外观
javascript
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() |
在动画循环中更新控制器状态 |
动画循环
javascript
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) |
实现物体的变换控制 |