React Three Fiber:如何仅高亮对象数组中选中的模型
React Three Fiber 单模型高亮解决方案
核心问题分析
你当前的实现思路错误在于:postprocessing的enabled属性是控制整个效果的全局开关,无法实现局部模型过滤。要仅高亮选中模型,必须通过掩码渲染分层或模型材质动态修改两种方式实现。
方案一:基于MaskPass的后期处理高亮(推荐)
利用Three.js的掩码通道,仅对选中模型区域应用高亮效果:
1. 给模型标记选中状态与图层
确保每个模型有唯一ID,绑定选中事件并设置专属图层:
import { cloneElement } from 'react'; import { useStore } from './your-zustand-store'; function ModelRenderer() { const { activeModules, selectedModule, setSelectedModule } = useStore(); return ( <> {activeModules.map((module) => { const isSelected = selectedModule?.id === module.id; return cloneElement(module.jsx, { // 选中模型放到图层1,其余在默认图层0 layers: isSelected ? 1 : 0, // 绑定交互事件 onPointerOver: () => setSelectedModule(module), onContextMenu: (e) => { e.preventDefault(); setSelectedModule(module); }, }); })} </> ); }
2. 配置EffectComposer的分层渲染通道
import { useThree, useFrame } from '@react-three/fiber'; import { EffectComposer, RenderPass, MaskPass, ClearMaskPass, UnrealBloomPass } from 'postprocessing'; import { useRef, useEffect } from 'react'; import { useStore } from './your-zustand-store'; function CustomPostProcessing() { const { gl, scene, camera } = useThree(); const composer = useRef(null); const { selectedModule } = useStore(); useEffect(() => { // 初始化 composer composer.current = new EffectComposer(gl); // 第一步:渲染背景和非选中模型(默认图层0) const baseRenderPass = new RenderPass(scene, camera); composer.current.addPass(baseRenderPass); if (selectedModule) { // 第二步:设置掩码,仅渲染选中模型(图层1) camera.layers.set(1); const maskPass = new MaskPass(scene, camera); composer.current.addPass(maskPass); camera.layers.set(0); // 切回默认图层 // 第三步:对掩码区域应用高亮效果(可替换为其他高亮效果) const bloomPass = new UnrealBloomPass(); bloomPass.strength = 1.8; bloomPass.radius = 0.5; composer.current.addPass(bloomPass); // 第四步:清除掩码,恢复全局渲染 composer.current.addPass(new ClearMaskPass()); } // 清理资源 return () => composer.current?.dispose(); }, [gl, scene, camera, selectedModule]); // 替换默认渲染流程 useFrame((_, delta) => composer.current?.render(delta), 1); return null; }
方案二:动态修改模型材质实现高亮
如果后期处理配置复杂,可直接给选中模型修改材质属性:
{activeModules.map((module) => { const isSelected = selectedModule?.id === module.id; return cloneElement(module.jsx, { // 保留原材质的同时添加 emissive 高亮效果 onBeforeRender: (_, mesh) => { if (isSelected) { mesh.material.emissive.set(0xffff00); // 黄色高亮 mesh.material.emissiveIntensity = 0.8; } else { mesh.material.emissive.set(0x000000); mesh.material.emissiveIntensity = 0; } }, }); })}
排查要点
- 检查
selectedModule.id与模型ID的类型是否一致(避免字符串和数字混用) - 用MaskPass方案时,确保相机图层切换正确,否则掩码区域为空
- 若使用postprocessing库,确认版本与R3F兼容(建议用
postprocessing@6.x系列)
内容的提问来源于stack exchange,提问作者Rix11
相关产品推荐
相关产品推荐

