103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								## Post-FX Stack 
							 | 
						|||
| 
								 | 
							
								为了效率跳过。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								`void Draw(RenderTargetIdentifier from,RenderTargetIdentifier to,Pass pass)`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								to代表绘制的RT id,通过`buffer.SetRenderTarget()`来设置。from为原始渲染结果,使用`buffer.SetGlobalTexture()`来向Shader传递贴图资源。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## Bloom
							 | 
						|||
| 
								 | 
							
								对图像进行双线性采样,以生成分辨率不断对半分的Bloom金字塔。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								给`_BloomPyramid1`~`_BloomPyramid16`传递id。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								创建一个DoBloom方法。首先将摄像机的像素宽度和高度减半,然后选择默认的渲染纹理格式。最初,我们将从源复制到金字塔中的第一个纹理。追踪那些标识符。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 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`中的给低分辨率结果乘以强度之后在于高分辨率结果叠加。
							 |