React加载gltf多网格模型如何实现单个mesh悬停时独立变色
问题根源
你当前所有可交互mesh共用同一个全局hovered布尔状态,任意一个mesh触发悬停都会修改这个全局状态,而所有mesh的颜色都绑定了该状态,因此会出现全部同时变色的问题。
解决方案
有两种常用实现方式,按需选择即可:
方式1:全局记录当前悬停的mesh标识
把原来的布尔类型hovered状态修改为存储当前悬停mesh的唯一标识(这里直接用mesh的name属性即可),每个mesh单独判断自己是否为当前悬停的元素来设置颜色:
// 原代码 const [hovered, setHovered] = useState(false); 替换为下方代码 const [hoveredMesh, setHoveredMesh] = useState(null); // 原代码 useCursor(hovered); 替换为下方代码 useCursor(hoveredMesh !== null);
{/* 第一个mesh,name为react */} <mesh name='react' castShadow receiveShadow onClick={(e) => (e.stopPropagation(), setClicked(!clicked))} onPointerOver={(e) => ( e.stopPropagation(), setHoveredMesh('react') )} onPointerOut={(e) => ( e.stopPropagation(), setHoveredMesh(null) )} geometry={nodes.react.geometry} material={nodes.react.material} position={[0, 6.25, 6.77]} scale={[2.56, 0.87, 0.87]} > <meshStandardMaterial attach='material' color={hoveredMesh === 'react' ? 0xffb6ff : 0xff00ff} /> </mesh> {/* 第二个mesh,name为react01 */} <mesh name='react01' castShadow receiveShadow onClick={(e) => (e.stopPropagation(), setClicked(!clicked))} onPointerOver={(e) => ( e.stopPropagation(), setHoveredMesh('react01') )} onPointerOut={(e) => ( e.stopPropagation(), setHoveredMesh(null) )} geometry={nodes.react01.geometry} material={nodes.react01.material} position={[0, 4.5, 7.7]} scale={[2.56, 0.87, 0.87]} > <meshStandardMaterial attach='material' color={hoveredMesh === 'react01' ? 0xffb6ff : 0xff00ff} /> </mesh>
方式2:抽离可交互mesh为独立组件(更适合mesh数量多的场景)
把每个需要交互的mesh封装成单独的子组件,每个子组件内部维护自己的hover状态,完全独立互不干扰:
// 单独抽离的可交互Mesh组件 const InteractiveMesh = ({ node, name, position, scale, onClick }) => { const [hovered, setHovered] = useState(false); return ( <mesh name={name} castShadow receiveShadow onClick={(e) => { e.stopPropagation(); onClick(); }} onPointerOver={(e) => { e.stopPropagation(); setHovered(true); }} onPointerOut={(e) => { e.stopPropagation(); setHovered(false); }} geometry={node.geometry} material={node.material} position={position} scale={scale} > <meshStandardMaterial attach='material' color={hovered ? 0xffb6ff : 0xff00ff} /> </mesh> ) } // 父组件内调用示例 return ( {/* 其余原有代码保持不变 */} <InteractiveMesh node={nodes.react} name='react' position={[0, 6.25, 6.77]} scale={[2.56, 0.87, 0.87]} onClick={() => setClicked(!clicked)} /> <InteractiveMesh node={nodes.react01} name='react01' position={[0, 4.5, 7.7]} scale={[2.56, 0.87, 0.87]} onClick={() => setClicked(!clicked)} /> )
补充优化:原代码中控制动画启停的useEffect没有指定依赖数组,会导致每次组件渲染都重复执行,建议添加
[clicked, actions]作为依赖项,性能更优。
内容的提问来源于stack exchange,提问作者oORiggsOo
相关产品推荐
相关产品推荐

