Three.js中带孔洞的拉伸模型旋转后如何填充孔洞并着色?
解决带孔洞3D模型的孔洞填充颜色问题
方法一:通过Group统一控制旋转(快速解决对齐问题)
你之前单独旋转几何体导致对齐失败,核心原因是几何体的旋转中心可能不一致。换个思路,不要直接修改几何体顶点,而是把主模型和孔洞填充模型放在同一个Group里,旋转整个Group——所有子物体会基于同一个中心点旋转,自然不会错位:
- 创建主形状和孔洞填充形状的拉伸几何体:
// 主形状(带孔洞) const mainShape = new THREE.Shape(); mainShape.moveTo(...); mainShape.lineTo(...); const holePath = new THREE.Path(); holePath.moveTo(...); holePath.lineTo(...); mainShape.holes.push(holePath); const mainGeometry = new THREE.ExtrudeGeometry(mainShape, { depth: height }); // 孔洞填充形状(直接用和孔洞完全一致的坐标) const fillShape = new THREE.Shape(); fillShape.moveTo(...); // 和之前hole的坐标完全匹配 fillShape.lineTo(...); const fillGeometry = new THREE.ExtrudeGeometry(fillShape, { depth: height });
- 在react-three-fiber中构建Group并统一旋转:
import { useRef, useEffect } from 'react'; const ModelWithHoles = ({ axis, angle, height }) => { const groupRef = useRef(); useEffect(() => { if (groupRef.current) { // 旋转整个Group groupRef.current.quaternion.setFromAxisAngle(axis, angle); } }, [axis, angle]); return ( <group ref={groupRef}> {/* 主模型 */} <mesh geometry={mainGeometry}> <meshBasicMaterial color="red" side={THREE.FrontSide} /> </mesh> {/* 孔洞填充模型 */} <mesh geometry={fillGeometry}> <meshBasicMaterial color="blue" side={THREE.FrontSide} /> </mesh> </group> ); };
方法二:多材质单几何体(性能更优)
如果想减少Draw Call提升性能,可以将主形状和填充形状合并为一个几何体,通过材质索引区分不同部分,用多材质渲染:
- 合并几何体并设置材质索引:
import { BufferGeometryUtils } from 'three/addons/utils/BufferGeometryUtils.js'; // 主几何体(材质索引设为0) const mainGeometry = new THREE.ExtrudeGeometry(mainShape, { depth: height }); mainGeometry.setAttribute( 'materialIndex', new THREE.Uint16BufferAttribute(new Array(mainGeometry.attributes.position.count).fill(0), 1) ); // 填充几何体(材质索引设为1) const fillGeometry = new THREE.ExtrudeGeometry(fillShape, { depth: height }); fillGeometry.setAttribute( 'materialIndex', new THREE.Uint16BufferAttribute(new Array(fillGeometry.attributes.position.count).fill(1), 1) ); // 合并两个几何体 const mergedGeometry = BufferGeometryUtils.mergeGeometries([mainGeometry, fillGeometry]);
- 多材质渲染:
const MergedModel = ({ axis, angle }) => { const meshRef = useRef(); useEffect(() => { if (meshRef.current) { meshRef.current.quaternion.setFromAxisAngle(axis, angle); } }, [axis, angle]); return ( <mesh ref={meshRef} geometry={mergedGeometry}> <meshBasicMaterial color="red" side={THREE.FrontSide} /> <meshBasicMaterial color="blue" side={THREE.FrontSide} /> </mesh> ); };
关键注意事项
- 确保填充形状的坐标、拉伸depth参数和主形状的孔洞完全一致;
- 尽量避免直接修改几何体顶点(比如
applyQuaternion),优先通过父容器(Group/Mesh)控制变换,减少坐标计算错误。
内容的提问来源于stack exchange,提问作者TreeMage
相关产品推荐
相关产品推荐

