## Post-FX Stack 为了效率跳过。 `void Draw(RenderTargetIdentifier from,RenderTargetIdentifier to,Pass pass)` ![](https://pic2.zhimg.com/80/v2-9e0c020362ba48d9652de9507acd876d_720w.jpg) to代表绘制的RT id,通过`buffer.SetRenderTarget()`来设置。from为原始渲染结果,使用`buffer.SetGlobalTexture()`来向Shader传递贴图资源。 ## Bloom 对图像进行双线性采样,以生成分辨率不断对半分的Bloom金字塔。 ![](https://pic1.zhimg.com/80/v2-263834811ad5f64ae6674ebaae360bc8_720w.jpg) 给`_BloomPyramid1`~`_BloomPyramid16`传递id。 ![](https://pic1.zhimg.com/80/v2-a2dfea38523980ad31c5e656a181735c_720w.jpg) 创建一个DoBloom方法。首先将摄像机的像素宽度和高度减半,然后选择默认的渲染纹理格式。最初,我们将从源复制到金字塔中的第一个纹理。追踪那些标识符。 ![](https://pic4.zhimg.com/80/v2-8946f3551e373b2a5cc399a360c1e34b_720w.jpg) ## OnBloom 循环整个级别的贴图,并调用`Draw()`绘制,之后计算后一级别的贴图的数据准备下一次循环,直到循环完成或者贴图分辨为1*1时候。 ### Draw ```c# void Draw ( RenderTargetIdentifier from, RenderTargetIdentifier to, Pass pass ) { buffer.SetGlobalTexture(fxSourceId, from); buffer.SetRenderTarget( to, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store ); buffer.DrawProcedural( Matrix4x4.identity, settings.Material, (int)pass, MeshTopology.Triangles, 3 ); } ``` ## ```c# Pass { BloomCombine, BloomHorizontal, BloomPrefilter, BloomVertical, Copy } ``` Bloom循环的主要内逻辑为: 1. copy之前的渲染结果。 2. 进行一次预处理。 3. 取得2个RT,首先进行水平高斯模糊,之后进行垂直高斯模糊。因为水平模糊已经进行一次采样,所以垂直采样的次数可以减半了。 4. 释放中间产生水平高斯的RT。 5. 进行反向叠加产生结果循环。(垂直高斯模糊后的结果) 6. 释放垂直高斯的RT。 ## 预处理 Bloom通常在艺术上用于仅使某些东西发光,但是我们的效果目前适用于所有对象,不管它有多亮。尽管从物理上讲没有意义,但是我们可以通过引入亮度阈值来限制影响效果的因素。实际上就是提取亮度高的区域。 c# DoBloom(): ```c# Vector4 threshold; threshold.x = Mathf.GammaToLinearSpace(bloom.threshold); threshold.y = threshold.x * bloom.thresholdKnee; threshold.z = 2f * threshold.y; threshold.w = 0.25f / (threshold.y + 0.00001f); threshold.y -= threshold.x; buffer.SetGlobalVector(bloomThresholdId, threshold); ``` Shader: ```c# float3 ApplyBloomThreshold (float3 color) { float brightness = Max3(color.r, color.g, color.b); float soft = brightness + _BloomThreshold.y; soft = clamp(soft, 0.0, _BloomThreshold.z); soft = soft * soft * _BloomThreshold.w; float contribution = max(soft, brightness - _BloomThreshold.x); contribution /= max(brightness, 0.00001); return color * contribution; } float4 BloomPrefilterPassFragment (Varyings input) : SV_TARGET { float3 color = ApplyBloomThreshold(GetSource(input.fxUV).rgb); return float4(color, 1.0); } ``` ## 解决白色辉光显得块状化问题 使用在Core RP Library的Filtering include文件中定义的SampleTexture2DBicubic函数。 ```c# #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Filtering.hlsl" float4 GetSourceBicubic (float2 fxUV) { return SampleTexture2DBicubic( TEXTURE2D_ARGS(_PostFXSource, sampler_linear_clamp), fxUV, _PostFXSource_TexelSize.zwxy, 1.0, 0.0 ); } ``` 之后再合并结果的时候对低分辨的贴图使用该函数进行采样。在案例中被设置为可开启项。 ## 强制控制 在`BloomCombinePassFragment`中的给低分辨率结果乘以强度之后在于高分辨率结果叠加。