Introduction to my galaxy engine 7: Volumetric Light Scattering

花了一天时间,给引擎中添加了Volumetric Light Scattering模块.

视频地址:https://vimeo.com/43232452

截屏图如下:

Volumetric Light Scattering又名god light,Crepuscular Rays 等等, 也是一个游戏中比较常见的效果,主要是用post process来实现的。

具体实现步骤如下:

1.渲染发光体和场景,场景不添加材质,只显示成黑色,将结果渲染到render target 1上。

2. 只渲染场景,添加材质和光照,将结果渲染到render target 2上。

3. 对render target 1 做采样处理,计算光照。原理见如下图:

在屏幕上每一点到光源中心点做射线,对射线上点做采样。如果采样点被物体遮住,自然光照亮会减少。具体计算公式见GPU GERM 3相关那一张。最近处理结果如下图所示:

4. 最后一步,将render target 2的贴图附在上图上,就是最后的结果了。

完整代码如下:

  1 SamplerState g_samWrap
  2 {
  3     Filter = MIN_MAG_MIP_LINEAR;
  4     AddressU = Wrap;
  5     AddressV = Wrap;
  6 };
  7 
  8 SamplerState g_samClamp
  9 {
 10     Filter = MIN_MAG_MIP_LINEAR;
 11     AddressU = Clamp;
 12     AddressV = Clamp;
 13 };
 14 
 15 DepthStencilState DisableDepth
 16 {
 17     DepthEnable = FALSE;
 18     DepthWriteMask = ZERO;
 19 };
 20 
 21 DepthStencilState EnableDepth
 22 {
 23     DepthEnable = TRUE;
 24     DepthWriteMask = ALL;
 25     DepthFunc = Less_Equal;//set to less equal since texture background is ini as 1.0
 26 };
 27 
 28 BlendState NoBlending
 29 {
 30     AlphaToCoverageEnable = FALSE;
 31     BlendEnable[0] = FALSE;
 32 };
 33 
 34 BlendState AdditiveBlending
 35 {
 36     AlphaToCoverageEnable = FALSE;
 37     BlendEnable[0] = TRUE;
 38     SrcBlend = ONE;
 39     DestBlend = ONE;
 40     BlendOp = ADD;
 41     SrcBlendAlpha = SRC_ALPHA;
 42     DestBlendAlpha = INV_SRC_ALPHA;
 43     RenderTargetWriteMask[0] = 0x0F;
 44 };
 45 
 46 Texture2D  g_ModelTexture;
 47 
 48 Texture2D  g_BlackSceneTexture;
 49 Texture2D  g_NormalSceneTexture;
 50 
 51 matrix g_World;
 52 matrix g_View;
 53 matrix g_Projection;
 54 
 55 //float4 g_AmbientColor = float4(0.1f, 0.1f, 0.1f, 1.0f);
 56 float4 g_DirLightColor = float4(0.3f, 0.3f, 0.3f, 1.0f);
 57 float3 g_DirLightDir = float3(0.0f, 1.0f, -1.0f);
 58 
 59 float4 g_LightPos = float4(0.0f, 1.0f, 0.0f, 1.0f);
 60 uint NUM_SAMPLES = 200;
 61 float g_Density = 1.0f;
 62 float g_Weight = 1.0f;
 63 float g_Decay = 0.98f;
 64 float g_Exposure = 0.05f;
 65 
 66 bool g_bLight;
 67 
 68 struct VS_MODEL_INPUT
 69 {
 70     float4 Pos            : POSITION;         
 71     float2 Tex            : TEXCOORD0;     
 72     float3 Norm        : NORMAL;       
 73 };
 74 
 75 struct PS_MODEL_INPUT
 76 {
 77     float4 Pos            : SV_POSITION;   
 78     float2 Tex            : TEXCOORD0;     
 79     float3 Norm        : NORMAL;    
 80 };
 81 
 82 struct PS_MODEL_OUTPUT
 83 {
 84     float4 blackScene        : SV_Target0;
 85     float4 normalScene        : SV_Target1;
 86 };
 87 //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 88 struct VS_QUAD_INPUT
 89 {
 90     float4 Pos            : POSITION;           
 91     float2 Tex            : TEXCOORD0;       
 92 };
 93 
 94 struct PS_SCENE_INPUT
 95 {
 96     float4 Pos                        : SV_POSITION;   
 97     float2 Tex                        : TEXCOORD0;     
 98     float2 ScreenLightPos        : TEXCOORD1;  
 99 };
100 //---------------------------------------------------------------------------------------render black scene--------------------------------------------------------------------------------------------------------
101 PS_MODEL_INPUT VS_SCENE(VS_MODEL_INPUT input)
102 {
103     PS_MODEL_INPUT output = (PS_MODEL_INPUT)0;
104     output.Pos = input.Pos;
105     output.Pos.w = 1;
106 
107     output.Pos = mul( output.Pos, g_World );
108     output.Pos = mul( output.Pos, g_View );
109     output.Pos = mul( output.Pos, g_Projection );
110     output.Pos = output.Pos / output.Pos.w;
111 
112     output.Norm = input.Norm;
113     output.Tex = input.Tex;
114     return output;
115 }
116 
117 PS_MODEL_OUTPUT PS_BLACK_SCENE(PS_MODEL_INPUT input)
118 {
119     PS_MODEL_OUTPUT output = (PS_MODEL_OUTPUT)0;
120 
121     if(g_bLight)
122     {
123         output.blackScene = float4(1.0f, 1.0f, 1.0f, 1.0f);
124         output.normalScene = float4(0.0f, 0.0f, 0.0f, 0.0f);
125     }
126     else
127     {
128         output.blackScene = float4(0.0f, 0.0f, 0.0f, 1.0f);
129         output.normalScene = dot(normalize(g_DirLightDir), input.Norm) * g_DirLightColor * g_ModelTexture.Sample( g_samWrap, input.Tex );
130         output.normalScene.a = 1;
131     }
132 
133     return output;
134 }
135 
136 PS_SCENE_INPUT VS_VLS(VS_QUAD_INPUT input)
137 {
138     PS_SCENE_INPUT output = (PS_SCENE_INPUT)0;
139 
140     float2 Pos = input.Pos.xy;
141     output.Pos = float4(Pos.xy, 0, 1);
142     
143     output.Tex =  0.5 * (1 + Pos);
144 
145     float4 ScreenLightPos = g_LightPos;
146     ScreenLightPos = mul( ScreenLightPos, g_World );
147     ScreenLightPos = mul( ScreenLightPos, g_View );
148     ScreenLightPos = mul( ScreenLightPos, g_Projection );
149     ScreenLightPos = ScreenLightPos / ScreenLightPos.w;
150     ScreenLightPos = (ScreenLightPos + 1.0f) / 2.0f;
151     output.ScreenLightPos = ScreenLightPos;
152 
153     return output;
154 }
155 
156 float4 PS_VLS(PS_SCENE_INPUT input) : SV_Target
157 {
158     float2 texCoord = input.Tex;
159 
160     float2 deltaTexCoord = (texCoord - input.ScreenLightPos); 
161     deltaTexCoord *= 1.0f / NUM_SAMPLES * g_Density;
162 
163     float4 color = g_BlackSceneTexture.Sample(g_samClamp, float2(texCoord.x, 1 - texCoord.y));
164 
165     float illuminationDecay = 1.0f;
166 
167     for (uint i = 0; i < NUM_SAMPLES; i++)
168     {
169         texCoord -= deltaTexCoord;
170         float4 sampleColor = g_BlackSceneTexture.Sample(g_samClamp, float2(texCoord.x, 1 - texCoord.y));//shift y after operation
171         sampleColor *= illuminationDecay * g_Weight;
172         color += sampleColor;
173         illuminationDecay *= g_Decay;
174     }
175 
176     color *= g_Exposure;
177     color.a = 1;
178     return color;
179 }
180 
181 float4 PS_Blend(PS_SCENE_INPUT input) : SV_Target
182 {
183     float2 texCoord = input.Tex;
184     return g_NormalSceneTexture.Sample(g_samClamp, float2(texCoord.x, 1 - texCoord.y));
185 }
186 
187 technique10 RenderBlackScene
188 {
189     pass p0
190     {
191         SetVertexShader( CompileShader( vs_4_0, VS_SCENE() ) );
192         SetGeometryShader( NULL );
193         SetPixelShader( CompileShader( ps_4_0, PS_BLACK_SCENE() ) );
194 
195         SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
196     }  
197 }
198 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
199 technique10 VLS
200 {
201     pass p0
202     {
203         SetVertexShader( CompileShader( vs_4_0, VS_VLS() ) );
204         SetGeometryShader( NULL );
205         SetPixelShader( CompileShader( ps_4_0, PS_VLS() ) );
206 
207         SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
208     }  
209 }
210 
211 technique10 BlendScene
212 {
213     pass p0
214     {
215         SetVertexShader( CompileShader( vs_4_0, VS_VLS() ) );
216         SetGeometryShader( NULL );
217         SetPixelShader( CompileShader( ps_4_0, PS_Blend() ) );
218 
219         SetBlendState( AdditiveBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
220         SetDepthStencilState( EnableDepth, 0 );//set depth test to less_equal
221     }  
222 }

References:

[1] http://www.unrealcreations.com/groups/kb/wiki/7d174/Volumetric_Light_Scattering_Implementation.html

[2] http://developer.nvidia.com/node/170

[3] http://fabiensanglard.net/lightScattering/index.php

转载于:https://www.cnblogs.com/RobinG/archive/2012/06/01/2530527.html