Hi, I'm developing a mod for Dirt 3, I'm using 3DMigoto as a shader injector. I've modified 100s of shaders, but I'm completely stuck at implementing Screen Space reflections for water shaders. I've got it almost working, but the reflection is floating whenever I change the camera elevation and there is a lot of misaligned elements floating around. It's been my number one headache trigger for the last year. I've tried everything. but no luck so far.
If there is anyone that could spare some time, take a look at the shader code and point me in the right direction I would be really grateful.
Here is a video showing my problem:
and the vertex and pixel shaders:
// water deep not moving VS
cbuffer _Globals : register(b0)
{
float HDRRange : packoffset(c29);
float4x4 model : packoffset(c30);
float4x4 modelViewProj : packoffset(c34);
float2 AmbientLightMapScale : packoffset(c38);
float4x4 modelView : packoffset(c39);
float4x4 prevViewProj : packoffset(c43);
float4x4 prevModel : packoffset(c47);
float4 normalParams1 : packoffset(c51);
float4 normalParams2 : packoffset(c52);
float4 normalParams3 : packoffset(c53);
float4 normalParams4 : packoffset(c54);
float timer : packoffset(c55);
float blendValue : packoffset(c55.y);
float4 specularParams : packoffset(c56);
float4 waveParams : packoffset(c57);
float4 interactiveParams2 : packoffset(c58);
float4 interactiveParams3 : packoffset(c59);
float4 interactiveParams4 : packoffset(c60);
}
cbuffer CameraParamsConstantBuffer : register(b3)
{
float4x4 projection : packoffset(c0);
float4x4 viewProjection : packoffset(c4);
row_major float3x4 view : packoffset(c8);
row_major float3x4 viewI : packoffset(c11);
float3 eyePositionWS : packoffset(c14);
float4x4 inverseProj : packoffset(c15);
bool leftEye : packoffset(c19);
bool padding3[3] : packoffset(c20);
}
cbuffer PerFrameConstantBuffer : register(b1)
{
float4 colorBufferEncodingParams : packoffset(c0);
float4 envMapEncodingParams : packoffset(c1);
float4 velocityEncodingParams : packoffset(c2);
float4 snowEffectsParam2 : packoffset(c3);
float4 sunDirectionAndTime : packoffset(c4);
float4 sunColour : packoffset(c5);
float4 skylightColour : packoffset(c6);
float4 ambientOcclusionScales : packoffset(c7);
float4 backlightColour : packoffset(c8);
float4 specularScales : packoffset(c9);
float3 specularDirection : packoffset(c10);
float4 specularColourAndMultiplier : packoffset(c11);
float4 fogColour : packoffset(c12);
float4 fogParams : packoffset(c13);
float4 hazeParams : packoffset(c14);
float4 hazeParams2 : packoffset(c15);
float4 nightLightmapParam1 : packoffset(c16);
float4 nightLightmapParam2 : packoffset(c17);
float4 wetLightingParam : packoffset(c18);
float4 snowEffectsParam : packoffset(c19);
float4 ambientColour : packoffset(c20);
float4 shadowBlend : packoffset(c21);
float4 maskParams : packoffset(c22);
float4 deferredSpecularParams : packoffset(c23);
}
// 3Dmigoto declarations
#define cmp -
Texture1D<float4> IniParams : register(t120);
Texture2D<float4> StereoParams : register(t125);
void main(
float4 v0 : POSITION0,
float3 v1 : NORMAL0,
float3 v2 : TANGENT0,
float3 v3 : BINORMAL0,
float4 v4 : COLOR0,
out float4 o0 : SV_Position0,
out float4 o1 : COLOR1,
out float4 o2 : TEXCOORD0,
out float4 o3 : TEXCOORD1,
out float4 o4 : TEXCOORD2,
out float4 o5 : TEXCOORD3,
out float4 o6 : TEXCOORD4,
out float4 o7 : TEXCOORD5,
out float4 o8 : TEXCOORD6,
out float4 o9 : TEXCOORD7,
out float4 o10 : TEXCOORD8, //viewPosition
out float3 o11 : TEXCOORD9, //viewNormal
out float3 o12 : TEXCOORD10) //csPos
{
float4 r0,r1,r2,r3,r4,r5;
uint4 bitmask, uiDest;
float4 fDest;
//-- original game shader code
r0.xyzw = modelViewProj._m01_m11_m21_m31 * v0.yyyy;
r0.xyzw = modelViewProj._m00_m10_m20_m30 * v0.xxxx + r0.xyzw;
r0.xyzw = modelViewProj._m02_m12_m22_m32 * v0.zzzz + r0.xyzw;
r0.xyzw = modelViewProj._m03_m13_m23_m33 * v0.wwww + r0.xyzw;
o0.xyzw = r0.xyzw;
r1.xyz = model._m01_m11_m21 * v0.yyy;
r1.xyz = model._m00_m10_m20 * v0.xxx + r1.xyz;
r1.xyz = model._m02_m12_m22 * v0.zzz + r1.xyz;
r1.xyz = model._m03_m13_m23 * v0.www + r1.xyz;
r2.xyz = -eyePositionWS.xyz + r1.xyz;
r1.w = dot(r2.xyz, r2.xyz);
r1.w = sqrt(r1.w);
r2.xyz = r2.xyz / r1.www;
r2.x = saturate(dot(r2.xyz, sunDirectionAndTime.xyz));
r2.x = log2(r2.x);
r2.x = hazeParams2.w * r2.x;
r2.x = exp2(r2.x);
r2.yzw = hazeParams2.xyz + -hazeParams.xyz;
r2.xyz = r2.xxx * r2.yzw + hazeParams.xyz;
r3.x = 1 / fogParams.z;
r3.x = -r3.x + r1.w;
r1.w = -30 + r1.w;
r1.w = saturate(fogParams.z * r1.w);
r4.w = fogParams.w * r1.w;
r1.w = max(0, r3.x);
r1.w = hazeParams.w * r1.w;
r1.w = 1.44269502 * r1.w;
r1.w = exp2(r1.w);
r2.w = 1 + -r1.w;
r4.xyz = fogColour.xyz;
r3.xyzw = -r4.xyzw + r2.xyzw;
r2.xyzw = r2.wwww * r3.xyzw + r4.xyzw;
o1.xyz = r2.xyz * r2.www;
o1.w = 1 + -r2.w;
r2.xyz = model._m01_m11_m21 * v1.yyy;
r2.xyz = model._m00_m10_m20 * v1.xxx + r2.xyz;
r2.xyz = model._m02_m12_m22 * v1.zzz + r2.xyz;
r1.w = dot(r2.xyz, r2.xyz);
r1.w = rsqrt(r1.w);
r2.xyz = r2.xyz * r1.www;
o2.xyz = r2.xyz;
r3.xy = interactiveParams2.wz * float2(1,-1);
r3.xy = interactiveParams4.xx * r3.xy;
r1.w = timer + 0.5;
r3.xy = r1.ww * r3.xy;
r3.zw = float2(0.0500000007,0.0500000007) * r1.xz;
r3.xy = r3.zw * interactiveParams4.xx + r3.xy;
o2.w = r3.x;
o3.w = r3.y;
r4.xyz = model._m01_m11_m21 * v2.yyy;
r4.xyz = model._m00_m10_m20 * v2.xxx + r4.xyz;
r4.xyz = model._m02_m12_m22 * v2.zzz + r4.xyz;
r1.w = dot(r4.xyz, r4.xyz);
r1.w = rsqrt(r1.w);
r4.xyz = r4.xyz * r1.www;
o3.xyz = r4.xyz;
r5.xyz = r4.yzx * r2.zxy;
r2.xyz = r2.yzx * r4.zxy + -r5.xyz;
r1.w = dot(r2.xyz, r2.xyz);
r1.w = rsqrt(r1.w);
o4.xyz = r2.xyz * r1.www;
o4.w = 0;
r2.xyzw = normalParams4.xyzw + r1.xzxz;
o7.xyz = r1.xyz;
o7.w = 0;
r1.xyzw = normalParams2.xxyy * r2.xyzw;
r1.xyzw = specularParams.wwww * r1.xyzw;
o5.xyzw = float4(0.0500000007,0.0500000007,0.0500000007,0.0500000007) * r1.xyzw;
r1.xy = specularParams.ww * r3.zw;
r1.zw = waveParams.xy * timer;
r1.zw = normalParams1.zz * r1.zw;
o6.xy = r1.xy * normalParams2.zz + r1.zw;
r1.xy = interactiveParams3.ww * interactiveParams2.zw;
r1.xy = timer * r1.xy;
o6.zw = r3.zw * interactiveParams3.ww + r1.xy;
o8.x = dot(float2(0.5,0.5), r0.xw);
o8.y = dot(float2(0.5,0.5), r0.yw);
o8.zw = r0.zw;
r0.x = modelView._m21 * v0.y;
r0.x = modelView._m20 * v0.x + r0.x;
r0.x = modelView._m22 * v0.z + r0.x;
o9.z = modelView._m23 + r0.x;
o9.xyw = float3(0,0,1);
//-- output values for SSR
o10 = mul(modelView, v0.xyzw); //viewPosition
o11 = mul((float3x3)modelView, v1.xyz); //viewNormal
float4 position = mul(modelViewProj, float4(v0.xyzw));
o12 = position.xyz / position.w; //csPosition
return;
}
// water deep not moving PS
cbuffer _Globals : register(b0)
{
float HDRRange : packoffset(c29);
float2 AmbientLightMapScale : packoffset(c29.y);
float4 normalParams1 : packoffset(c30);
float4 normalParams2 : packoffset(c31);
float4 normalParams3 : packoffset(c32);
float4 normalParams4 : packoffset(c33);
float timer : packoffset(c34);
float4 screenProj : packoffset(c35);
float4 fresnelParams : packoffset(c36);
float4 horizonColour : packoffset(c37);
float4 nadirColour : packoffset(c38);
float4 interactiveParams1 : packoffset(c39);
float4 interactiveParams5 : packoffset(c40);
float4 waterShadowBlend : packoffset(c41);
float4 decodeParam : packoffset(c42);
float4 sparkleParams : packoffset(c43);
float4 sparkleParams2 : packoffset(c44);
float blendValue : packoffset(c45);
float4 specularParams : packoffset(c46);
float4 waveParams : packoffset(c47);
float4 interactiveParams2 : packoffset(c48);
float4 interactiveParams3 : packoffset(c49);
float4 interactiveParams4 : packoffset(c50);
}
cbuffer RenderTargetConstantBuffer : register(b2)
{
float4 viewportDimensions : packoffset(c0);
}
cbuffer CameraParamsConstantBuffer : register(b3)
{
float4x4 projection : packoffset(c0);
float4x4 viewProjection : packoffset(c4);
row_major float3x4 view : packoffset(c8);
row_major float3x4 viewI : packoffset(c11);
float3 eyePositionWS : packoffset(c14);
float4x4 inverseProj : packoffset(c15);
bool leftEye : packoffset(c19);
bool padding3[3] : packoffset(c20);
}
cbuffer PerFrameConstantBuffer : register(b1)
{
float4 colorBufferEncodingParams : packoffset(c0);
float4 envMapEncodingParams : packoffset(c1);
float4 velocityEncodingParams : packoffset(c2);
float4 snowEffectsParam2 : packoffset(c3);
float4 sunDirectionAndTime : packoffset(c4);
float4 sunColour : packoffset(c5);
float4 skylightColour : packoffset(c6);
float4 ambientOcclusionScales : packoffset(c7);
float4 backlightColour : packoffset(c8);
float4 specularScales : packoffset(c9);
float3 specularDirection : packoffset(c10);
float4 specularColourAndMultiplier : packoffset(c11);
float4 fogColour : packoffset(c12);
float4 fogParams : packoffset(c13);
float4 hazeParams : packoffset(c14);
float4 hazeParams2 : packoffset(c15);
float4 nightLightmapParam1 : packoffset(c16);
float4 nightLightmapParam2 : packoffset(c17);
float4 wetLightingParam : packoffset(c18);
float4 snowEffectsParam : packoffset(c19);
float4 ambientColour : packoffset(c20);
float4 shadowBlend : packoffset(c21);
float4 maskParams : packoffset(c22);
float4 deferredSpecularParams : packoffset(c23);
}
SamplerState TNormalMap_s : register(s0);
SamplerState DepthMap_s : register(s1);
SamplerState ReflectionMap_s : register(s2);
SamplerState ReflectionMap2_s : register(s3);
SamplerState TMaskMap_s : register(s4);
SamplerState TShadowMask_s : register(s10);
Texture2D<float4> DepthMap : register(t0);
Texture2D<float4> TNormalMap : register(t1);
Texture2D<float4> ReflectionMap : register(t2);
Texture2D<float4> ReflectionMap2 : register(t3);
Texture2D<float4> TShadowMask : register(t4);
Texture2D<float4> TMaskMap : register(t5);
//-- SSR buffers
Texture2D<float> DepthBuffer : register(t100);
SamplerState DepthBuffer_s : register(s11);
Texture2D<float4> HDRTex : register(t101);
SamplerState HDRTex_s : register(s12);
//-- 3Dmigoto declarations
#define cmp -
Texture1D<float4> IniParams : register(t120);
Texture2D<float4> StereoParams : register(t125);
//-- SSR Constants
static float2 cb_depthBufferSize; // dimensions of the z-buffer
static const float cb_zThickness = 1; // thickness to ascribe to each pixel in the depth buffer
//static const float cb_nearPlaneZ = 0.6; // the camera's near z plane
static const float cb_stride = 1; // Step in horizontal or vertical pixels between samples. This is a float
// because integer math is slow on GPUs, but should be set to an integer >= 1.
static float cb_maxSteps; // Maximum number of iterations. Higher gives better images but may be slow.
//static const float cb_maxDistance = 10000; // Maximum camera-space distance to trace before returning a miss.
static const float cb_strideZCutoff = 0; // More distant pixels are smaller in screen space. This value tells at what point to
// start relaxing the stride to give higher quality reflections for objects far from
// the camera.
static const float cb_numMips = 1; // the number of mip levels in the convolved color buffer
static const float cb_fadeStart = 0; // determines where to start screen edge fading of effect
static const float cb_fadeEnd = 0; // determines where to end screen edge fading of effect
static const float cb_sslr_padding0 = 0; // padding for alignment
//--SSR Functions
float linearizeDepth(float depth)
{
float4 tmp = mul(inverseProj, float4(0, 0, depth, 1));
return mul(projection, tmp / tmp.w).w;
//float n = cb_nearPlaneZ; // camera z near
//float f = cb_maxDistance; // camera z far
//float z = depth;
//return (2.0 * n) / (f + n - z * (f - n));
}
float distanceSquared(float2 a, float2 b)
{
a -= b;
return dot(a, a);
}
bool intersectsDepthBuffer(float z, float minZ, float maxZ)
{
/*
* Based on how far away from the camera the depth is,
* adding a bit of extra thickness can help improve some
* artifacts. Driving this value up too high can cause
* artifacts of its own.
*/
float depthScale = min(1.0f, z * cb_strideZCutoff);
z += cb_zThickness + lerp(0.0f, 2.0f, depthScale);
return (maxZ >= z) && (minZ - cb_zThickness <= z);
}
void swap(inout float a, inout float b)
{
float t = a;
a = b;
b = t;
}
float linearDepthTexelFetch(int2 hitPixel)
{
// Load returns 0 for any value accessed out of bounds
return linearizeDepth(DepthBuffer.Load(int3(hitPixel, 0)).r);
}
bool traceScreenSpaceRay(
// Camera-space ray origin, which must be within the view volume
float3 csOrig,
// Unit length camera-space ray direction
float3 csDir,
// Number between 0 and 1 for how far to bump the ray in stride units
// to conceal banding artifacts. Not needed if stride == 1.
float jitter,
// Pixel coordinates of the first intersection with the scene
out float2 hitPixel,
// Camera space location of the ray hit
out float3 hitPoint)
{
float near = linearizeDepth(0);
float far = linearizeDepth(1);
// Clip to the near plane
float rayLength = ((csOrig.z + csDir.z * far) > -near) ?
(-near - csOrig.z) / csDir.z : far;
float3 csEndPoint = csOrig + csDir * rayLength;
// Project into homogeneous clip space
float4 H0 = mul(projection, float4(csOrig, 1.0f));
float4 H1 = mul(projection, float4(csEndPoint, 1.0f));
float k0 = 1.0f / H0.w;
float k1 = 1.0f / H1.w;
// The interpolated homogeneous version of the camera-space points
float3 Q0 = csOrig * k0;
float3 Q1 = csEndPoint * k1;
// Screen-space endpoints
float2 P0 = H0.xy * k0;
float2 P1 = H1.xy * k1;
// Scale to pixels:
P0 = (P0 * float2(0.5, -0.5) + 0.5) * cb_depthBufferSize;
P1 = (P1 * float2(0.5, -0.5) + 0.5) * cb_depthBufferSize;
// If the line is degenerate, make it cover at least one pixel
// to avoid handling zero-pixel extent as a special case later
P1 += (distanceSquared(P0, P1) < 0.0001f) ? float2(0.01f, 0.01f) : 0.0f;
float2 delta = P1 - P0;
// Permute so that the primary iteration is in x to collapse
// all quadrant-specific DDA cases later
bool permute = false;
if(abs(delta.x) < abs(delta.y))
{
// This is a more-vertical line
permute = true;
delta = delta.yx;
P0 = P0.yx;
P1 = P1.yx;
}
float stepDir = sign(delta.x);
float invdx = stepDir / delta.x;
// Track the derivatives of Q and k
float3 dQ = (Q1 - Q0) * invdx;
float dk = (k1 - k0) * invdx;
float2 dP = float2(stepDir, delta.y * invdx);
// Scale derivatives by the desired pixel stride and then
// offset the starting values by the jitter fraction
float strideScale = 1.0f - min(1.0f, csOrig.z * cb_strideZCutoff);
float stride = 1.0f + strideScale * cb_stride;
dP *= stride;
dQ *= stride;
dk *= stride;
P0 += dP * jitter;
Q0 += dQ * jitter;
k0 += dk * jitter;
// Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1
float4 PQk = float4(P0, Q0.z, k0);
float4 dPQk = float4(dP, dQ.z, dk);
float3 Q = Q0;
float end = P1.x * stepDir;
float stepCount = 0.0f;
float prevZMaxEstimate = csOrig.z;
float rayZMin = prevZMaxEstimate;
float rayZMax = prevZMaxEstimate;
float sceneZMax = rayZMax + 100.0f;
for(;
((PQk.x * stepDir) <= end) && (stepCount < cb_maxSteps) &&
!intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax) &&
(sceneZMax != 0.0f); ++stepCount)
{
rayZMin = prevZMaxEstimate;
rayZMax = (dPQk.z * 0.5f + PQk.z) / (dPQk.w * 0.5f + PQk.w);
prevZMaxEstimate = rayZMax;
if(rayZMin > rayZMax)
{
swap(rayZMin, rayZMax);
}
hitPixel = permute ? PQk.yx : PQk.xy;
// You may need hitPixel.y = depthBufferSize.y - hitPixel.y; here if your vertical axis
// is different than ours in screen space
sceneZMax = linearDepthTexelFetch(int2(hitPixel));
PQk += dPQk;
}
// Advance Q based on the number of steps
Q.xy += dQ.xy * stepCount;
hitPoint = Q * (1.0f / PQk.w);
return intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax);
}
//-- Main stripped from all code, only planar reflection is displayed
void main(
float4 v0 : SV_Position0,
float4 v1 : COLOR1,
float4 v2 : TEXCOORD0,
float4 v3 : TEXCOORD1,
float4 v4 : TEXCOORD2,
linear centroid float4 v5 : TEXCOORD3,
linear centroid float4 v6 : TEXCOORD4,
linear centroid float4 v7 : TEXCOORD5,
float4 v8 : TEXCOORD6,
linear centroid float4 v9 : TEXCOORD7,
out float4 o0 : SV_Target0,
float4 viewPosition : TEXCOORD8,
float3 normalVS : TEXCOORD9,
float3 csPosition : TEXCOORD10)
{
float4 stereo = StereoParams.Load(0);
float separation = stereo.x * (leftEye ? -1 : 1);
float convergence = stereo.y;
viewPosition.x += separation * convergence * inverseProj._m00;
DepthBuffer.GetDimensions(cb_depthBufferSize.x, cb_depthBufferSize.y);
cb_maxSteps = cb_depthBufferSize.y;
float2 hitPixel = float2(0.0f, 0.0f);
float3 hitPoint = float3(0.0f, 0.0f, 0.0f);
int3 loadIndices = int3(v0.xy, 0);
float depth = DepthBuffer.Load(loadIndices);
float3 rayOriginVS = viewPosition * linearizeDepth(depth);
float3 toPositionVS = normalize(rayOriginVS);
float3 rayDirectionVS = normalize(reflect(-toPositionVS, normalVS));
// output rDotV to the alpha channel for use in determining how much to fade the ray
float rDotV = dot(rayDirectionVS, toPositionVS);
float jitter = cb_stride > 1.0f ? float(int(v0.x + v0.y) & 1) * 0.5f : 0.0f;
bool intersection = traceScreenSpaceRay(-rayOriginVS, -rayDirectionVS, jitter, hitPixel, hitPoint);
if (intersection != false) o0.xyz = HDRTex.Load(float3(hitPixel, 0));
else o0.xyz = float3(0,0,0);
o0.w=1;
return;
}
↧