OpenMontage threejs-geometry 技能深度指南:Three.js 几何体创建、BufferGeometry 与实例化渲染实战
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
本篇指南以 OpenMontage 仓库中.agents/skills/threejs-geometry/SKILL.md为骨架,系统讲解 Three.js 几何体的完整技术栈:从内置几何体、路径型与文字几何体,到底层BufferGeometry自定义顶点数据、边线与点云、实例化渲染,再到几何合并与性能优化。结合仓库中tools/graphics/threejs_world.py与world-runtime.js的真实实现,读者将掌握在 Agent 驱动的 3D 世界生成、数据可视化与动画项目中高效创建、修改和渲染 3D 网格的完整实战方案。
快速上手:从几何体到可见网格
Three.js 中"几何体"(Geometry)描述的是物体的形状数据(顶点、法线、UV、索引),它本身不可见;只有当它与"材质"(Material)组合成"网格"(Mesh)并加入场景后才会被渲染。这是理解整个几何体体系的第一原则。
import * as THREE from "three"; // 内置几何体:直接传入尺寸参数即可创建 const box = new THREE.BoxGeometry(1, 1, 1); const sphere = new THREE.SphereGeometry(0.5, 32, 32); const plane = new THREE.PlaneGeometry(10, 10); // 创建网格:几何体 + 材质 const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const mesh = new THREE.Mesh(box, material); scene.add(mesh);仓库中tools/graphics/templates/threejs_world/world-runtime.js的buildLandmark函数即完全遵循这一模式——它通过addMesh辅助函数把BoxGeometry、CylinderGeometry、ConeGeometry、TorusGeometry、OctahedronGeometry与MeshStandardMaterial组合出 arch(拱门)、tower(塔)、ruin(废墟)、crystal(水晶)、settlement(聚落)、ring(环)等六类地标建筑,可见"几何体 + 材质 = 网格"是仓库所有 3D 产出的通用基石。
内置几何体全家桶
基础形状(Basic Shapes)
内置几何体构造函数的第一个参数通常是主要尺寸,随后是细分段数(segments)与角度区间参数。细分段数直接决定网格平滑度与顶点数量:
// BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) // 后三个分段参数用于增加顶点密度(如做形变目标时) new THREE.BoxGeometry(1, 1, 1, 1, 1, 1); // SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) // phi 是赤道方向角(绕 Y 轴),theta 是极方向角(从北极到南极) new THREE.SphereGeometry(1, 32, 32); // 完整球体(32×32 为质量与性能的良好折中) new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // 完整球体(显式写出全部角度) new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // 半球(phiLength = π,即赤道切一半) // PlaneGeometry(width, height, widthSegments, heightSegments) new THREE.PlaneGeometry(10, 10, 1, 1); // CircleGeometry(radius, segments, thetaStart, thetaLength) new THREE.CircleGeometry(1, 32); new THREE.CircleGeometry(1, 32, 0, Math.PI); // 半圆 // CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded) new THREE.CylinderGeometry(1, 1, 2, 32, 1, false); // 标准圆柱 new THREE.CylinderGeometry(0, 1, 2, 32); // 圆锥(radiusTop = 0) new THREE.CylinderGeometry(1, 1, 2, 6); // 六棱柱(radialSegments = 6) // ConeGeometry(radius, height, radialSegments, heightSegments, openEnded) new THREE.ConeGeometry(1, 2, 32, 1, false); // TorusGeometry(radius, tube, radialSegments, tubularSegments, arc) new THREE.TorusGeometry(1, 0.4, 16, 100); // TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q) // p、q 为纽结参数(如 2,3 是经典三叶纽结) new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3); // RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments) new THREE.RingGeometry(0.5, 1, 32, 1);仓库实战佐证:在world-runtime.js中,树木的树干使用CylinderGeometry(0.16, 0.23, 1.75, 6)(6 段径向细分形成低多边形树干),树冠使用ConeGeometry(0.92, 2.4, 7)(7 段形成棱锥状树冠),塔楼使用CylinderGeometry(0.52, 0.68, 2.4, 8),正是"通过径向段数控制多边形风格"的典型用法。
进阶形状(Advanced Shapes)
// CapsuleGeometry(radius, length, capSegments, radialSegments) // 胶囊体 = 圆柱体 + 两端半球帽,length 为中间圆柱段高度 new THREE.CapsuleGeometry(0.5, 1, 4, 8); // DodecahedronGeometry(radius, detail):正十二面体 new THREE.DodecahedronGeometry(1, 0); // IcosahedronGeometry(radius, detail):正二十面体 // detail = 0 时恰好 20 个三角面;detail 越大越接近球体(每次细分翻 4 倍面数) new THREE.IcosahedronGeometry(1, 0); new THREE.IcosahedronGeometry(1, 1); // 80 面,明显更圆滑 new THREE.IcosahedronGeometry(1, 2); // 320 面,接近低精度球体 // OctahedronGeometry(radius, detail):正八面体 new THREE.OctahedronGeometry(1, 0); // TetrahedronGeometry(radius, detail):正四面体 new THREE.TetrahedronGeometry(1, 0); // PolyhedronGeometry(vertices, indices, radius, detail):任意多面体 // vertices 为顶点坐标扁平数组(每 3 个浮点一个顶点),indices 为三角形索引 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]; new THREE.PolyhedronGeometry(vertices, indices, 1, 0);仓库实战佐证:world-runtime.js用DodecahedronGeometry(0.72, 0)作为岩石(粗糙多面体质感),用OctahedronGeometry(0.72, 0)作为水晶与晶簇,用OctahedronGeometry(0.32, 0)作为地标顶部的发光装饰。低 detail 多面体天然具备"硬朗、结晶、低多边形"的视觉语言,是环境散射中性价比极高的几何选择。
路径型形状(Path-Based Shapes)
// LatheGeometry(points[], segments, phiStart, phiLength):绕 Y 轴旋转二维轮廓生成三维体 // 适合花瓶、酒杯等旋转对称物体;points 必须从底部到顶部排列 const points = [ new THREE.Vector2(0, 0), new THREE.Vector2(0.5, 0), new THREE.Vector2(0.5, 1), new THREE.Vector2(0, 1), ]; new THREE.LatheGeometry(points, 32); // ExtrudeGeometry(shape, options):沿法线方向挤压 2D Shape const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(1, 0); shape.lineTo(1, 1); shape.lineTo(0, 1); shape.lineTo(0, 0); const extrudeSettings = { steps: 2, // 深度方向细分步数 depth: 1, // 挤压深度 bevelEnabled: true, // 是否启用倒角 bevelThickness: 0.1, // 倒角厚度(外扩量) bevelSize: 0.1, // 倒角尺寸(沿面方向) bevelSegments: 3, // 倒角圆滑段数 }; new THREE.ExtrudeGeometry(shape, extrudeSettings); // TubeGeometry(path, tubularSegments, radius, radialSegments, closed) // 沿任意曲线路径生成管道;path 需为 Curve 子类实例 const curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0), ]); new THREE.TubeGeometry(curve, 64, 0.2, 8, false);从源码结构看,world-runtime.js中的相机飞行路径(cameraAt函数)正是基于camera_path关键帧做 smoothstep 插值,若需要曲线化的镜头轨迹,TubeGeometry/CatmullRomCurve3同样可用于生成可视化的路径引导线,与仓库中threejs-world-generation技能体系一脉相承。
文字几何体(Text Geometry)
TextGeometry不在 Three.js 核心包中,需要从 examples 目录导入,且必须先异步加载字体 JSON(helvetiker_regular.typeface.json为经典默认字体):
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js"; import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js"; const loader = new FontLoader(); loader.load("fonts/helvetiker_regular.typeface.json", (font) => { const geometry = new TextGeometry("Hello", { font: font, // 必需:FontLoader 加载的字体对象 size: 1, // 字号 depth: 0.2, // 厚度(旧版本中该参数名为 'height',升级时需注意) curveSegments: 12, // 曲线(贝塞尔)细分段数,越大越圆滑 bevelEnabled: true, bevelThickness: 0.03, bevelSize: 0.02, bevelSegments: 5, }); // 居中:先计算包围盒再调用 center(),将几何体移动到原点 geometry.computeBoundingBox(); geometry.center(); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); });BufferGeometry:一切几何体的底层基座
Three.js r125 之后,所有内置几何体都继承自BufferGeometry——数据以**类型化数组(typed arrays)**存储,可直接上传 GPU,性能远优于旧版基于对象的 Geometry。理解BufferGeometry是自定义网格、顶点动画与大规模场景优化的必经之路。
自定义 BufferGeometry 的完整示例
const geometry = new THREE.BufferGeometry(); // 顶点(position):每个顶点 3 个浮点(x, y, z),共 4 个顶点组成一个四边形 const vertices = new Float32Array([ -1, -1, 0, // vertex 0 1, -1, 0, // vertex 1 1, 1, 0, // vertex 2 -1, 1, 0, // vertex 3 ]); geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3)); // 索引(index):索引化几何体,顶点可被多个三角形复用,显著降低内存 // 注意 Uint16Array 上限为 65535 个顶点,更大网格需用 Uint32Array const indices = new Uint16Array([ 0, 1, 2, // triangle 1 0, 2, 3, // triangle 2 ]); geometry.setIndex(new THREE.BufferAttribute(indices, 1)); // 法线(normal):光照计算必需,每个顶点 3 个浮点 const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3)); // UV(uv):纹理坐标,每个顶点 2 个浮点(u, v) const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]); geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2)); // 逐顶点颜色(color):需配合 material.vertexColors = true 才生效 const colors = new Float32Array([ 1, 0, 0, // red 0, 1, 0, // green 0, 0, 1, // blue 1, 1, 0, // yellow ]); geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3)); // Use with: material.vertexColors = trueBufferAttribute 的类型与 itemSize 速查
BufferAttribute的第二个参数itemSize声明"每个顶点占用几个浮点",决定 GPU 如何解析数组:
new THREE.BufferAttribute(array, itemSize); // 类型化数组选型 new Float32Array(count * itemSize); // 顶点、法线、UV(浮点精度) new Uint16Array(count); // 索引(顶点数 ≤ 65535) new Uint32Array(count); // 索引(更大网格,WebGL2 必需) new Uint8Array(count * itemSize); // 颜色(0-255 整数范围,内存减半) // 各属性 itemSize 速查 // position: 3 (x, y, z) // normal: 3 (x, y, z) // uv: 2 (u, v) // color: 3 (r, g, b) 或 4 (r, g, b, a) // index: 1仓库实战佐证:world-runtime.js生成地形时正是手动构造BufferGeometry——先new THREE.PlaneGeometry(size, size, resolution, resolution)获取顶点缓冲,然后遍历position属性,用position.getX(index)/position.getZ(index)读取坐标、position.setY(index, heightAt(x, z))写入程序化高度场,最后以Float32Array构造"color"属性做逐顶点区域混色。这一套"读顶点 → 改写 → 设置新属性"的流程,正是本文档BufferGeometry章节的教科书级应用。
运行时修改 BufferGeometry
const positions = geometry.attributes.position; // 修改单个顶点 positions.setXYZ(index, x, y, z); // 读取顶点 const x = positions.getX(index); const y = positions.getY(index); const z = positions.getZ(index); // 关键:修改后必须置 needsUpdate = true,GPU 才会重新上传数据 positions.needsUpdate = true; // 位置变化后重新计算法线(否则光照会失真) geometry.computeVertexNormals(); // 重新计算包围盒与包围球(影响视锥剔除与 Raycaster 精度) geometry.computeBoundingBox(); geometry.computeBoundingSphere();交错缓冲(InterleavedBuffer,进阶)
将位置与 UV 等属性打包进同一个数组(stride 为每顶点总浮点数),通过 offset 指定各属性起点。缓存更连续,对大网格有内存与带宽收益:
const interleavedBuffer = new THREE.InterleavedBuffer( new Float32Array([ // pos.x, pos.y, pos.z, uv.u, uv.v(每个顶点 5 个浮点) -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1, ]), 5, // stride:每顶点浮点数 ); geometry.setAttribute("position", new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0)); // size 3, offset 0 geometry.setAttribute("uv", new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3)); // size 2, offset 3EdgesGeometry 与 WireframeGeometry:轮廓与线框
两者都用于可视化几何体结构,但语义不同:
// EdgesGeometry:只提取"硬边"(相邻面夹角超过阈值的边),适合描边风格 const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = 阈值角度(度) const edgeMesh = new THREE.LineSegments( edges, new THREE.LineBasicMaterial({ color: 0xffffff }), ); // WireframeGeometry:所有三角形的全部边,形成完整线框 const wireframe = new THREE.WireframeGeometry(boxGeometry); const wireMesh = new THREE.LineSegments( wireframe, new THREE.LineBasicMaterial({ color: 0xffffff }), );仓库实战佐证:threejs_world工具定义了render_mode的三种枚举值cinematic / semantic / wireframe(见tools/graphics/threejs_world.py中_RENDER_MODES),其中 wireframe 模式在world-runtime.js中通过MeshBasicMaterial({ wireframe: true })实现,其核心目的正是几何结构诊断——_report中diagnostic_passes明确写道"wireframe": "explicit terrain and asset geometry pass"。这说明线框渲染不是装饰,而是生产流程中验证地形拓扑与资产接触关系的必备调试手段。
Points:点云渲染
Points将每个顶点渲染为屏幕上的一个点,适合粒子、星云、散点图等无需三角面的效果。关键属性是sizeAttenuation——控制点大小是否随距离衰减:
const geometry = new THREE.BufferGeometry(); const positions = new Float32Array(1000 * 3); for (let i = 0; i < 1000; i++) { positions[i * 3] = (Math.random() - 0.5) * 10; positions[i * 3 + 1] = (Math.random() - 0.5) * 10; positions[i * 3 + 2] = (Math.random() - 0.5) * 10; } geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3)); const material = new THREE.PointsMaterial({ size: 0.1, sizeAttenuation: true, // 点大小随距离减小(远小近大,更具空间感) color: 0xffffff, }); const points = new THREE.Points(geometry, material); scene.add(points);Lines:线几何体三兄弟
// Line:按顺序连接所有点(折线) const points = [ new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0), ]; const geometry = new THREE.BufferGeometry().setFromPoints(points); const line = new THREE.Line( geometry, new THREE.LineBasicMaterial({ color: 0xff0000 }), ); // LineLoop:首尾闭合的环 const loop = new THREE.LineLoop(geometry, material); // LineSegments:每 2 个点为一对独立线段(不连续),适合网格线、坐标系轴 const segmentsGeometry = new THREE.BufferGeometry(); segmentsGeometry.setAttribute( "position", new THREE.BufferAttribute( new Float32Array([ -1, 0, 0, 0, 1, 0, // segment 1 0, 1, 0, 1, 0, 0, // segment 2 ]), 3, ), ); const segments = new THREE.LineSegments(segmentsGeometry, material);InstancedMesh:批量渲染同一几何体
当场景中有成百上千个相同几何体(树木、岩石、粒子)时,逐个创建 Mesh 会产生海量 draw call。InstancedMesh用一个几何体 + 一份材质 + 一个矩阵数组,一次 draw call 渲染全部实例,是环境散射与群集渲染的行业标准方案:
const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const count = 1000; const instancedMesh = new THREE.InstancedMesh(geometry, material, count); // 用临时 Object3D 组装每个实例的变换矩阵 const dummy = new THREE.Object3D(); const matrix = new THREE.Matrix4(); for (let i = 0; i < count; i++) { dummy.position.set( (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, ); dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0); dummy.scale.setScalar(0.5 + Math.random()); dummy.updateMatrix(); // 把 position/rotation/scale 合成矩阵 instancedMesh.setMatrixAt(i, dummy.matrix); } // 关键:批量写入后标记 GPU 更新 instancedMesh.instanceMatrix.needsUpdate = true; // 可选:逐实例颜色(需要额外实例颜色缓冲) instancedMesh.instanceColor = new THREE.InstancedBufferAttribute( new Float32Array(count * 3), 3, ); for (let i = 0; i < count; i++) { instancedMesh.setColorAt( i, new THREE.Color(Math.random(), Math.random(), Math.random()), ); } instancedMesh.instanceColor.needsUpdate = true; scene.add(instancedMesh);运行时更新单个实例与拾取
// 更新单个实例:先取出矩阵,修改后再写回并标记 const matrix = new THREE.Matrix4(); instancedMesh.getMatrixAt(index, matrix); // Modify matrix... instancedMesh.setMatrixAt(index, matrix); instancedMesh.instanceMatrix.needsUpdate = true; // 射线拾取:Raycaster 命中后通过 instanceId 定位具体实例 const intersects = raycaster.intersectObject(instancedMesh); if (intersects.length > 0) { const instanceId = intersects[0].instanceId; }仓库实战佐证:world-runtime.js的makeInstanced函数完整复刻了这一模式——它把scatterPoints计算出的每个散布点通过dummy.updateMatrix()写入InstancedMesh,并mesh.instanceMatrix.needsUpdate = true,用于岩石、树木(树干 + 树冠两组实例)与水晶的批量散布。threejs_world工具的_report中environment_instances统计项正是对这类实例数量的汇总,其输入约束将单区域散射上限设为 1200(见_normalize_spec中scatter的 clamp 范围),确保实例化渲染始终在可控的 GPU 预算内。
InstancedBufferGeometry:超越变换与颜色的自定义实例属性(进阶)
InstancedBufferGeometry允许为每个实例声明任意自定义属性(如偏移、速度、自定义尺寸),需配合自定义 Shader 使用:
const geometry = new THREE.InstancedBufferGeometry(); geometry.copy(new THREE.BoxGeometry(1, 1, 1)); // 添加逐实例属性:每个实例 3 个浮点偏移量 const offsets = new Float32Array(count * 3); for (let i = 0; i < count; i++) { offsets[i * 3] = Math.random() * 10; offsets[i * 3 + 1] = Math.random() * 10; offsets[i * 3 + 2] = Math.random() * 10; } geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3)); // 在 Shader 中使用: // attribute vec3 offset; // vec3 transformed = position + offset;几何体工具集(BufferGeometryUtils)
BufferGeometryUtils是官方 examples 提供的工具模块,用于合并、清洗与优化几何体:
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js"; // 合并多个几何体(要求所有几何体拥有相同的属性集合;不同则需先补齐) const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]); // 合并并保留 groups(用于多材质 Mesh:[material1, material2]) const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true); // 计算切线(法线贴图渲染的必需预处理) BufferGeometryUtils.computeTangents(geometry); // 交错化属性:把 position/normal/uv 打包为 InterleavedBuffer,提升缓存局部性 const interleaved = BufferGeometryUtils.interleaveAttributes([ geometry.attributes.position, geometry.attributes.normal, geometry.attributes.uv, ]);高频实用模式
居中几何体
geometry.computeBoundingBox(); geometry.center(); // 平移顶点使包围盒中心落在原点等比缩放到单位尺寸
geometry.computeBoundingBox(); const size = new THREE.Vector3(); geometry.boundingBox.getSize(size); const maxDim = Math.max(size.x, size.y, size.z); geometry.scale(1 / maxDim, 1 / maxDim, 1 / maxDim); // 最长边缩放到 1克隆并变换
const clone = geometry.clone(); clone.rotateX(Math.PI / 2); clone.translate(0, 1, 0); clone.scale(2, 2, 2);形变目标(Morph Targets)
Morph 目标允许 GPU 在多个顶点姿态间平滑插值,常用于表情动画、呼吸起伏等低成本形变。几何体的每个 morph 目标需要与基础几何体顶点数完全一致:
// 基础几何体:分段数 4×4×4,提供足够的顶点密度 const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4); // 创建形变目标:复制 position 数组后修改 const morphPositions = geometry.attributes.position.array.slice(); for (let i = 0; i < morphPositions.length; i += 3) { morphPositions[i] *= 2; // 拉伸 X morphPositions[i + 1] *= 0.5; // 压扁 Y } geometry.morphAttributes.position = [ new THREE.BufferAttribute(new Float32Array(morphPositions), 3), ]; const mesh = new THREE.Mesh(geometry, material); mesh.morphTargetInfluences[0] = 0.5; // 50% 混合,介于基础形态与目标形态之间性能优化清单
- 优先使用索引化几何体:
setIndex复用顶点,内存与顶点着色器负载双降; - 合并静态网格:场景中不再移动的物体用
mergeGeometries合并,减少 draw call; - 大量重复对象用 InstancedMesh:千级实例仅需一次 draw call;
- 按需选择细分段数:段数越多越平滑,但顶点数与填充率成本同步上升;
- 及时释放资源:
geometry.dispose()让 GPU 释放缓冲,避免内存泄漏。
// 常见细分段数参考(以球体为例) new THREE.SphereGeometry(1, 32, 32); // 良好质量(默认推荐) new THREE.SphereGeometry(1, 64, 64); // 高质量(近景特写) new THREE.SphereGeometry(1, 16, 16); // 性能模式(远景/批量) // 用完后释放 geometry.dispose();在 OpenMontage 中如何实战这套几何体技能
本技能文档隶属于 OpenMontage 的 Agent 技能体系(.agents/skills/下与threejs-fundamentals、threejs-materials、threejs-shaders、threejs-lighting、threejs-interaction等组成完整的 Three.js 技能栈),其上层入口是skills/creative/3d-world-generation.md描述的三维世界生成能力。仓库中的实际落地路径为:
- 能力路由:Agent 通过
threejs_world工具(tools/graphics/threejs_world.py)执行operation: build,将结构化world_spec(世界尺寸、地形分辨率、区域、地标、相机路径)标准化并校验; - 工作区产出:工具会把模板目录(tools/graphics/templates/threejs_world/world-runtime.js、
index.html、world.css)与规格 JSON(world.json、world-spec.js)物化为可编辑的 Three.js 工作区; - 几何体落地:运行时模板使用本文介绍的内置几何体(
PlaneGeometry地形、CylinderGeometry/ConeGeometry树木、DodecahedronGeometry岩石、OctahedronGeometry水晶、BoxGeometry/TorusGeometry地标)、BufferGeometry逐顶点高度场、逐顶点颜色与InstancedMesh环境散射; - 质量验证:测试套件 tests/tools/test_threejs_world.py 通过
operation: validate断言terrain_triangles、region_count等统计项,并验证两次build产出哈希一致(Determinism.SEEDED确定性输出),确保几何体生成可复现、可回归。
这种"技能文档定义能力 → 工具执行产出 → 模板运行时消费几何体 → 测试锁定契约"的四层结构,正是 OpenMontage 将 Three.js 几何体知识工程化、让 AI 编码助手可直接复用的完整闭环。
相关技能导航
threejs-fundamentals(.agents/skills/threejs-fundamentals/SKILL.md):场景搭建、相机、渲染器与 Object3D 层次结构;threejs-materials(.agents/skills/threejs-materials/SKILL.md):网格材质选型与属性;threejs-shaders(.agents/skills/threejs-shaders/SKILL.md):自定义顶点与片元着色器操作。
掌握本文的几何体创建与优化手段后,即可顺畅衔接上述技能,从"能画出形状"进阶到"能用 1000 个实例填满整个三维世界"。
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考