threejs 实现3D游戏(11)—— 物体表面发光效果

1,734 阅读3分钟

概述

这是一个很常见需求,游戏场景中往往需要展现炫酷的霓虹灯,各种led灯,或需要光照渲染氛围的朦胧光效。

材质发光

three中的材质可分为自发光材质和不发光材质,发光材质即使在没有光的场景中依然清晰可见(需要设置发光的颜色如果是黑色依然不可见),而不发光材质在无光时是一片黑色。

react-three中常见的发光材质是MeshBasicMaterialMeshStandardMaterial

<mesh> 
    <boxGeometry args={[2, 2, 2]} /> 
    <meshBasicMaterial color="white" emissive="orange" emissiveIntensity={1} /> 
</mesh>

上面的代码实现了一个发出黄色光的白球,黄光强度是1。

image.png

在线示例

你也可以加载模型直接修改模型的发光效果和材质。

 const { scene, nodes } = useGLTF(path);
    useLayoutEffect(() => {
      scene.traverse((obj) => {
        if (obj instanceof Mesh) {
          obj.material.emissive = 'white'
          obj.material.emissiveIntensity=10
        }
      });
    }, [scene, map]);

光晕效果

<Billboard>组件:

  • Billboard@react-three/drei的组件 ,它可以将物体始终面向相机。这对实现发光效果很重要,我们不需要构建一个三维的发光体,只需要构建一个二维的发光体,让它一直朝着镜头。这样确保用户总能看到发光效果。

<LayerMaterial> 材质体:

  • LayerMaterial 是一种多层材质,通过叠加不同的 Depth 层来实现发光效果。这个材质设置了:
  • transparent: true:使材质具有透明效果。
  • depthWrite: false:禁止深度写入,这样材质不会影响深度缓冲,可以避免深度遮挡,确保发光效果在其他物体之前渲染。
  • 自定义 blending(混合模式):使用 THREE.CustomBlendingblendEquationblendSrcblendDst 设置来控制如何将每个层的颜色叠加在一起。这些设置确保不同层的颜色和透明度能混合在一起,产生柔和的发光效果。

<Depth>:

  • Depth 是一种可以实现深度渐变的材质,通常用于模拟光的散射效果。这里每个 Depth 层代表一种发光的深度效果,通过 colorAcolorB 控制颜色的渐变,alpha 控制透明度。
  • 每个 Depth 层的属性设置有所不同,组合起来可以产生分散的发光效果。
  • 参数解读:
    • colorAcolorB:用于控制发光颜色的渐变,例如从 colorAcolorB 的渐变,其中 colorB 被设置为黑色以营造出从明亮到暗淡的效果。
    • alpha:控制透明度,让光晕效果更柔和。
    • mode:混合模式,如 normaladd
    • nearfar:控制每一层的深度范围。不同层的 nearfar 设置产生不同的层次效果,使光晕看起来更自然
const Glow = ({ color, scale = 0.5, near = -2, far = 1.4 }) => (
  <Billboard>
    <mesh>
      <circleGeometry args={[2 * scale, 16]} />
      <LayerMaterial
        transparent
        depthWrite={false}
        blending={THREE.CustomBlending}
        blendEquation={THREE.AddEquation}
        blendSrc={THREE.SrcAlphaFactor}
        blendDst={THREE.DstAlphaFactor}>
        <Depth colorA={color} colorB="black" alpha={1} mode="normal" near={near * scale} far={far * scale} origin={[0, 0, 0]} />
        <Depth colorA={color} colorB="black" alpha={0.5} mode="add" near={-40 * scale} far={far * 1.2 * scale} origin={[0, 0, 0]} />
        <Depth colorA={color} colorB="black" alpha={1} mode="add" near={-15 * scale} far={far * 0.7 * scale} origin={[0, 0, 0]} />
        <Depth colorA={color} colorB="black" alpha={1} mode="add" near={-10 * scale} far={far * 0.68 * scale} origin={[0, 0, 0]} />
      </LayerMaterial>
    </mesh>
  </Billboard>
)

image.png

示例地址

点光源

在场景中添加一个点光源,它会照亮周围,它是不可见的但可以看到周围被照亮的物体。当它与后处理的光晕效果结合时表现力更强。

<pointLight ref={light} intensity={1} color={[10, 2, 5]} distance={2.5} />

screenshot_2024-11-15_15-24-47.png

在线示例

后处理

光晕效果

这应该是最简单的实现了,只需要添加上后处理效果的绽光组件Bloom就可以实现。 它会极大的加强光线的表现力,让光照更有层次,有晕染开的效果。

      <EffectComposer>
        <Bloom luminanceThreshold={2} mipmapBlur />
        <ToneMapping />
      </EffectComposer>

比起前面Billboard组件实现的Glow,它更加简单自然。但是性能消耗也大。

image.png

关于Bloom效果具体参数参见官方文档

上帝射线

顾名思义,上帝登场时一定从天际投射出一道光线照在他身上,以此来表现祂宗教上的神性。 GodRays组件从某个物体上投射出一道光线,可以设置其曝光程度,和衰减速率。

核心代码如下:

import { EffectComposer, GodRays } from '@react-three/postprocessing'

function Screen() {
  const [material, set] = useState()
  return (
    <>
      <Emitter ref={set} />
      {material && (
        <EffectComposer disableNormalPass multisampling={8}>
          <GodRays sun={material} exposure={0.34} decay={0.8} blur />
          <Bloom luminanceThreshold={0} mipmapBlur luminanceSmoothing={0.0} intensity={1} />
        </EffectComposer>
      )}
    </>
  )
}

image.png 在线测试地址