Three.js向顶点着色器传递多个BufferGeometry数据的方法
多几何体顶点过渡的自定义着色器实现方案
核心逻辑:不需要将整个BufferGeometry作为uniform传入,WebGL 逐顶点数据的传递原生依赖**顶点属性(Attribute)**绑定缓冲区,Three.js 已经完整封装了这套能力,只要所有参与过渡的几何体顶点数量、顶点顺序完全对齐,直接把额外几何体的顶点数据作为自定义属性挂到渲染用的几何体上即可,性能和原生顶点读取一致。
Three.js 侧实现步骤
- 预处理所有参与过渡的几何体,保证顶点数、顶点索引顺序完全匹配。例如圆锥过渡到球体时,两个几何体的分段参数要调整到生成的顶点数一致,必要时对目标几何体顶点做顺序重映射,避免过渡时顶点错位跳变。
- 将额外几何体的所需顶点数据(位置、法线、UV等)作为自定义
BufferAttribute添加到实际用于渲染的几何体上,示例代码:
// 示例:以圆锥几何体为渲染基础,附加同顶点数球体的顶点数据 const baseConeGeo = new THREE.ConeGeometry(1, 2, 64, 1, false); const targetSphereGeo = new THREE.SphereGeometry(1, 64, 32); // 提取目标几何体的顶点、法线数据 const spherePosArray = targetSphereGeo.getAttribute('position').array; const sphereNormalArray = targetSphereGeo.getAttribute('normal').array; // 给基础几何体绑定自定义顶点属性 baseConeGeo.setAttribute('aTargetPos', new THREE.BufferAttribute(spherePosArray, 3)); baseConeGeo.setAttribute('aTargetNormal', new THREE.BufferAttribute(sphereNormalArray, 3)); // 若需要更多过渡形态(如立方体、圆环等),按相同规则追加自定义属性即可,例如aCubePos、aTorusPos // 最后用处理好的baseConeGeo创建Points/InstancedMesh/Mesh即可
- 给着色器传过渡控制参数,例如添加
uProgress的float类型uniform,取值范围0~1,控制从基础几何体到目标几何体的过渡进度。
顶点着色器读取方式
在自定义顶点着色器中,直接声明和自定义属性同名的attribute变量即可,和读取原生position、normal属性没有区别,示例代码:
// 原生基础几何体属性 attribute vec3 position; attribute vec3 normal; // 自定义的目标几何体属性 attribute vec3 aTargetPos; attribute vec3 aTargetNormal; // 过渡进度控制uniform uniform float uProgress; void main() { // 线性插值计算当前帧的顶点位置、法线 vec3 currentPos = mix(position, aTargetPos, uProgress); vec3 currentNormal = mix(normal, aTargetNormal, uProgress); // 后续按常规逻辑写坐标变换即可 gl_Position = projectionMatrix * modelViewMatrix * vec4(currentPos, 1.0); }
注意事项
- 不要尝试用uniform数组传递顶点数据:uniform是全局统一值,并非逐顶点绑定的GPU缓冲区,不仅性能差,WebGL对uniform数组长度还有严格上限,顶点数稍多就会触发超限错误。
- 顶点数对齐是必要前提:如果不同几何体顶点数不一致,这个方案不适用,需要改用纹理存储顶点数据+顶点ID采样的方案;你当前场景顶点数一致,用自定义Attribute是性能最高、实现成本最低的方案,底层逻辑和Three.js原生MorphTargets一致,只是插值逻辑完全由你自定义,灵活度更高。
- 用于
InstancedMesh时注意区分属性类型:上述逐顶点的几何体属性按普通BufferAttribute传入即可,如果是每个实例独立的参数(比如每个实例单独的过渡进度),才需要用InstancedBufferAttribute传递。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

