个人简介
👀个人主页: 前端杂货铺
⚡开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL)
🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍖开源 rich-vue3 🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js
🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧
内容 | 参考链接 |
---|---|
WebGL专栏 | WebGL 入门 |
Three.js(一) | 创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化 |
Three.js(二) | scene场景、几何体位置旋转缩放、正射投影相机、透视投影相机 |
Three.js(三) | 聚光灯、环境光、点光源、平行光、半球光 |
Three.js(四) | 基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质 |
文章目录
前言
大家好,这里是前端杂货铺。
上篇文章我们学习了 基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质。接下来,我们继续我们 three.js 的学习!
在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。
一、二维平面
PlaneBufferGeometry 一个用于生成平面几何体的类。相较于于 PlaneGeometry 更加轻量化。
javascript
new THREE.PlaneBufferGeometry(width : Float, height : Float, widthSegments : Integer, heightSegments : Integer)
参数名称 | 描述 |
---|---|
width | 平面沿着 X 轴的宽度。默认值是 1 |
height | 平面沿着 Y 轴的高度。默认值是 1 |
widthSegments | (可选)平面的宽度分段数,默认值是 1 |
heightSegments | (可选)平面的高度分段数,默认值是 1 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加平面 平面沿着 X 轴的宽度 | 平面沿着 Y 轴的高度 | 平面的宽度分段数 | 平面的高度分段数
const geometry = new THREE.PlaneBufferGeometry(10, 10, 2, 2);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
二维平面
二、二维圆
CircleGeometry 是欧式几何的一个简单形状,它由围绕着一个中心点的三角分段的数量所构造,由给定的半径来延展。 同时它也可以用于创建规则多边形,其分段数量取决于该规则多边形的边数。
javascript
new MeshDepthMaterial(parameters: Object);
参数名称 | 描述 |
---|---|
radius | 圆形的半径,默认值为1 |
segments | 分段(三角面)的数量,最小值为3,默认值为 32 |
thetaStart | 第一个分段的起始角度,默认为0 |
thetaLength | 圆形扇区的中心角,通常被称为"θ"(西塔)。默认值是2*Pi,这使其成为一个完整的圆 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加二维圆 半径 | 指定创建圆需要的面的数量(最少3个) | 开始画的角度,0-Math.PI * 2 | 角度,定义圆要画多大
const geometry = new THREE.CircleGeometry(4, 10, 0, Math.PI * 2);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
二维圆
三、自定义二维图形
自定义二维图形需要使用到 Shape 对象 和 ShapeGeometry 对象。
Shpae 使用路径以及可选的孔洞来定义一个二维形状平面。 它可以和 ExtrudeGeometry、ShapeGeometry 一起使用,获取点,或者获取三角面。
javascript
new THREE.Shape( points : Array );
参数名称 | 描述 |
---|---|
points | 一个 Vector2 数组 |
ShapeGeometry 形状缓冲几何体,用于从一个或多个路径形状中创建一个单面多边形几何体。
javascript
new THREE.ShapeGeometry(shapes : Array, curveSegments : Integer)
参数名称 | 描述 |
---|---|
shapes | 一个单独的shape,或者一个包含形状的Array |
curveSegments | 每一个形状的分段数,默认值为12 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const shape = new THREE.Shape();
// 将绘制点移动到某处
shape.moveTo(0, 0);
// 从起始位置开始绘制,绘制到xy处停止
shape.lineTo(0, 3);
shape.lineTo(2, 3);
shape.lineTo(5, 0);
shape.lineTo(0, 0);
// 绘制圆
// shape.arc(1, 1, Math.PI * 2, Math.PI * 2, 100);
const geometry = new THREE.ShapeGeometry(shape);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
自定义二维图形
四、立方体
BoxGeometry 是四边形的原始几何类,它通常使用构造函数所提供的 "width"、"height"、"depth" 参数来创建立方体或者不规则四边形。
javascript
new THREE.BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
参数名称 | 描述 |
---|---|
width | X 轴上面的宽度,默认值为 1 |
height | Y 轴上面的高度,默认值为 1 |
depth | Z 轴上面的深度,默认值为 1 |
widthSegments | (可选)宽度的分段数,默认值是 1 |
heightSegments | (可选)高度的分段数,默认值是 1 |
depthSegments | (可选)深度的分段数,默认值是 1 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 宽度 x轴方向 | 高度 y轴方向 | 深度 z轴方向 | x轴方向将面分成多少份 | y... | z...
const geometry = new THREE.BoxGeometry(3, 3, 3, 1, 1, 1);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
立方体
五、球体
SphereGeometry 是 一个用于生成球体的类。
javascript
new THREE.SphereGeometry(radius : Float, widthSegments : Integer, heightSegments : Integer, phiStart : Float, phiLength : Float, thetaStart : Float, thetaLength : Float)
参数名称 | 描述 |
---|---|
radius | 球体半径,默认为 1 |
widthSegments | 水平分段数(沿着经线分段),最小值为 3,默认值为 32 |
heightSegments | 垂直分段数(沿着纬线分段),最小值为 2,默认值为 16 |
phiStart | 指定水平(经线)起始角度,默认值为 0 |
phiLength | 指定水平(经线)扫描角度的大小,默认值为 Math.PI * 2 |
thetaStart | 指定垂直(纬线)起始角度,默认值为0 |
thetaLength | 指定垂直(纬线)扫描角度大小,默认值为 Math.PI |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 半径 | x轴方向将面分成多少份 | y轴方向将面分成多少份 | 从x轴什么位置开始回值 | 绘制多少 | 从y轴什么位置开始回值 | 绘制多少
const geometry = new THREE.SphereGeometry(2, 20, 20, Math.PI * 2, Math.PI * 2, Math.PI * 2, Math.PI * 2);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
球体
六、圆柱体
CylinderGeometry 是 一个用于生成圆柱几何体的类。
javascript
new THREE.CylinderGeometry(radiusTop : Float, radiusBottom : Float, height : Float, radialSegments : Integer, heightSegments : Integer, openEnded : Boolean, thetaStart : Float, thetaLength : Float);
参数名称 | 描述 |
---|---|
radiusTop | 圆柱的顶部半径,默认值是 1 |
radiusBottom | 圆柱的底部半径,默认值是 1 |
height | 圆柱的高度,默认值是 1 |
radialSegments | 圆柱侧面周围的分段数,默认为 32 |
heightSegments | 圆柱侧面沿着其高度的分段数,默认值为 1 |
openEnded | 一个 Boolean 值,指明该圆锥的底面是开放的还是封顶的。默认值为 false,即其底面默认是封顶的 |
thetaStart | 第一个分段的起始角度,默认为 0 |
thetaLength | 圆柱底面圆扇区的中心角,通常被称为"θ"(西塔)。默认值是2*Pi,这使其成为一个完整的圆柱 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 半径 | x轴方向将面分成多少份 | y轴方向将面分成多少份 | 从x轴什么位置开始回值 | 绘制多少 | 从y轴什么位置开始回值 | 绘制多少
const geometry = new THREE.CylinderGeometry(2, 2, 2, 20, 4, false);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
圆柱体
七、圆环
TorusGeometry 是 一个用于生成圆环几何体的类。
javascript
new THREE.TorusGeometry(radius : Float, tube : Float, radialSegments : Integer, tubularSegments : Integer, arc : Float);
参数名称 | 描述 |
---|---|
radius | 环面的半径,从环面的中心到管道横截面的中心。默认值是 1 |
tube | 管道的半径,默认值为 0.4 |
radialSegments | 管道横截面的分段数,默认值为 12 |
tubularSegments | 管道的分段数,默认值为 48 |
arc | 圆环的圆心角(单位是弧度),默认值为 Math.PI * 2 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 半径 | 管子的半径 | 沿圆环长度分为多少段 | 宽度分成多少段 | 是否形成一个完整的闭环 |
const geometry = new THREE.TorusGeometry(2, 1, 10, 10, Math.PI * 2);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
圆环
八、扭结
TorusKnotGeometry 用于创建一个圆环扭结,其特殊形状由一对互质的整数,p和q所定义。如果p和q不互质,创建出来的几何体将是一个环面链接。。
javascript
new THREE.TorusKnotGeometry(radius : Float, tube : Float, tubularSegments : Integer, radialSegments : Integer, p : Integer, q : Integer);
参数名称 | 描述 |
---|---|
radius | 圆环的半径,默认值为 1 |
tube | 管道的半径,默认值为 0.4 |
tubularSegments | 管道的分段数量,默认值为 64 |
radialSegments | 横截面分段数量,默认值为 8 |
p | 这个值决定了几何体将绕着其旋转对称轴旋转多少次,默认值是 2 |
q | 这个值决定了几何体将绕着其内部圆环旋转多少次,默认值是 3 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 半径 | 管子的半径 | 沿圆环长度分为多少段 | 宽度分成多少段 | 定义结的形状 | 定义结的形状 | 拉伸纽结 |
const geometry = new THREE.TorusKnotGeometry(2, 1, 20, 6, 1, 3, 1);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
扭结
九、多面体
PolyhedronGeometry 多面体在三维空间中具有一些平面的立体图形。这个类将一个顶点数组投射到一个球面上,之后将它们细分为所需的细节级别。
javascript
new THREE.PolyhedronGeometry(vertices : Array, indices : Array, radius : Float, detail : Integer);
参数名称 | 描述 |
---|---|
vertices | 一个顶点Array(数组):[1,1,1, -1,-1,-1, ... ] |
indices | 一个构成面的索引Array(数组), [0,1,2, 2,3,0, ... ] |
radius | 最终形状的半径 |
detail | 将对这个几何体细分多少个级别。细节越多,形状就越平滑 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 构成多面体的顶点 | 创建出的面 | 指定多面的大小 | 处理多面体细节 |
const geometry = new THREE.PolyhedronGeometry(vertices, indices, 4, 0);
// 正四面体
// const geometry = new THREE.TetrahedronGeometry(4, 0);
// 正八面体
// const geometry = new THREE.OctahedronGeometry(4, 0);
// 正二十面体
// const geometry = new THREE.IcosahedronGeometry(4, 0);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
多面体
十、文字
TextGeometry 是一个用于将文本生成为单一的几何体的类。 它是由一串给定的文本,以及由加载的font(字体)和该几何体 ExtrudeGeometry 父类中的设置所组成的参数来构造的。
javascript
// text 将要显示的文本
new THREE.TextGeometry(text : String, parameters : Object);
参数名称 | 描述 |
---|---|
font | THREE.Font 的实例 |
size | 字体大小,默认值为100 |
depth | 挤出文本的厚度。默认值为 50 |
curveSegments | (表示文本的)曲线上点的数量。默认值为 12 |
bevelEnabled | 是否开启斜角,默认为 false |
bevelThickness | 文本上斜角的深度,默认值为 20 |
bevelSize | 斜角与原始文本轮廓之间的延伸距离。默认值为 8 |
bevelSegments | 斜角的分段数。默认值为 3 |
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/three/three.js"></script>
<script src="../lib/three/dat.gui.js"></script>
<script src="../controls/index.js"></script>
<script src="../assets/font/font.js"></script>
</head>
<body>
<script>
// 创建场景
const scene = new THREE.Scene();
// 创建相机 视野角度FOV、长宽比、近截面、远截面
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置
camera.position.set(0, 0, 20);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 文字
const geometry = new THREE.TextGeometry("THREE", textOptions);
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
const mesh = {
pointer: new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
])
};
// 添加到场景
scene.add(mesh.pointer);
// 添加灯光
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 10, 90);
scene.add(spotLight);
initControls(geometry, camera, mesh, scene);
const animation = () => {
mesh.pointer.rotation.x += 0.01;
mesh.pointer.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>
文字
GUI 控制文件
老规矩,我们把本篇文章需要使用的 ./controls/index.js
补充完毕
javascript
const basicType = {
// 颜色。默认为一个白色(0xffffff)的 Color 对象。
color: {
method: 'addColor',
getValue: item => item.color.getStyle(),
setValue: (item, value) => item.color.setStyle(value),
},
//
skyColor: {
method: 'addColor',
getValue: item => item.skyColor.getStyle(),
setValue: (item, value) => item.skyColor.setStyle(value),
},
// 光照强度。默认值为 1
intensity: {
method: 'add',
extends: [0, 2],
getValue: item => item.intensity,
setValue: (item, value) => item.intensity = +value,
},
// 光源照射的最大距离。默认值为 0(无限远)
distance: {
method: 'add',
extends: [0, 1],
getValue: item => item.distance,
setValue: (item, value) => item.distance = +value,
},
// 光线照射范围的角度。默认值为 Math.PI/3
angle: {
method: 'add',
extends: [0, Math.PI / 2],
getValue: item => item.angle,
setValue: (item, value) => item.angle = +value,
},
// 决定了光线强度递减的速度。
exponent: {
method: 'add',
extends: [0, 20],
getValue: item => item.exponent,
setValue: (item, value) => item.exponent = +value,
},
// 亮度
opacity: {
extends: [0, 1],
getValue: item => item.opacity,
setValue: (item, value) => item.opacity = +value
},
// 透明度
transparent: {
getValue: item => item.transparent,
setValue: (item, value) => item.transparent = value
},
// 线框
wireframe: {
getValue: item => item.wireframe,
setValue: (item, value) => item.wireframe = value
},
// 显隐
visible: {
getValue: item => item.visible,
setValue: (item, value) => item.visible = value
},
cameraNear: {
extends: [0, 50],
getValue: (item, camera) => camera.near,
setValue: (item, value, camera) => camera.near = value
},
cameraFar: {
extends: [50, 200],
getValue: (item, camera) => camera.far,
setValue: (item, value, camera) => camera.far = value
},
side: {
extends: [
['font', 'back', 'double']
],
getValue: (item, camera) => 'font',
setValue: (item, value) => {
switch (value) {
case 'font':
item.side = THREE.FrontSide;
break;
case 'back':
item.side = THREE.BackSide;
break;
case 'double':
item.side = THREE.DoubleSide;
break;
}
}
},
// 材料的环境颜色
ambient: {
method: 'addColor',
getValue: (item) => item.ambient.getHex(),
setValue: (item, value) => item.ambient = new THREE.Color(value),
},
// 物体材料本身发出的颜色
emissive: {
method: 'addColor',
getValue: (item) => item.emissive.getHex(),
setValue: (item, value) => item.emissive = new THREE.Color(value),
},
// 设置高亮部分的颜色
specular: {
method: 'addColor',
getValue: (item) => item.specular.getHex(),
setValue: (item, value) => item.specular = new THREE.Color(value),
},
// 设置高亮部分的亮度
shininess: {
extends: [0, 100],
getValue: (item) => item.shininess,
setValue: (item, value) => item.shininess = value,
},
red: {
extends: [0, 1],
getValue: (item) => item.uniforms.r.value,
setValue: (item, value) => item.uniforms.r.value = value,
},
alpha: {
extends: [0, 1],
getValue: (item) => item.uniforms.a.value,
setValue: (item, value) => item.uniforms.a.value = value,
},
dashSize: {
extends: [0, 5],
getValue: (item) => item.dashSize,
setValue: (item, value) => item.dashSize = +value,
},
width: getMeshValue([0, 20], 'width'),
height: getMeshValue([0, 20], 'height'),
widthSegments: getMeshValue([0, 20], 'widthSegments'),
heightSegments: getMeshValue([0, 20], 'heightSegments'),
radius: getMeshValue([1, 20], 'radius'),
segments: getMeshValue([3, 80], 'segments'),
thetaStart: getMeshValue([0, Math.PI * 2], 'thetaStart'),
thetaLength: getMeshValue([0, Math.PI * 2], 'thetaLength'),
depth: getMeshValue([0, 20], 'depth'),
depthSegments: getMeshValue([0, 20], 'depthSegments'),
phiStart: getMeshValue([0, Math.PI * 2], 'phiStart'),
radiusTop: getMeshValue([-20, 20], 'radiusTop'),
radiusBottom: getMeshValue([-20, 20], 'radiusBottom'),
radialSegments: getMeshValue([1, 60], 'radialSegments'),
openEnded: getMeshValue([], 'openEnded'),
tube: getMeshValue([1, 6], 'tube'),
tubularSegments: getMeshValue([0, Math.PI * 2], 'tubularSegments'),
arc: getMeshValue([1, 20], 'arc'),
p: getMeshValue([1, 10], 'p'),
q: getMeshValue([1, 10], 'q'),
detail: getMeshValue([0, 5], 'detail'),
heightScale: getMeshValue([0, 5], 'heightScale'),
size: getMeshValue([0, 10], 'size'),
bevelThickness: getMeshValue([1, 30], 'bevelThickness'),
bevelEnabled: getMeshValue([], 'bevelEnabled'),
bevelSegments: getMeshValue([1, 30], 'bevelSegments'),
curveSegments: getMeshValue([1, 30], 'curveSegments'),
steps: getMeshValue([0, 10], 'steps'),
}
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
function createMaterial(geometry) {
const lambert = new THREE.MeshLambertMaterial({
color: 0xff0000
});
const basic = new THREE.MeshBasicMaterial({
wireframe: true
});
return new THREE.SceneUtils.createMultiMaterialObject(geometry, [
lambert, basic
]);
}
// 字体配置
const textOptions = {
size: 1,
height: 1,
weight: 'normal',
font: 'helvetiker',
bevelThickness: 1,
bevelEnabled: false,
bevelSegments: 1,
curveSegments: 1,
steps: 1
}
const roundValue = {
width: 1,
height: 1,
depth: 1,
widthSegments: 1,
heightSegments: 1,
depthSegments: 1, // 不能为 undefined
radialSegments: 1,
tubularSegments: 1,
detail: 1,
size: 1,
bevelSegments: 1,
curveSegments: 1,
steps: 1
}
const isPolyhedron = item => item.type === 'PolyhedronGeometry';
const isFont = item => item.type === 'TextGeometry';
function removeAndAdd(item, value, camera, mesh, scene, controls) {
const {
x,
y,
z
} = mesh.pointer.rotation;
scene.remove(mesh.pointer);
const arg = [];
for (const key in controls) {
if (roundValue[key]) {
// ~~位运算符,转为数字
controls[key] = ~~controls[key];
}
arg.push(controls[key]);
}
// 多面体
if (isPolyhedron(item)) {
arg.unshift(vertices, indices);
}
if (isFont(item)) {
mesh.pointer = createMaterial(new THREE[item.type]('THREE', Object.assign(textOptions, controls)));
} else {
mesh.pointer = createMaterial(new THREE[item.type](...arg));
}
mesh.pointer.rotation.set(x, y, z);
scene.add(mesh.pointer);
}
function getMeshValue(extend, name) {
return {
extends: extend,
getValue: (item, camera, mesh) => isFont(item) && textOptions[name] !== undefined ? textOptions[name] : mesh.children[0].geometry.parameters[name],
setValue: (...arg) => removeAndAdd(...arg)
}
}
const itemType = {
SpotLight: ['color', 'intensity', 'distance', 'angle', 'exponent'], // 聚光灯
AmbientLight: ['color'], // 环境光
PointLight: ['color', 'intensity', 'distance'], // 点光源
DirectionalLight: ['color', 'intensity'], // 平行光
HemisphereLight: ['groundColor', 'intensity'], // 半球光
MeshBasicMaterial: ['color', 'opacity', 'transparent', 'wireframe', 'visible'], // 基础网格材质
MeshDepthMaterial: ['wireframe', 'cameraNear', 'cameraFar'], // 深度网格材质
MeshNormalMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side'],
MeshLambertMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side', 'ambient', 'emissive', 'color'], // 朗伯材质
MeshPhongMaterial: ['opacity', 'transparent', 'wireframe', 'visible', 'side', 'ambient', 'emissive', 'color', 'specular', 'shininess'], // Phong材质
ShaderMaterial: ['red', 'alpha'], // 着色器材质
LineBasicMaterial: ['color'], // 直线
LineDashedMaterial: ['dashSize', 'gapSize'], // 虚线
PlaneBufferGeometry: ['width', 'height', 'widthSegments', 'heightSegments'], // 二维屏幕
CircleGeometry: ['radius', 'segments', 'thetaStart', 'thetaLength'], // 二维圆
BoxGeometry: ['width', 'height', 'depth', 'widthSegments', 'heightSegments', 'depthSegments'], // 立方体
SphereGeometry: ['radius', 'widthSegments', 'heightSegments', 'phiStart', 'phiLength', 'thetaStart', 'thetaLength'], // 球体
CylinderGeometry: ['radiusTop', 'radiusBottom', 'height', 'radialSegments', 'heightSegments', 'openEnded'], // 圆柱体
TorusGeometry: ['radius', 'tube', 'radialSegments', 'tubularSegments', 'arc'], // 圆环
TorusKnotGeometry: ['radius', 'tube', 'radialSegments', 'tubularSegments', 'p', 'q', 'heightScale'], // 纽结
PolyhedronGeometry: ['radius', 'detail'], // 多面缓冲几何体
TetrahedronGeometry: ['radius', 'detail'], // 四面缓冲几何体
OctahedronGeometry: ['radius', 'detail'], // 八面缓冲几何体
IcosahedronGeometry: ['radius', 'detail'], // 二十面缓冲几何体
TextGeometry: ['size', 'bevelThickness', 'bevelEnabled', 'bevelSegments', 'curveSegments', 'steps'],
}
function initControls(item, camera, mesh, scene) {
console.log('item', item)
const typeList = itemType[item.type];
const controls = {};
if (!typeList || !typeList.length) {
return;
}
const gui = new dat.GUI();
for (let i = 0; i < typeList.length; i++) {
const child = basicType[typeList[i]];
if (child) {
controls[typeList[i]] = child.getValue(item, camera, mesh.pointer);
const childExtends = child.extends || [];
gui[child.method || 'add'](controls, typeList[i], ...childExtends).onChange((value) => {
child.setValue(item, value, camera, mesh, scene, controls);
})
}
}
}
总结
本篇文章我们讲解了几种常见几何体的基本使用,包括二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字。
更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!
好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!
参考资料:
- Three.js 官方文档
- WebGL+Three.js 入门与实战【作者:慕课网_yancy】