Browse Source

Cleaned up bloom shader code.
Split SampleOffsets shader parameter to GBufferInvSize and ShadowMapInvSize parameters.
Set Offsets & InvSize parameters for user-defined rendertargets during postprocessing.
Fixed bug on some NVIDIA drivers caused by using tex2Dlod on the hardware depth buffer.

Lasse Öörni 14 years ago
parent
commit
7075513957

+ 0 - 1
Bin/Data/PostProcess/Bloom.xml

@@ -3,7 +3,6 @@
     <rendertarget name="hblur" sizedivisor="4 4" format="rgb" filter="true" />
     <parameter name="BloomThreshold" value="0.3" />
     <parameter name="BloomMix" value="0.9 0.4" />
-    <parameter name="BlurOffset" value="2 2" />
     <pass vs="Bloom" ps="Bloom_Bright" output="vblur">
         <texture unit="diffuse" name="viewport" />
     </pass>

+ 1 - 1
Docs/Reference.dox

@@ -704,7 +704,7 @@ In addition to configuring programmatically, the PostProcess can be configured w
 
 Rendertargets can either specify an absolute width and height, or a divisor for the viewport size (for example sizedivisor="2 2" would divide the viewport dimensions by two.) The rendertargets are shared by all passes. A pass can output either into a rendertarget or into the viewport. The current contents of the viewport (either the scene render or a previous post-process pass) can also be read as a texture; this will always use the other half of the ping-pong buffer to avoid sampling the texture being rendered.
 
-Shader parameters can be defined either as global for all passes, or as pass-specific. In addition to the user-defined shader parameters, the shader parameters GBufferOffsets and SampleOffsets will always be set according to the viewport coordinates and the destination rendertarget size, so that the GetScreenPos() shader function will operate correctly, and adjacent pixels can be sampled. See the EdgeFilter shader for an example.
+Shader parameters can be defined either as global for all passes, or as pass-specific. In addition to the user-defined shader parameters, the shader parameters GBufferOffsets and GBufferInvSize will always be set according to the viewport coordinates and the destination rendertarget inverse size, so that the GetScreenPos() shader function can operate correctly, and adjacent pixels can be sampled. See the EdgeFilter shader for an example. Finally for user-defined rendertargets the shader parameters RenderTargetNameOffsets and RenderTargetNameInvSize will be set (if they exist) to allow to sample also these rendertargets properly. In this case the "offsets" parameter represents the half-pixel UV offset needed to sample whole pixels on Direct3D9 only; on OpenGL it will be zero.
 
 Note that when hardware multisampling is used in conjunction with post-processing, the multisampled backbuffer will first be resolved to the ping-pong buffer before rendering the post-process passes. This has a small performance cost.
 

+ 16 - 10
Engine/Graphics/Batch.cpp

@@ -216,13 +216,13 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         graphics->SetShaderParameter(VSP_FRUSTUMSIZE, viewportParams);
     }
     
+    IntVector2 rtSize = graphics->GetRenderTargetDimensions();
     IntRect viewport = graphics->GetViewport();
     unsigned viewportHash = (viewport.left_) | (viewport.top_ << 8) | (viewport.right_ << 16) | (viewport.bottom_ << 24);
+    float rtWidth = (float)rtSize.x_;
+    float rtHeight = (float)rtSize.y_;
     if (graphics->NeedParameterUpdate(VSP_GBUFFEROFFSETS, (const void*)viewportHash))
     {
-        IntVector2 rtSize = graphics->GetRenderTargetDimensions();
-        float rtWidth = (float)rtSize.x_;
-        float rtHeight = (float)rtSize.y_;
         float widthRange = 0.5f * (viewport.right_ - viewport.left_) / rtWidth;
         float heightRange = 0.5f * (viewport.bottom_ - viewport.top_) / rtHeight;
         
@@ -236,6 +236,12 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         
         graphics->SetShaderParameter(VSP_GBUFFEROFFSETS, bufferUVOffset);
     }
+    if (graphics->NeedParameterUpdate(PSP_GBUFFERINVSIZE, (const void*)viewportHash))
+    {
+        float sizeX = 1.0f / rtWidth;
+        float sizeY = 1.0f / rtHeight;
+        graphics->SetShaderParameter(PSP_GBUFFERINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
+    }
     
     if (overrideView_)
     {
@@ -455,13 +461,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         // Set shadow mapping shader parameters
         if (shadowMap)
         {
-            if (graphics->NeedParameterUpdate(PSP_SAMPLEOFFSETS, shadowMap))
-            {
-                float addX = 1.0f / (float)shadowMap->GetWidth();
-                float addY = 1.0f / (float)shadowMap->GetHeight();
-                graphics->SetShaderParameter(PSP_SAMPLEOFFSETS, Vector4(addX, addY, 0.0f, 0.0f));
-            }
-            
             if (graphics->NeedParameterUpdate(PSP_SHADOWCUBEADJUST, light))
             {
                 unsigned faceWidth = shadowMap->GetWidth() / 2;
@@ -518,6 +517,13 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 graphics->SetShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues / samples, intensity, 0.0f, 0.0f));
             }
             
+            if (graphics->NeedParameterUpdate(PSP_SHADOWMAPINVSIZE, shadowMap))
+            {
+                float sizeX = 1.0f / (float)shadowMap->GetWidth();
+                float sizeY = 1.0f / (float)shadowMap->GetHeight();
+                graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
+            }
+            
             if (graphics->NeedParameterUpdate(PSP_SHADOWSPLITS, light))
             {
                 Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);

+ 2 - 1
Engine/Graphics/GraphicsDefs.cpp

@@ -49,6 +49,7 @@ StringHash PSP_AMBIENTCOLOR("AmbientColor");
 StringHash PSP_DEPTHRECONSTRUCT("DepthReconstruct");
 StringHash PSP_FOGCOLOR("FogColor");
 StringHash PSP_FOGPARAMS("FogParams");
+StringHash PSP_GBUFFERINVSIZE("GBufferInvSize");
 StringHash PSP_LIGHTCOLOR("LightColor");
 StringHash PSP_LIGHTDIR("LightDirPS");
 StringHash PSP_LIGHTPOS("LightPosPS");
@@ -56,9 +57,9 @@ StringHash PSP_MATDIFFCOLOR("MatDiffColor");
 StringHash PSP_MATEMISSIVECOLOR("MatEmissiveColor");
 StringHash PSP_MATENVMAPECOLOR("MatEnvMapColor");
 StringHash PSP_MATSPECCOLOR("MatSpecColor");
-StringHash PSP_SAMPLEOFFSETS("SampleOffsets");
 StringHash PSP_SHADOWCUBEADJUST("ShadowCubeAdjust");
 StringHash PSP_SHADOWDEPTHFADE("ShadowDepthFade");
 StringHash PSP_SHADOWINTENSITY("ShadowIntensity");
+StringHash PSP_SHADOWMAPINVSIZE("ShadowMapInvSize");
 StringHash PSP_SHADOWSPLITS("ShadowSplits");
 StringHash PSP_LIGHTMATRICES("LightMatricesPS");

+ 2 - 1
Engine/Graphics/GraphicsDefs.h

@@ -219,6 +219,7 @@ extern StringHash PSP_AMBIENTCOLOR;
 extern StringHash PSP_DEPTHRECONSTRUCT;
 extern StringHash PSP_FOGCOLOR;
 extern StringHash PSP_FOGPARAMS;
+extern StringHash PSP_GBUFFERINVSIZE;
 extern StringHash PSP_LIGHTCOLOR;
 extern StringHash PSP_LIGHTDIR;
 extern StringHash PSP_LIGHTPOS;
@@ -226,10 +227,10 @@ extern StringHash PSP_MATDIFFCOLOR;
 extern StringHash PSP_MATEMISSIVECOLOR;
 extern StringHash PSP_MATENVMAPCOLOR;
 extern StringHash PSP_MATSPECCOLOR;
-extern StringHash PSP_SAMPLEOFFSETS;
 extern StringHash PSP_SHADOWCUBEADJUST;
 extern StringHash PSP_SHADOWDEPTHFADE;
 extern StringHash PSP_SHADOWINTENSITY;
+extern StringHash PSP_SHADOWMAPINVSIZE;
 extern StringHash PSP_SHADOWSPLITS;
 extern StringHash PSP_LIGHTMATRICES;
 

+ 1 - 0
Engine/Graphics/PostProcess.cpp

@@ -240,6 +240,7 @@ bool PostProcess::CreateRenderTarget(const String& name, unsigned width, unsigne
         return false;
     
     PostProcessRenderTarget target;
+    target.name_ = name;
     target.format_ = format;
     target.size_ = IntVector2(width, height),
     target.sizeDivisor_ = sizeDivisor;

+ 2 - 0
Engine/Graphics/PostProcess.h

@@ -85,6 +85,8 @@ private:
 /// Post-processing rendertarget info.
 struct PostProcessRenderTarget
 {
+    /// Name.
+    String name_;
     /// Texture format.
     unsigned format_;
     /// Size.

+ 18 - 1
Engine/Graphics/View.cpp

@@ -1372,7 +1372,24 @@ void View::RunPostProcesses()
             #endif
             
             graphics_->SetShaderParameter(VSP_GBUFFEROFFSETS, bufferUVOffset);
-            graphics_->SetShaderParameter(PSP_SAMPLEOFFSETS, Vector4(1.0f / rtWidth, 1.0f / rtHeight, 0.0f, 0.0f));
+            graphics_->SetShaderParameter(PSP_GBUFFERINVSIZE, Vector4(1.0f / rtWidth, 1.0f / rtHeight, 0.0f, 0.0f));
+            
+            // Set per-rendertarget inverse size / offset shader parameters as necessary
+            for (HashMap<StringHash, PostProcessRenderTarget>::ConstIterator k = renderTargetInfos.Begin(); k !=
+                renderTargetInfos.End(); ++k)
+            {
+                String invSizeName = k->second_.name_ + "InvSize";
+                String offsetsName = k->second_.name_ + "Offsets";
+                float width = (float)renderTargets[k->first_]->GetWidth();
+                float height = (float)renderTargets[k->first_]->GetHeight();
+                
+                graphics_->SetShaderParameter(StringHash(invSizeName), Vector4(1.0f / width, 1.0f / height, 0.0f, 0.0f));
+                #ifdef USE_OPENGL
+                graphics_->SetShaderParameter(StringHash(offsetsName), Vector4::ZERO);
+                #else
+                graphics_->SetShaderParameter(StringHash(offsetsName), Vector4(0.5f / width, 0.5f / height, 0.0f, 0.0f));
+                #endif
+            }
             
             const String* textureNames = pass->GetTextures();
             for (unsigned k = 0; k < MAX_MATERIAL_TEXTURE_UNITS; ++k)

+ 7 - 8
SourceAssets/GLSLShaders/Bloom.frag

@@ -5,18 +5,17 @@
 
 uniform float cBloomThreshold;
 uniform vec2 cBloomMix;
-uniform vec2 cBlurOffset;
+uniform vec2 cHBlurInvSize;
 
 varying vec2 vTexCoord;
 varying vec2 vScreenPos;
 
-// We are blurring a 4x downsampled RT, so blur offsets are 4x in terms of the original RT
 float offsets[5] = float[](
-    8.0,
-    4.0,
+    2.0,
+    1.0,
     0.0,
-    -4.0,
-    -8.0
+    -1.0,
+    -2.0
 );
 
 float weights[5] = float[](
@@ -37,14 +36,14 @@ void main()
     #ifdef HBLUR
     vec3 rgb = vec3(0.0, 0.0, 0.0);
     for (int i = 0; i < 5; ++i)
-        rgb += texture2D(sDiffMap, vTexCoord + vec2(offsets[i], 0.0) * cSampleOffsets).rgb * weights[i];
+        rgb += texture2D(sDiffMap, vTexCoord + vec2(offsets[i], 0.0) * cHBlurInvSize).rgb * weights[i];
     gl_FragColor = vec4(rgb, 1.0);
     #endif
 
     #ifdef VBLUR
     vec3 rgb = vec3(0.0, 0.0, 0.0);
     for (int i = 0; i < 5; ++i)
-        rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, offsets[i]) * cSampleOffsets).rgb * weights[i];
+        rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, offsets[i]) * cHBlurInvSize).rgb * weights[i];
     gl_FragColor = vec4(rgb, 1.0);
     #endif
 

+ 2 - 2
SourceAssets/GLSLShaders/EdgeFilter.frag

@@ -19,7 +19,7 @@ void main()
     float FXAA_REDUCE_MUL = 1.0/8.0;
     float FXAA_REDUCE_MIN = 1.0/128.0;
 
-    vec2 posOffset = cSampleOffsets.xy * cEdgeFilterParams.x;
+    vec2 posOffset = cGBufferInvSize.xy * cEdgeFilterParams.x;
 
     vec3 rgbNW = texture2D(sDiffMap, vScreenPos + vec2(-posOffset.x, -posOffset.y)).rgb;
     vec3 rgbNE = texture2D(sDiffMap, vScreenPos + vec2(posOffset.x, -posOffset.y)).rgb;
@@ -49,7 +49,7 @@ void main()
         float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
         dir = min(vec2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX),
               max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
-              dir * rcpDirMin)) * cSampleOffsets.xy;
+              dir * rcpDirMin)) * cGBufferInvSize.xy;
 
         dir *= cEdgeFilterParams.z;
 

+ 2 - 2
SourceAssets/GLSLShaders/Lighting.frag

@@ -39,9 +39,9 @@ float GetShadow(vec4 shadowPos)
     #ifndef LQSHADOW
         // Take four samples and average them
         #ifndef POINTLIGHT
-            vec2 offsets = cSampleOffsets * shadowPos.w;
+            vec2 offsets = cShadowMapInvSize * shadowPos.w;
         #else
-            vec2 offsets = cSampleOffsets;
+            vec2 offsets = cShadowMapInvSize;
         #endif
         vec4 inLight = vec4(
             shadow2DProj(sShadowMap, shadowPos).r,

+ 2 - 1
SourceAssets/GLSLShaders/Uniforms.frag

@@ -2,6 +2,7 @@ uniform vec3 cAmbientColor;
 uniform vec2 cDepthReconstruct;
 uniform vec3 cFogParams;
 uniform vec3 cFogColor;
+uniform vec2 cGBufferInvSize;
 uniform vec4 cLightColor;
 uniform vec3 cLightDirPS;
 uniform vec4 cLightPosPS;
@@ -9,9 +10,9 @@ uniform vec4 cMatDiffColor;
 uniform vec3 cMatEmissiveColor;
 uniform vec3 cMatEnvMapColor;
 uniform vec4 cMatSpecColor;
-uniform vec2 cSampleOffsets;
 uniform vec4 cShadowCubeAdjust;
 uniform vec4 cShadowDepthFade;
 uniform vec2 cShadowIntensity;
+uniform vec2 cShadowMapInvSize;
 uniform vec4 cShadowSplits;
 uniform mat4 cLightMatricesPS[4];

+ 12 - 12
SourceAssets/HLSLShaders/Bloom.hlsl

@@ -5,15 +5,15 @@
 
 uniform float cBloomThreshold;
 uniform float2 cBloomMix;
-uniform float2 cBlurOffset;
+uniform float2 cHBlurOffsets;
+uniform float2 cHBlurInvSize;
 
-// We are blurring a 4x downsampled RT, so blur offsets are 4x in terms of the original RT
 static const float offsets[5] = {
-    8.0,
-    4.0,
+    2.0,
+    1.0,
     0.0,
-    -4.0,
-    -8.0,
+    -1.0,
+    -2.0,
 };
 
 static const float weights[5] = {
@@ -32,7 +32,7 @@ void VS(float4 iPos : POSITION,
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
-    oTexCoord = GetQuadTexCoord(oPos);
+    oTexCoord = GetQuadTexCoord(oPos) + cHBlurOffsets;
     oScreenPos = GetScreenPosPreDiv(oPos);
 }
 
@@ -41,27 +41,27 @@ void PS(float2 iTexCoord : TEXCOORD0,
     out float4 oColor : COLOR0)
 {
     #ifdef BRIGHT
-    float3 rgb = Sample(sDiffMap, iScreenPos + cBlurOffset * cSampleOffsets).rgb;
+    float3 rgb = tex2D(sDiffMap, iScreenPos).rgb;
     oColor = float4((rgb - cBloomThreshold) / (1.0 - cBloomThreshold), 1.0);
     #endif
 
     #ifdef HBLUR
     float3 rgb = 0.0;
     for (int i = 0; i < 5; ++i)
-        rgb += Sample(sDiffMap, iTexCoord + (cBlurOffset + float2(offsets[i], 0.0)) * cSampleOffsets).rgb * weights[i];
+        rgb += tex2D(sDiffMap, iTexCoord + (float2(offsets[i], 0.0)) * cHBlurInvSize).rgb * weights[i];
     oColor = float4(rgb, 1.0);
     #endif
 
     #ifdef VBLUR
     float3 rgb = 0.0;
     for (int i = 0; i < 5; ++i)
-        rgb += Sample(sDiffMap, iTexCoord + (cBlurOffset + float2(0.0, offsets[i])) * cSampleOffsets).rgb * weights[i];
+        rgb += tex2D(sDiffMap, iTexCoord + (float2(0.0, offsets[i])) * cHBlurInvSize).rgb * weights[i];
     oColor = float4(rgb, 1.0);
     #endif
 
     #ifdef COMBINE
-    float3 original = Sample(sDiffMap, iScreenPos).rgb * cBloomMix.x;
-    float3 bloom = Sample(sNormalMap, iTexCoord).rgb  * cBloomMix.y;
+    float3 original = tex2D(sDiffMap, iScreenPos).rgb * cBloomMix.x;
+    float3 bloom = tex2D(sNormalMap, iTexCoord).rgb  * cBloomMix.y;
     // Prevent oversaturation
     original *= (1.0 - saturate(bloom));
     oColor = float4(original + bloom, 1.0);

+ 2 - 2
SourceAssets/HLSLShaders/EdgeFilter.hlsl

@@ -31,7 +31,7 @@ void PS(float2 iScreenPos : TEXCOORD0,
     float FXAA_REDUCE_MUL = 1.0/8.0;
     float FXAA_REDUCE_MIN = 1.0/128.0;
 
-    float2 posOffset = cSampleOffsets.xy * cEdgeFilterParams.x;
+    float2 posOffset = cGBufferInvSize.xy * cEdgeFilterParams.x;
 
     float3 rgbNW = Sample(sDiffMap, iScreenPos + float2(-posOffset.x, -posOffset.y)).rgb;
     float3 rgbNE = Sample(sDiffMap, iScreenPos + float2(posOffset.x, -posOffset.y)).rgb;
@@ -61,7 +61,7 @@ void PS(float2 iScreenPos : TEXCOORD0,
         float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
         dir = min(float2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX),
               max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
-              dir * rcpDirMin)) * cSampleOffsets.xy;
+              dir * rcpDirMin)) * cGBufferInvSize.xy;
     
         dir *= cEdgeFilterParams.z;
     

+ 1 - 1
SourceAssets/HLSLShaders/GreyScale.hlsl

@@ -17,7 +17,7 @@ void VS(float4 iPos : POSITION,
 void PS(float2 iScreenPos : TEXCOORD0,
     out float4 oColor : COLOR0)
 {
-    float3 rgb = Sample(sDiffMap, iScreenPos).rgb;
+    float3 rgb = tex2D(sDiffMap, iScreenPos).rgb;
     float intensity = GetIntensity(rgb);
     oColor = float4(intensity, intensity, intensity, 1.0);
 }

+ 4 - 4
SourceAssets/HLSLShaders/LightVolume.hlsl

@@ -49,17 +49,17 @@ void PS(
     // If rendering a directional light quad, optimize out the w divide
     #ifdef DIRLIGHT
         #ifdef ORTHO
-            float depth = Sample(sDepthBuffer, iScreenPos).r;
+            float depth = tex2D(sDepthBuffer, iScreenPos).r;
             float3 worldPos = lerp(iNearRay, iFarRay, depth);
         #else
             #ifdef LINEAR
-                float depth = Sample(sDepthBuffer, iScreenPos).r;
+                float depth = tex2D(sDepthBuffer, iScreenPos).r;
             #else
-                float depth = ReconstructDepth(Sample(sDepthBuffer, iScreenPos).r);
+                float depth = ReconstructDepth(tex2D(sDepthBuffer, iScreenPos).r);
             #endif
             float3 worldPos = iFarRay * depth;
         #endif
-        float4 normalInput = Sample(sNormalBuffer, iScreenPos);
+        float4 normalInput = tex2D(sNormalBuffer, iScreenPos);
     #else
         #ifdef ORTHO
             float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;

+ 2 - 2
SourceAssets/HLSLShaders/Lighting.hlsl

@@ -93,9 +93,9 @@ float GetShadow(float4 shadowPos)
     #ifndef LQSHADOW
         // Take four samples and average them
         #ifndef POINTLIGHT
-            float2 offsets = cSampleOffsets * shadowPos.w;
+            float2 offsets = cShadowMapInvSize * shadowPos.w;
         #else
-            float2 offsets = cSampleOffsets;
+            float2 offsets = cShadowMapInvSize;
         #endif
         float4 inLight = float4(
             tex2Dproj(sShadowMap, shadowPos).r,

+ 2 - 1
SourceAssets/HLSLShaders/Uniforms.hlsl

@@ -24,6 +24,7 @@ uniform float3 cAmbientColor;
 uniform float2 cDepthReconstruct;
 uniform float3 cFogParams;
 uniform float3 cFogColor;
+uniform float2 cGBufferInvSize;
 uniform float4 cLightColor;
 uniform float4 cLightPosPS;
 uniform float3 cLightDirPS;
@@ -31,10 +32,10 @@ uniform float4 cMatDiffColor;
 uniform float3 cMatEmissiveColor;
 uniform float3 cMatEnvMapColor;
 uniform float4 cMatSpecColor;
-uniform float2 cSampleOffsets;
 uniform float4 cShadowCubeAdjust;
 uniform float4 cShadowDepthFade;
 uniform float2 cShadowIntensity;
+uniform float2 cShadowMapInvSize;
 uniform float4 cShadowSplits;
 #ifdef SM3
     uniform float4x4 cLightMatricesPS[4];