Three.js——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字
个人简介
👀个人主页: 前端杂货铺
⚡开源项目: 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材质、着色器材质、直线和虚线、联合材质 |
文章目录
- 前言
- 一、二维平面
- 二、二维圆
- 三、自定义二维图形
- 四、立方体
- 五、球体
- 六、圆柱体
- 七、圆环
- 八、扭结
- 九、多面体
- 十、文字
- GUI 控制文件
- 总结
前言
大家好,这里是前端杂货铺。
上篇文章我们学习了 基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质。接下来,我们继续我们 three.js 的学习!
在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。
一、二维平面
PlaneBufferGeometry 一个用于生成平面几何体的类。相较于于 PlaneGeometry 更加轻量化。
new THREE.PlaneBufferGeometry(width : Float, height : Float, widthSegments : Integer, heightSegments : Integer)
| 参数名称 | 描述 |
|---|---|
| width | 平面沿着 X 轴的宽度。默认值是 1 |
| height | 平面沿着 Y 轴的高度。默认值是 1 |
| widthSegments | (可选)平面的宽度分段数,默认值是 1 |
| heightSegments | (可选)平面的高度分段数,默认值是 1 |
<!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 是欧式几何的一个简单形状,它由围绕着一个中心点的三角分段的数量所构造,由给定的半径来延展。 同时它也可以用于创建规则多边形,其分段数量取决于该规则多边形的边数。
new MeshDepthMaterial(parameters: Object);
| 参数名称 | 描述 |
|---|---|
| radius | 圆形的半径,默认值为1 |
| segments | 分段(三角面)的数量,最小值为3,默认值为 32 |
| thetaStart | 第一个分段的起始角度,默认为0 |
| thetaLength | 圆形扇区的中心角,通常被称为“θ”(西塔)。默认值是2*Pi,这使其成为一个完整的圆 |
<!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 一起使用,获取点,或者获取三角面。
new THREE.Shape( points : Array );
| 参数名称 | 描述 |
|---|---|
| points | 一个 Vector2 数组 |
ShapeGeometry 形状缓冲几何体,用于从一个或多个路径形状中创建一个单面多边形几何体。
new THREE.ShapeGeometry(shapes : Array, curveSegments : Integer)
| 参数名称 | 描述 |
|---|---|
| shapes | 一个单独的shape,或者一个包含形状的Array |
| curveSegments | 每一个形状的分段数,默认值为12 |
<!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” 参数来创建立方体或者不规则四边形。
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 |
<!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 是 一个用于生成球体的类。
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 |
<!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 是 一个用于生成圆柱几何体的类。
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,这使其成为一个完整的圆柱 |
<!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 是 一个用于生成圆环几何体的类。
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 |
<!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不互质,创建出来的几何体将是一个环面链接。。
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 |
<!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 多面体在三维空间中具有一些平面的立体图形。这个类将一个顶点数组投射到一个球面上,之后将它们细分为所需的细节级别。
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 | 将对这个几何体细分多少个级别。细节越多,形状就越平滑 |
<!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 父类中的设置所组成的参数来构造的。
// 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 |
<!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 补充完毕
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),},// 光照强度。默认值为 1intensity: {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/3angle: {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, // 不能为 undefinedradialSegments: 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】

相关文章:
Three.js——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字
个人简介 👀个人主页: 前端杂货铺 ⚡开源项目: rich-vue3 (基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL) 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 …...
24年湖南教资认定即将开始,别被照片卡审!
24年湖南教资认定即将开始,别被照片卡审!...
数据库(8)——DML数据操作
增添数据 给指定字段添加数据 INSERT INTO 表名 (字段名1,字段名2,...)VALUES(值1,值2...); 没有的添加的字段默认为NULL。 给全部字段添加数据 INSERT INTO 表名 VALUE (值1,值2,....值n); 此时值的顺序对应表中字段的顺序 批量添加数据 INSERT INTO 表名(字段1,…...
Gitee在已有项目基础上创建仓库中遇到的问题和解决
问题一:fatal: remote origin already exists 解释:当前仓库添加了一个名为"origin"的远程仓库配置,此时输入 git remote add origin https://xxx就会提示上面的内容。 解决方案1:移除旧的origin git remote remove origin 解决方案…...
【推荐算法-特征工程】每种item单侧特征,都可产生对应user单侧特征
比如item的平均成单价格,可以分成10个档位,作为一个标签值打在item上, 那么对应user对item的click用户行为,就能产生user-click的10个档位作为特征值 作为user的标签。 比如item的平均点击率,也可以分成比如20个档位…...
一行代码实现UI拖拽的效果
演示 先来看效果吧! 实现方式 1.首先创建一个你想拖动的UI图片 2.创建一个C#的脚本 3.编写控制脚本(代码按我的敲就行) 付上代码片段 public void OnDrag(PointerEventData eventData){transform.position eventData.position;} 4.添加脚…...
【Linux】TCP协议【下一】{三次握手/四次挥手的深度解读==状态变化}
文章目录 本篇知识需要有TCP协议【中】的知识!详情点击👇1.测试一:服务器start函数不定义任何行为(不调用accept)的三次握手状态变化int listen(int sockfd, int backlog);的backlog参数全连接队列当全连接队列已满&am…...
【C语言回顾】编译和链接
前言1. 编译2. 链接结语 上期回顾: 【C语言回顾】文件操作 个人主页:C_GUIQU 归属专栏:【C语言学习】 前言 各位小伙伴大家好!上期小编给大家讲解了C语言中的文件操作,接下来我们讲解一下编译和链接! 1. 编译 预处理…...
2024年5月27日 十二生肖 今日运势
小运播报:2024年5月27日,星期一,农历四月二十 (甲辰年己巳月辛卯日),法定工作日。 红榜生肖:羊、蛇、狗 需要注意:鼠、鸡、龙 喜神方位:西南方 财神方位:…...
【Text2SQL 论文】SeaD:使用 Schema-aware 去噪训练的 end2end 的 Text2SQL
论文:SeaD: End-to-end Text-to-SQL Generation with Schema-aware Denoising ⭐⭐ NAACL 2022, arXiv:2105.07911 本论文提出 SeaD 模型,使用 schema-aware 的去噪方法来训练一个 end2end、seq2seq 的 Transformer 模型来实现 Text2SQL。 一、论文速读…...
python数据分析——apply 1
参考资料:活用pandas库 apply是指把函数同时作用于DataFrame的每一行或每一列。类似于编写一些跨每行或每列的for循环,并同时调用apply函数。 1、函数 函数是对python代码进行分组和复用的一种方法。如果某段代码会被多次使用,并且使用时是需…...
Spring Boot 项目统一异常处理
在 Spring Boot 项目开发中,异常处理是一个非常重要的环节。良好的异常处理不仅能提高应用的健壮性,还能提升用户体验。本文将介绍如何在 Spring Boot 项目中实现统一异常处理。 统一异常处理有以下几个优点: 提高代码可维护性:…...
安卓手机APP开发__网络连接性支持VPN
安卓手机APP开发__网络连接性支持VPN 安卓提供了API给开发者,来创建一个虚拟的私有网络(VPN)的解决方案. 根据这里的介绍,你能知道如何开发和测试你的针对安卓设备的VPN的客户端. 概述 VPN允许设备为了安全地连接网络,而没有物理性的连接在一个网络上. 安卓包括了一个内嵌的…...
Shopee单个商品详情采集
Shopee商品详情页数据采集实战 作为东南亚地区最大的电商平台之一,Shopee拥有超过3亿活跃用户。对于跨境电商企业、市场分析师等角色而言,从Shopee获取商品数据是非常有价值的。本文将介绍如何使用Python程序采集Shopee单个商品详情页数据。 1. 确定采集目标和技术方案 确定…...
深入研究Qt Meta - Object System
目录 先说RTTI 再说QMeta Object System 关于Q_OBJECT 这篇文章我打算研究一下QMetaObject System,也就是Qt自己构建起来的元对象系统。 先说RTTI 啥是RTTI?这是C编程里的一个常见术语,全称是:运行阶段类型识别(Ru…...
web学习笔记(五十八)
目录 1. v-model 双向数据绑定 2. 事件修饰符 3. 路径别名 4. setup语法糖 4.1 语法糖的概念 4.2 setup语法糖 5. 配置代理服务器 1. v-model 双向数据绑定 v-model 双向数据绑定只能使用在表单标签; v-model双向数据绑定原理:采用 Object.de…...
精准安全运维,统信UOS服务器版V20(1070)漏洞修复指南丨年度更新
随着信息安全威胁的不断升级,操作系统的安全性已成为企业运维的关键要素。 为了确保业务运行环境的安全无忧,统信软件持续致力于技术创新和优化,并于日前重磅推出了统信UOS服务器版V20(1070)。该系统提供了高频补丁更…...
Vue3实战笔记(46)—Vue 3高效开发定制化Dashboard的权威手册
文章目录 前言Dashboard开发总结 前言 后台管理系统中的Dashboard是一种图形化的信息显示工具,通常用于提供一个特定领域或系统的概况。它可以帮助用户监控和分析数据,快速获取重要信息。可以帮助用户监控业务状况、分析数据、获取关键信息和管理资源。…...
MySQL为什么会选错索引
有的时候,我们加了索引,也不一定最终查询语句就能用上索引,因为Innodb要不要使用索引,该使用哪个索引是优化器决定的,它是根据成本(代价)预估来选择的,他会倾向于选择一个成本最低的…...
kafka调优参考建议 —— 筑梦之路
这里主要是从不同使用场景来调优,仅供参考。 吞吐量优先 吞吐量优先使用场景如采集日志。 1. broker配置调优 num.partitions:分区个数,设置为与消费者的线程数基本相等 2. producer配置调优 batch.size 批量提交消息的字节数,…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
GraphRAG优化新思路-开源的ROGRAG框架
目前的如微软开源的GraphRAG的工作流程都较为复杂,难以孤立地评估各个组件的贡献,传统的检索方法在处理复杂推理任务时可能不够有效,特别是在需要理解实体间关系或多跳知识的情况下。先说结论,看完后感觉这个框架性能上不会比Grap…...
深度解析:etcd 在 Milvus 向量数据库中的关键作用
目录 🚀 深度解析:etcd 在 Milvus 向量数据库中的关键作用 💡 什么是 etcd? 🧠 Milvus 架构简介 📦 etcd 在 Milvus 中的核心作用 🔧 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...
