概述
让一个场景看起来真实需要很多算法,让场景的景深光照等效果贴近现实需要考虑各种复杂的情况,例如光照(光影、光晕、反射、折射、色调)、景深等等。
也许你听说过虚幻引擎的光追技术的实现,它让光照更真实。但多数时候我们需要考虑性能,让光反射一次(真实的光能反射无数次),已经是在效果和性能间追求平衡的一种最佳实践。
在threejs中我们只在完成了场景和功能后,才考虑进一步的后期处理。
后期处理会占用一定的性能,但它是为整个场景服务的。它让场景更真实更鲜活,更具有特定的氛围感。 但要知道,不可以因此而喧宾夺主,如果不加克制的滥用,很可能会导致严重性能问题。
three中的后处理库
在three中我们常用的后处理库是 postprocessing
,而适用于react-three-fiber
的后处理库是react-postprocessing
。
它仅仅是基于前者的基础上了做了react的封装,能更方便的在react-three-fiber
项目中实现各种后处理效果。react-postprocessing
简化了与 Three.js 后处理效果的集成,使得在 React 应用中使用后处理效果更加方便。
此库提供了一个 EffectPass,可自动组织和合并任何给定的效果组合。这可最大限度地减少渲染操作量,并可组合多种效果,而不会像传统 pass chain 那样影响性能。此外,每种效果都可以选择自己的混合函数。
所有全屏渲染操作也使用一个填充屏幕的三角形。与使用四边形相比,这种方法与现代 GPU 光栅化模式相协调,并消除了沿屏幕对角线的不必要片段计算。这对于使用复杂片段着色器的 GPGPU 通道和效果尤其有益。
安装命令
npm install @react-three/postprocessing
几种常用的后处理
抗锯齿(MSAA)
-
MSAA(Multi-Sample Anti-Aliasing):基于样本的抗锯齿方法,对每个像素进行多次采样。
-
FXAA(Fast Approximate Anti-Aliasing):基于图像的抗锯齿方法,通过检测和模糊边缘来减少锯齿。
-
TAA(Temporal Anti-Aliasing):时间抗锯齿方法,通过结合当前帧和前几帧的图像数据来减少锯齿。
react-postprocessing默认采用 MSAA(多重采样抗锯齿),你可以在 EffectComposer
上设置其采样数:multisampling
值为 2\4\8\16, 当将其设为0时即禁用 MSAA。
禁用它可能让边缘看起来粗糙,图像渲染质量下降,但会带来性能的提升,帧率提高。
子像素形态抗锯齿 (SMAA),当默认的MSAA出现问题或你想使用webgl1时,可以关闭MSAA 并使用 SMAA
关闭抗锯齿:
import { EffectComposer,SMAA} from '@react-three/postprocessing'
...
<EffectComposer multisampling={0}>
<SMAA>
</EffectComposer>
...
开启抗锯齿:
import { EffectComposer} from '@react-three/postprocessing'
...
<EffectComposer multisampling={16}>
</EffectComposer>
...
仔细观察水滴的边缘部位,在不开的情况下锯齿很明显,开启后可以看到有明显的改善。
光晕(Bloom)
<Bloom>
通过模拟光源发出的散射光来创建光晕。
该组件控制发光material上的光效。你必须关闭该材质的色调映射(toneMapped设为false),通常用于基础材质:meshStandardMaterial
和 meshBasicMaterial
,此外react-three/fiber
提供的其他发光材质组件 如:MeshDistortMaterial,MeshWobbleMaterial等等。
其基础属性如下:
luminanceThreshold
:亮度阈值,仅将亮度高于该值的部分会产生光晕 [0,1]luminanceSmoothing
:从亮度中心向周围产生光晕的平滑度 [0,1]height
:设置光晕效果的高度。通常用于调整效果的显示区域opacity
: 光晕效果的透明度,光晕的强度
使用示例:
...
<MeshDistortMaterial
...
/>
...
<EffectComposer multisampling={0} >
<Bloom
luminanceThreshold={0}
luminanceSmoothing={1}
height={300}
opacity={3}
/>
</EffectComposer>
...
这是我们设置光晕前:
设置光晕后:
- Bloom 是一种模拟光源光晕效果的后处理技术,使图像中的高亮区域产生柔和的光晕。
- 在
react-three-postprocessing
中,可以使用<Bloom>
组件来实现该效果,通过调整参数来控制光晕的强度和范围。 - 需要注意的是,Bloom 效果可能会影响性能,特别是在处理复杂场景时,要使用
luminanceThreshold
和luminanceSmoothing
参数来减少性能开销。 -在线示例
景深(DepthOfField)
在 react-postprocessing
中,DepthOfField
组件用于实现景深效果。
该效果模拟人眼的自然特性,眼睛焦点清晰,焦点范围外的物体则会变得模糊。这个效果可以用来引导观众的注意力,突出画面的特定部分,同时增加画面的深度感和真实感。
以下是一些关键参数:
focusDistance
:焦距距离,决定了哪个距离的物体是清晰的。值为 0 时焦点在最近处,值为 1 时焦点在最远处。focalLength
:焦距,决定了景深效果的强度。较小的值会使模糊效果更强。bokehScale
:散景比例,控制模糊区域中光斑的大小。较大的值会产生更大的光斑。height
:渲染高度,控制景深效果的分辨率。较高的值会有更高的细节,但也会增加性能消耗。
...
<EffectComposer
<DepthOfField
focusDistance={0}
focalLength={0.02}
bokehScale={2}
height={480}
/>
</EffectComposer>
...
景深启用前:
景深启用:
仔细观察,远处的小球已经模糊化了。
性能优化建议:
- 降低焦距距离(
focusDistance
)和焦距(focalLength
) :减少模糊计算强度,提高性能。 - 降低渲染高度(
height
) :减少景深效果的分辨率,显著提高性能,特别是在高分辨率场景中。 - 优化散景比例(
bokehScale
) :适当调整散景比例,避免过大的光斑导致性能瓶颈。 - 在线示例
晕影(Vignette)
游戏中经常使用这个效果,为了突出中心部分,整个画面会以屏幕为中心添加一个径向渐变:从屏幕的四角到中心由暗转亮的过渡效果,这种效果模仿了人眼观察的自然特性(视点中心清晰,四周模糊),可以增加视觉焦点和氛围感。
它的实现本身较为简单,仅仅是颜色渐变,性能开销可以忽略不计,理论上你使用一张png图片蒙在上面是一样的效果。
常用参数:
- eskil: 设置是否启用eskil模式,Eskil Steenberg使用指数渐变算法来更贴近自然界的晕影效果。
- offset:晕影的偏移,通常用于调整效果的范围。
- darkness:控制 晕影效果的强度,值越大,边缘越暗。
<EffectComposer multisampling={0}>
<Vignette eskil={false} offset={0.1} darkness={1.1} />
</EffectComposer>
启用前:
启用后:
光影(SSAO)
SSAO(屏幕空间环境光遮蔽,Screen Space Ambient Occlusion)是一种用于增强3D场景深度感和真实感的技术。它通过计算屏幕空间中每个像素的遮蔽程度来模拟环境光在复杂表面上的散射效果,从而在屏幕上生成阴影和暗角,增加视觉上的深度和细节。
个人实测:性能消耗极大,效果不明显,除非你的性能剩余太多,否则不推荐使用。
<EffectComposer>
<SSAO
samples={31}
radius={0.05}
intensity={20}
luminanceInfluence={0.7}
color="black"
/>
</EffectComposer>
关键参数:
samples
:每个像素的采样点数量。更多的采样点可以提高遮蔽计算的准确性,但也会增加计算开销。radius
:采样半径,决定了遮蔽效果的影响范围。较大的半径可以产生更宽泛的遮蔽效果,但可能导致性能下降。intensity
:遮蔽效果的强度。值越大,遮蔽效果越明显。luminanceInfluence
:环境光遮蔽对亮度的影响程度。较高的值会使遮蔽效果更多地影响亮度。bias
:用于避免自遮蔽的偏移量。适当的偏移可以防止像素被自己的几何体遮蔽。color
:环境光被遮蔽时的颜色。
环境光遮蔽启用前:
环境光遮蔽启用后:
初看,可能不明显,我们使用红色遮蔽光:
- SSAO 是一种计算环境光遮蔽效果的后处理技术,通过在屏幕空间计算遮蔽量来模拟光线衰减和阻挡。
- 在
react-postprocessing
中,可以使用<SSAO>
组件,并通过调整samples
、radius
、intensity
、luminanceInfluence
和bias
等参数来控制效果的细节和性能。 - 需要根据具体的场景和性能要求,调整参数以获得最佳的视觉效果和性能平衡。
- 在线示例
色调映射(ToneMapping)
色调映射(Tone Mapping)是一种图像处理技术,用于将高动态范围(HDR)图像转换为可在标准动态范围(SDR)显示器上显示的图像。其目的是压缩图像中的亮度范围,同时保留图像细节和对比度,从而使图像在低动态范围设备上看起来更自然和真实。
色调映射有多种算法,每种算法都有不同的参数和特性:
- Reinhard Tone Mapping:一种经典的全局色调映射方法,简单且效果较好。
- ACES (Academy Color Encoding System) :一种常用的色调映射标准,提供高质量的色彩转换。
- Filmic Tone Mapping:一种更复杂的色调映射方法,模拟电影胶片的效果。
它们都使用 exposure
:曝光参数,控制图像的整体亮度。
你可以在Canvas组件上的onCreated
事件中设置gl上的toneMapping
<Canvas
linear
mode="concurrent"
dpr={[1, 1.5]}
gl={{ antialias: false }}
camera={{ position: [0, 0, 2000], near: 0.01, far: 10000, fov }}
onCreated={({ gl, camera }) => {
actions.init(camera)
gl.toneMapping = THREE.ReinhardToneMapping
gl.setClearColor(new THREE.Color('#020209'))
}}>
噪点(Noise)
在 react-three-postprocessing
库中,Noise
组件用于在渲染后的图像中添加噪点效果(雪花点)。以下是 Noise
组件的常用属性:
opacity
: 噪声的透明度。控制噪声的强度,值越高,噪声效果越明显。通常为 1,即完全不透明。blendFunction
: 噪声图层的混合模式。控制噪声图层如何与底下的图像混合。常见有:BlendFunction.SCREEN
,BlendFunction.NORMAL
,BlendFunction.MULTIPLY
, 等。
import { BlendFunction } from "postprocessing";
...
<EffectComposer multisampling={0}>
<Noise opacity={0.025} blendFunction={BlendFunction.NORMAL} />
</EffectComposer>
...
效果:
有点黑泽明剑戟片的味了!
像素化(Pixelation)
Pixelation 是一种图像处理效果,用于模拟低分辨率显示器上的像素化效果。通过将图像的像素块化,可以产生复古的、马赛克风格的视觉效果。这种效果常用于创建特定的艺术风格、模拟旧游戏图像或突出某些视觉元素。
关键属性:
granularity
:控制像素化的大小。值越大,像素块越大,图像的像素化效果越明显。- 在线示例
<EffectComposer>
<Pixelation granularity={5} />
</EffectComposer>
效果:
小结
综合比较
给出以上后期处理效果的性能开销,方便处理可能的性能问题。
-
SSAO:最消耗性能,需要大量采样和计算。
- 适用场景:需要真实阴影效果的场景,尤其是那些需要突出物体间细节和深度的场景。
-
MSAA:抗锯齿效果对性能影响较大,特别是在高分辨率下。
- 适用场景:所有要求真实,和画面流畅平滑度和视觉质量的场景。
-
DepthOfField:景深效果对性能影响较大,尤其是在高分辨率和高强度模糊计算时。
- 适用场景:需要突出焦点或创建逼真摄影效果的场景,例如在游戏中强调某些对象或在电影风格的场景中使用。
-
Bloom:性能消耗中等,涉及多次模糊和亮度计算。
- 适用场景: 需要强调光源和光晕效果的场景,例如科幻或浪漫风格的视觉效果。
-
Noise: 低到中等。噪声效果通常比较轻量级,但可能会对性能产生一些影响,特别是当噪声强度较高时。
- 适用场景: 需要添加细节或模拟老旧摄影机效果的场景。
-
Pixelation:低到中等。像素化效果通常比较简单,但大像素块可能会导致一定的性能开销。
- 适用场景: 需要像素艺术风格或模拟旧款显示器的场景。
-
ToneMapping:性能消耗较低,但仍需根据场景和需求选择合适的算法和参数。
- 适用场景: 创建电影感的色彩和对比度,使画面更具视觉吸引力和艺术效果。
-
Vignette:性能消耗最小,仅需简单的颜色渐变处理。
- 适用场景: 需要引导观众注意力到画面中心或创建怀旧感的场景。
仅仅介绍了些常用的,和自己感兴趣的,受篇幅限制必然有很多没有介绍到。这是它的官方文档 ( react-postprocessing),你可以在这上面实验你感兴趣的后处理效果。
结语
劝君金屈栀,满酌不须辞。
花发多风雨,人生足别离。