基础概念
Renderer(渲染器):
渲染器是Three.js中负责将3D场景转换为2D图像并显示在网页上的核心组件。常见的渲染器类型是WebGLRenderer,它利用WebGL技术与浏览器的canvas元素配合工作,将三维模型、光照效果等渲染到屏幕上。
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
在Three.js中,最常用且广泛支持的渲染器类型是WebGLRenderer,它基于WebGL技术,允许在浏览器中高效地渲染3D内容。然而,除了WebGLRenderer外,Three.js也提供了其他几种渲染器以适应不同的需求和环境:
- WebGLRenderer
这是最主要且功能最强大的渲染器,利用WebGL API来实现硬件加速的3D图形渲染。 - CSS3DRenderer
该渲染器使用CSS3的3D变换特性来渲染三维对象,适合轻量级应用或对WebGL不支持的旧版浏览器。 - SVGRenderer
SVG(Scalable Vector Graphics)渲染器将场景渲染为矢量图形,适用于需要生成可缩放矢量输出的应用。 - CanvasRenderer
在WebGL不可用的情况下,可以使用CanvasRenderer通过HTML5 Canvas元素进行2D渲染。不过请注意,CanvasRenderer对于复杂的3D场景性能较低,并且不支持许多高级特性,如光照、阴影等。
随着WebGL标准的普及,大部分现代浏览器都支持WebGL,因此WebGLRenderer成为了Three.js中最常使用的渲染器类型。而其他类型的渲染器由于性能、功能限制以及兼容性问题,在实际项目中的应用相对较少。
Scene(场景):
场景是容纳所有3D对象(如网格、光源、相机和辅助对象等)的地方。它是整个3D世界的基础容器。
const scene = new THREE.Scene();
Camera(相机):
相机决定了用户如何查看场景中的内容,类似于现实生活中摄影机的作用。
在Three.js中,相机(Camera)是至关重要的组件,它决定了场景的观察视角和渲染方式。主要提供了两种类型的相机:
- 透视投影相机 (PerspectiveCamera):
透视投影模拟了人眼看到的真实世界效果,具有近大远小的透视特性。
构造函数:
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
参数说明:
-
fov:视场角(Field of View),以度为单位,表示相机镜头能看到的角度大小,默认值通常在45到60之间。
- aspect:长宽比,通常设置为当前视窗宽度除以高度。
- near:近裁剪面距离,表示离相机最近还能被渲染的物体的距离。
- far:远裁剪面距离,表示离相机最远还能被渲染的物体的距离。
正交投影相机 (OrthographicCamera):
正交投影不会产生透视效果,所有物体不论远近看起来都一样大小。
构造函数:
const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
参数说明:
- left 和 right:定义摄像机视野在X轴上的范围。
- top 和 bottom:定义摄像机视野在Y轴上的范围。
- near 和 far:与透视相机相同,同样代表近裁剪面和远裁剪面距离。
Render Loop(渲染循环):
在Three.js中,需要设置一个动画渲染循环来持续更新和重新绘制场景以实现动态效果。
function animate() {
requestAnimationFrame(animate)
// 更新场景中的任何动态内容
// 渲染场景
renderer.render(scene, camera);
}
animate();
Geometry(几何体) 和 Material(材质):
几何体定义了3D对象的形状,例如立方体、球体或自定义网格。
材质则定义了物体表面的颜色、纹理、透明度以及其他视觉属性。
几何体和材质组合形成了Mesh(网格)。
以下是three.js中定义的几何体:
名称 | 示例代码 | 参数说明 |
---|---|---|
BoxGeometry - 立方体 | const geometry = new THREE.BoxGeometry(width, height, depth); | 参数分别代表立方体的宽度、高度和深度。 |
SphereGeometry - 球体 | const geometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments); | 参数分别为球体半径、经度分割数(水平方向上的线段数)、纬度分割数(垂直方向上的线段数)。 |
CylinderGeometry - 圆柱体 | const geometry = new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded); | 参数分别为上底面半径、下底面半径、圆柱高度、沿圆周方向的分段数、沿高度方向的分段数以及是否打开两端(默认为false,即两端封闭)。 |
ConeGeometry - 圆锥体 | const geometry = new THREE.ConeGeometry(radius, height, radialSegments, heightSegments, openEnded); | 类似于圆柱体,参数中没有了上下底面半径的区别,只有一个半径参数,并用于定义圆锥顶部的半径。 |
PlaneGeometry - 平面 | const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments); | 参数分别表示平面的宽度、高度以及沿宽高方向的分段数 |
CircleGeometry - 圆形 | const geometry = new THREE.CircleGeometry(radius, segments); | 参数分别为圆的半径和圆周上的分段数。 |
TorusGeometry - 圆环体 | const geometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc); | 参数分别为圆环体的半径、管状部分的半径、围绕中心轴的圆形细分数量、围绕管状部分的圆形细分数量,以及圆弧所覆盖的角度范围(以圆周的百分比表示,默认为Math.PI * 2,即整个圆周)。 |
IcosahedronGeometry 和 OctahedronGeometry - 正二十面体和正八面体等多面体几何体。 | ||
RingGeometry - 环形几何体 | const geometry = new THREE.RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength); | 参数分别表示内径、外径、theta方向(垂直于环面)的分段数、phi方向(沿着环面)的分段数、起始角度和结束角度。 |
以下是three.js中定义的材质:
名称 | 说明 | 示例 |
---|---|---|
MeshBasicMaterial | 最基本的材质类型,不支持光照计算,仅使用颜色填充 | const basicMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, // 颜色,默认白色 transparent: false, // 是否透明,默认为false opacity: 1.0, // 透明度,默认为1(完全不透明) side: THREE.FrontSide // 渲染面,默认只渲染正面 }); |
MeshLambertMaterial | 简单漫反射光照材质,对环境光有响应,但不支持镜面高光和阴影 | const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, emissive: 0x000000, // 自发光颜色 map: texture, // 纹理贴图 side: THREE.DoubleSide // 双面渲染 }); |
MeshPhongMaterial | 具有漫反射、镜面高光和环境贴图等更复杂的光照模型,支持阴影。 | const phongMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, emissive: 0x000000, specular: 0x111111, // 镜面高光颜色 shininess: 30, // 高光强度(光泽度) map: texture, normalMap: normalTexture, // 法线贴图 bumpMap: bumpTexture, // 凸凹贴图 lightMap: lightTexture, // 光照贴图 envMap: reflectionCube, // 环境贴图(立方体贴图) combine: THREE.MultiplyOperation // 多种贴图混合模式 }); |
MeshStandardMaterial | 基于物理渲染(PBR)的标准材质,提供最真实的光照和材质表现 | const standardMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff, metalness: 0.5, // 金属度 roughness: 0.5, // 粗糙度 map: texture, aoMap: ambientOcclusionTexture, // 环境遮蔽贴图 metalnessMap: metalnessTexture, // 金属度贴图 roughnessMap: roughnessTexture, // 粗糙度贴图 normalMap: normalTexture, envMap: reflectionCube, alphaTest: 0.5, // 用于剔除透明度低于此值的像素 transparent: true, // 是否开启透明度 opacity: 1.0 }); |
LineBasicMaterial | 用于渲染线段或线框模型的基本线条材质 | const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 1, // 线宽,WebGL2环境中有效 linecap: ‘round’, // 线头样式 linejoin: ‘round’ // 线连接处样式 }); |
PointsMaterial | 用于点状几何体(如粒子系统)的材质 | const pointsMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 1, // 点大小 sizeAttenuation: true, // 点大小是否随距离衰减 map: texture, // 点纹理 transparent: true, opacity: 0.8 }); |
ShaderMaterial | 可自定义着色器代码的材质。 | const shaderMaterial = new THREE.ShaderMaterial({ uniforms: { time: { value: 0 }, texture: { value: texture } }, vertexShader: varying vec2 vUv;<br/> void main() {<br/> vUv = uv;<br/> gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);<br/> }<br/> ,fragmentShader: uniform sampler2D texture;<br/> varying vec2 vUv;<br/> void main() {<br/> gl_FragColor = texture2D(texture, vUv);<br/> }<br/> ,}); |
这些几何体可以与材质(Material)结合创建Mesh对象并添加到场景中进行渲染。例如:
const material = new THREE.MeshBasicMaterial({ color: 0xffffff });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Lighting(光照)
光照对于创建逼真的3D场景至关重要,包括环境光、点光源、聚光灯等多种光源类型。
以下是three.js中提供的光照类型及简单说明:
名称 | 说明 | 示例 | 参数 |
---|---|---|---|
AmbientLight(环境光) | 均匀地照亮场景中的所有物体,不产生阴影。 | const ambientLight = new THREE.AmbientLight(color, intensity); | color:THREE.Color对象或CSS颜色字符串,表示环境光的颜色。 intensity:数值类型,表示光照强度,默认值为1。 |
DirectionalLight(平行光/方向光) | 模拟从无限远的点发出、且光线平行的光源,如太阳光 | const directionalLight = new THREE.DirectionalLight(color, intensity); directionalLight.position.set(x, y, z); // 设置光源的位置 | color:同上,表示光源颜色。 intensity:同上,表示光照强度。 position:设置光源相对于世界坐标的坐标位置。 |
PointLight(点光源) | 从一个点向各个方向发射光源,随着距离增加亮度衰减。 | const pointLight = new THREE.PointLight(color, intensity, distance, decay); pointLight.position.set(x, y, z); | color:光源颜色。 intensity:光源强度。 distance:光源的影响范围,默认值为0(无限制)。 decay:衰减系数,用于计算光照强度随距离的衰减,默认值为1。当值大于1时,表示非线性衰减。 |
SpotLight(聚光灯) | 光线从一个点沿特定方向射出,并形成具有角度限制的圆锥形光照区域 | const spotLight = new THREE.SpotLight(color, intensity, distance, angle, penumbra, decay); spotLight.position.set(x, y, z); spotLight.target.position.set(targetX, targetY, targetZ); | color:光源颜色。 intensity:光源强度。 distance:光源影响的最大距离。 angle:光源圆锥角大小,以弧度表示,决定了光照的集中程度。 penumbra:边缘柔化程度,定义了光晕的宽度,即主光照区与完全黑暗区之间的过渡范围。 decay:衰减系数,同上。 target:指定光照的方向,通过设置目标点的位置来确定光源照射的方向。 |
HemisphereLight(半球光) | 模拟天空光源和地面反射光源的组合效果,通常用来添加全局环境照明和基本色彩。 | const hemisphereLight = new THREE.HemisphereLight(skyColor, groundColor, intensity); | skyColor:天空部分的光源颜色。 groundColor:地面反射部分的光源颜色。 intensity:光源强度。 |
通过上述基本概念的组合,您可以使用Three.js构建复杂的3D应用程序,并通过调用renderer.render(scene, camera);这一关键方法来完成每一帧的渲染。
简单示例
接下来通过一个简单示例展示three.js使用的基本流程。以下内容完全基于html+css+js实现。
先看下实现的效果:
threejs示例视频-20240226
看下完整代码和简单分析:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3D Map with Three.js</title>
<style> body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.131.3/build/three.min.js"></script>
<script>
//场景
const scene = new THREE.Scene();
//透视投影相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);
//创建渲染器 设置抗锯齿属性为true
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
//设置背景色
renderer.setClearColor("#222222");
//作为元素添加到html中
document.body.appendChild(renderer.domElement);
camera.position.z = 5;
// resize 事件
window.addEventListener("resize", () => {
let width = window.innerWidth;
let height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
/**
* updateProjectionMatrix() 是 Three.js 中的一个方法,
* 通常用于相机(Camera)对象。在Three.js中,当你更改了相机的投影参数(如透视相机的视场角、近裁剪面或远裁剪面等),
* 或者更改了相机的位置、朝向等影响其投影矩阵的因素时,需要调用此方法来更新相机的内部投影矩阵。
*/
camera.updateProjectionMatrix();
});
// 立体方
/**
* BoxGeometry 是 Three.js 中用于创建一个立方体几何体的对象。
* 在Three.js中,所有3D模型都是基于几何体(Geometry)和材质(Material)构建的。
* BoxGeometry 提供了一种简单的方式创建一个具有指定宽度、高度和深度的立方体
* @type {BoxGeometry}
*/
const geometry = new THREE.BoxGeometry(1, 1, 1);
/**
* MeshStandardMaterial 是 Three.js 中的一种材质类型,
* 用于实现物理上基于真实感照明的标准着色模型(PBR - Physically Based Rendering)。
* 它考虑了材质的多种属性,如颜色、粗糙度、金属度、环境光遮蔽贴图等,以模拟现实生活中的光照效果。
* @type {Mesh}
*/
const material = new THREE.MeshStandardMaterial({
color: 0xff0051,
flatShading: true,
metalness: 0,
roughness: 1,
});
// 将材质与几何体结合创建Mesh对象
const cube = new THREE.Mesh(geometry, material);
// 将立方体添加到场景中
scene.add(cube);
// 维数据集
const geometry2 = new THREE.BoxGeometry(3, 3, 3);
/**
* MeshBasicMaterial 是 Three.js 中的一种材质类型,
* 提供了一种简单的、不考虑光照影响的着色方式。
* 这种材质通常用于快速渲染或不需要光照效果(如纯色填充)的情况。
*/
const material2 = new THREE.MeshBasicMaterial({
color: "#dadada",
wireframe: true,
transparent: true,
});
const wireframeCube = new THREE.Mesh(geometry2, material2);
scene.add(wireframeCube);
// 环境光
/**
* AmbientLight 是 Three.js 中的一种光源类型,
* 它模拟环境光的效果,即场景中的每个点都会受到相同强度和颜色的光照。
* 在三维场景中添加 AmbientLight 可以提供全局的基础照明。
* @type {AmbientLight}
*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);
// 点光源
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(25, 50, 25);
scene.add(pointLight);
const helper = new THREE.CameraHelper(camera)
scene.add(helper)
//添加动画
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
wireframeCube.rotation.x += 0.01;
wireframeCube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
下面是简要流程分析:
- 创建场景(Scene)对象,用于存储3D对象。
- 创建透视投影相机(PerspectiveCamera)对象,用于控制视角和投影。
- 创建WebGL渲染器(WebGLRenderer)对象,用于将3D场景渲染到HTML元素中。
- 设置渲染器的大小和背景色。
- 将渲染器添加到HTML元素中。
- 设置相机的位置和大小。
- 添加窗口调整事件监听器,以便在窗口大小改变时重新设置渲染器的大小和相机的投影矩阵。
- 创建立方体几何体(BoxGeometry)对象和材质(MeshStandardMaterial)对象,用于创建一个立方体。
- 将几何体和材质结合起来创建一个网格(Mesh)对象,并将其添加到场景中。
- 创建另一个立方体几何体和材质对象,但使用了另一种材质类型(MeshBasicMaterial),用于创建一个网格对象,并将其添加到场景中。
- 创建环境光(AmbientLight)对象,用于提供全局的基础照明。
- 创建点光源(PointLight)对象,用于提供局部光照。
- 创建一个辅助对象(CameraHelper),用于可视化相机的投影。
- 定义一个动画函数(animate),用于更新立方体的旋转角度,并调用渲染器的渲染函数。
- 在动画函数中,不断调用requestAnimationFrame方法来实现动画效果。
通过以上步骤,可以实现一个简单的3D应用,其中包含一个立体方和一个环境光,以及一个点光源。
以上步骤中1-7 以及11-15基本都是固定写法,而且也是创建一个3d场景的基础操作,可以当做模板使用。
而中间的8-11看似简单的4个步骤却可以创造出不同的3d世界,根据不同的需求结合three.js提供的几何体、材质、光源、相机位置可以做出各种各样的3d对象以及视图。
后续我们会结合具体场景由浅入深逐步深入研究其中的更多的奥妙,欢迎持续关注。
总结
本文主要介绍了three.js的基础概念,以及使用three.js创建简单对象的流程(模板)。
作为记录的同时也希望能帮助到需要的朋友。针对以上内容有任何疑问或者建议欢迎评论区留言讨论。
创作不易,欢迎一键三连~~~