You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js中带孔洞的拉伸模型旋转后如何填充孔洞并着色?

解决带孔洞3D模型的孔洞填充颜色问题

方法一:通过Group统一控制旋转(快速解决对齐问题)

你之前单独旋转几何体导致对齐失败,核心原因是几何体的旋转中心可能不一致。换个思路,不要直接修改几何体顶点,而是把主模型和孔洞填充模型放在同一个Group里,旋转整个Group——所有子物体会基于同一个中心点旋转,自然不会错位:

  1. 创建主形状和孔洞填充形状的拉伸几何体:
// 主形状(带孔洞)
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 });
  1. 在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提升性能,可以将主形状和填充形状合并为一个几何体,通过材质索引区分不同部分,用多材质渲染:

  1. 合并几何体并设置材质索引:
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]);
  1. 多材质渲染:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 09:51:12