尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【Three.js教程】 图元速查:官方内置的立体图形

【Three.js教程】 图元速查:官方内置的立体图形 Three.js 图元速查官方内置的立体图形原文出处Three.js Manual – Primitives本文基于 three.js 官方手册图元章节整理用通俗的方式带你过一遍 three.js 内置的所有 3D 基础形状。写在前面前面我们学会了搭场景、画立方体、画线、加文字。但光一个立方体显然不够玩——three.js 其实内置了一大堆开箱即用的 3D 形状官方把它们叫做Primitives图元。这篇就来做一个全面的速查把 three.js 里所有内置图元过一遍。以后做原型、做实验、或者临时需要一个形状 placeholder 的时候你知道该用哪个。一、什么是图元简单来说图元就是 three.js 用代码帮你实时生成的 3D 几何体。你给几个参数——比如半径、宽高、分段数——它就在内存里把顶点和三角面算出来变成一个可以直接拿来用的Geometry。这和从外部加载模型比如.gltf、.obj是不同的。图元的优势是快——不用等网络加载一行代码就出来一个球。适合做原型、数据可视化、或者一些程序化生成的场景。当然正经做项目的时候复杂模型还是得让美术用 Blender、Maya 这些工具来做。图元更多是够用就行。二、three.js 有哪些内置图元three.js 的内置图元还挺多的我们按类别来认基础形状图元是什么常用场景BoxGeometry长方体/立方体建筑块、容器、默认 placeholderSphereGeometry球体地球、星球、粒子球PlaneGeometry平面地面、墙面、2D 效果的载体CircleGeometry圆形平的圆盘、按钮底座、光圈RingGeometry圆环中间有洞呼啦圈、瞄准镜、UI 装饰柱状/锥状图元是什么常用场景CylinderGeometry圆柱体柱子、管道、杯子ConeGeometry圆锥体箭头、路障、圣诞树TubeGeometry沿路径扫出一个管状管道、线缆、弯曲的触手多面体图元是什么面数TetrahedronGeometry四面体4 面OctahedronGeometry八面体8 面DodecahedronGeometry十二面体12 面IcosahedronGeometry二十面体20 面这些多面体看起来像是几何知识点但在 制作3D 场景时还挺有用的——尤其是低面数的版本配合 flat shading平面着色会有一种复古的 low-poly 风格现在很多游戏和视觉设计都在用。复杂形状图元是什么常用场景TorusGeometry圆环体甜甜圈甜甜圈、传送门、装饰环TorusKnotGeometry环形结扭来扭去的甜甜圈炫酷的装饰物、数学可视化LatheGeometry旋转体把一条轮廓线绕轴旋转花瓶、酒杯、保龄球瓶、灯罩ExtrudeGeometry挤出几何体把 2D 形状拉成 3D自定义截面、文字挤出TextGeometry就是基于它ShapeGeometry2D 轮廓自动三角化平面 Logo、剪影ParametricGeometry参数化曲面用函数生成数学曲面、波浪、地形实验辅助几何体图元是什么作用EdgesGeometry提取另一个几何体的边缘线显示模型的线框轮廓过滤掉共面边WireframeGeometry把几何体转成线框格式生成适合LineSegments渲染的线框这两个不是形状而是形状的加工工具。比如你想看一个立方体的线框直接设wireframe: true会看到每个三角形的分割线而用EdgesGeometry可以只显示外轮廓更干净。三、怎么创建一个图元大部分图元的创建方式都差不多传几个尺寸参数拿到 geometry包上 material变成 Mesh塞进场景。以立方体为例constwidth8;constheight8;constdepth8;constgeometrynewTHREE.BoxGeometry(width,height,depth);constmaterialnewTHREE.MeshPhongMaterial({color:0x44aa88});constmeshnewTHREE.Mesh(geometry,material);scene.add(mesh);球体也是类似的套路constradius7;constwidthSegments12;// 水平方向分多少段constheightSegments8;// 垂直方向分多少段constgeometrynewTHREE.SphereGeometry(radius,widthSegments,heightSegments);每个图元的具体参数可以去 官方文档 查这里不一一列举了。重点是记住这个模式new THREE.XxxGeometry(参数...)→ 包 Material → 变 Mesh → 进场景。四、TextGeometry有点特殊TextGeometry比较特别它需要异步加载字体数据才能生成。不能像其他图元那样一行代码搞定。import{FontLoader}fromthree/addons/loaders/FontLoader.js;import{TextGeometry}fromthree/addons/geometries/TextGeometry.js;constloadernewFontLoader();loader.load(fonts/helvetiker_regular.typeface.json,function(font){constgeometrynewTextGeometry(Hello,{font:font,// 加载好的字体对象size:3,// 文字大小depth:0.2,// 挤出厚度curveSegments:12,// 曲线分段数bevelEnabled:true,// 是否倒角bevelThickness:0.15,bevelSize:0.3,bevelSegments:5,});constmaterialnewTHREE.MeshPhongMaterial({color:0x44aa88});constmeshnewTHREE.Mesh(geometry,material);scene.add(mesh);});注意这里是回调函数的形式因为字体加载是异步的。如果你用async/await也可以把它 promisifyfunctionloadFont(url){returnnewPromise((resolve,reject){loader.load(url,resolve,undefined,reject);});}asyncfunctioncreateText(){constfontawaitloadFont(fonts/helvetiker_regular.typeface.json);// ... 创建 TextGeometry}createText();还有一个坑默认生成的文字旋转中心在左边边缘。如果你想让文字绕着自己的中心旋转需要手动调整位置geometry.computeBoundingBox();// 计算包围盒geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1);这两行的意思是先算出文字几何体的中心点然后把 mesh 的位置往反方向挪同样的距离这样中心点就回到原点了。后面再做旋转就是绕中心转了。五、EdgesGeometry 和 WireframeGeometry看骨架有时候你想看看一个模型的骨架——比如调试的时候确认一下三角面长什么样。这时候可以用EdgesGeometry或WireframeGeometry。EdgesGeometry只看外轮廓constboxGeometrynewTHREE.BoxGeometry(8,8,8);constedgesGeometrynewTHREE.EdgesGeometry(boxGeometry);constedgesMaterialnewTHREE.LineBasicMaterial({color:0x000000});constedgesnewTHREE.LineSegments(edgesGeometry,edgesMaterial);scene.add(edges);EdgesGeometry很聪明它只显示夹角超过某个阈值的边。立方体的外轮廓线会保留但每个面上对角线分割成两个三角形的内部线会被过滤掉看起来更干净。WireframeGeometry所有边都显示constwireframeGeometrynewTHREE.WireframeGeometry(boxGeometry);constwireframenewTHREE.LineSegments(wireframeGeometry,edgesMaterial);scene.add(wireframe);WireframeGeometry会把几何体的每一条边都转成线段包括内部的三角形分割线。如果你想看模型的完整三角面结构用这个。注意这两个都要配合LineSegments来用而不是Mesh。六、Points只画点如果你不想画三角面只想在几何体的每个顶点位置画一个小点可以用PointsconstgeometrynewTHREE.SphereGeometry(7,12,8);constmaterialnewTHREE.PointsMaterial({color:red,size:0.2,// 点的大小世界单位});constpointsnewTHREE.Points(geometry,material);scene.add(points);效果就是一个由红点组成的球体轮廓有点像粒子系统的感觉。默认情况下点的大小会随距离变化——离相机越远看起来越小。如果你希望点的大小固定比如像素级固定可以关掉sizeAttenuationconstmaterialnewTHREE.PointsMaterial({color:red,size:3,// 像素单位sizeAttenuation:false,// 关闭透视衰减});七、分段数多一点还是少一点几乎每个图元都有分段数这个参数。比如SphereGeometry(radius, widthSegments, heightSegments)后两个就是控制球体分多少块的。分段数直接影响两件事视觉质量和性能。分段数低面数少性能好但看起来棱角分明分段数高面数多更圆润但更耗性能举个例子SphereGeometry(7, 5, 3)只有 30 个三角形看起来像多面体SphereGeometry(7, 24, 10)480 个三角形已经挺圆润了SphereGeometry(7, 50, 50)5000 个三角形非常光滑但这里有个反直觉的事实加了平滑着色smooth shading之后480 个三角形的球和 5000 个的球远看差别可能并没有那么大。如果你只画一两个球5000 面无所谓但如果你要画 1000 个球1000 × 5000 500 万个三角形每帧都要算浏览器就顶不住了。所以分段数没有绝对的标准答案看你的场景需求来定。原型阶段可以随便设上线前再根据实际情况优化。平面和盒子比较特殊——除非你要对它们做变形、扭曲、或者当作地形来修改顶点否则 2 个三角形的平面和 200 个的平面视觉上几乎没有区别。八、完整代码示例如果你想一次性把所有图元都摆出来看看效果可以用类似这样的结构constscenenewTHREE.Scene();scene.backgroundnewTHREE.Color(0xaaaaaa);constcameranewTHREE.PerspectiveCamera(40,2,0.1,1000);camera.position.z120;constrenderernewTHREE.WebGLRenderer();renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);// 辅助函数创建随机颜色的材质functioncreateMaterial(){constmaterialnewTHREE.MeshPhongMaterial({side:THREE.DoubleSide,// 双面渲染});consthueMath.random();material.color.setHSL(hue,1,0.5);returnmaterial;}// 辅助函数把物体摆到网格位置上constobjects[];constspread15;functionaddObject(x,y,obj){obj.position.xx*spread;obj.position.yy*spread;scene.add(obj);objects.push(obj);}functionaddSolidGeometry(x,y,geometry){constmeshnewTHREE.Mesh(geometry,createMaterial());addObject(x,y,mesh);}// 创建各种图元addSolidGeometry(-2,-2,newTHREE.BoxGeometry(8,8,8));addSolidGeometry(-1,-2,newTHREE.SphereGeometry(7,12,8));addSolidGeometry(0,-2,newTHREE.ConeGeometry(6,10,16));addSolidGeometry(1,-2,newTHREE.CylinderGeometry(4,4,10,16));addSolidGeometry(2,-2,newTHREE.TorusGeometry(5,2,8,24));// ... 更多图元// 渲染functionanimate(time){objects.forEach((obj,ndx){constspeed1ndx*0.1;constrottime*0.001*speed;obj.rotation.xrot;obj.rotation.yrot;});renderer.render(scene,camera);}renderer.setAnimationLoop(animate);这里有几个值得注意的点side: THREE.DoubleSide让材质双面渲染。像PlaneGeometry、ShapeGeometry这种没有厚度的 2D 形状如果不设双面从背面看会直接消失。每个图元给一个随机的 HSL 颜色摆成网格状方便对比。动画循环里让每个物体以不同速度旋转一眼就能看出哪个是哪个。回顾一下这篇我们过了一遍 three.js 的内置图元可以简单记住这几点图元是代码生成的 3D 形状适合 prototyping 和程序化场景复杂模型还是交给美术工具大部分图元的用法都一样new THREE.XxxGeometry(参数)→ Material → Mesh → 场景TextGeometry 是特例需要异步加载字体而且要注意旋转中心的问题EdgesGeometry / WireframeGeometry是辅助工具用来显示模型的线框结构Points可以在顶点位置画点适合做粒子效果或点云分段数要自己权衡质量和性能之间的取舍没有万能答案如果这些内置图元都不够你用后面还可以学怎么加载外部模型.obj、.gltf或者直接用BufferGeometry手写顶点数据创建完全自定义的形状。延伸阅读Three.js BoxGeometry 文档Three.js SphereGeometry 文档Three.js TextGeometry 文档Three.js BufferGeometry 文档
返回列表