Water refraction bug

Started by
3 comments, last by Yann_A 10 years, 3 months ago

Hi there,

I am trying to implement refraction for water surface, and i am struggling a bit with the implementation as this is the first time I am trying to do such a thing. The water surface is not flat, i use FFT on a small grid to make vertices move, and i use the normals of each vertices to calculate the refraction vector. Then i substract the view ray with the refract ray to know how much i need to offset my texture sampling when shading the water surface.

Here is the shader


VertexOut VS(VertexIn vin)
{
VertexOut vout; 

// Transform to world space.
vout.PosW    = mul(float4(vin.PosL, 1.0f), gWorld).xyz;

// Find transformed normals.
vout.NormalW = mul(vin.NormalL, (float3x3)gWorld);
vout.NormalV = mul(vin.NormalL, (float3x3)gWorldView);

// Transform to homogeneous clip space.
vout.PosH = mul(float4(vout.PosW, 1.0f), gViewProj);

vout.Tex = vin.Tex;

vout.PosV = mul(float4(vin.PosL, 1.0f), gWorldView).xyz;

return vout;
}

float4 PS(VertexOut pin) : SV_Target
{ 
float backBufferWidth = 1024.0f;
float backBufferHeight = 768.0f;
float zFar = 300.0f;
pin.NormalV = normalize(pin.NormalV);
float3 viewRay = normalize(pin.PosV);
float3 refractRay = refract(viewRay, pin.NormalV, 0.75f);
float2 InvTextureSize = float2(1.0f / backBufferWidth, 1.0f / backBufferHeight);
float2 texCoord = float2(pin.PosH.x, pin.PosH.y) * InvTextureSize;
float zw = gDepthMap.Sample(PointSampler, texCoord).x;

// Reconstruct linear depth.
    float depth2 = ProjectionB / (zw - ProjectionA);

// Calculate View position of ground fragment.
float3 groundPosV = viewRay * depth2; 

    // Calculate sampling offset caused by refraction.
float3 diff = normalize(normalize(viewRay) - normalize(refractRay));

texCoord = texCoord + diff.xz;

float3 sourceColor = gGroundMap.Sample(PointSampler, texCoord); 
return float4(sourceColor, 1.0f); 
}

And here is the result :

I think the issue is around these lines :


// Calculate sampling offset caused by refraction.
float3 diff = normalize(normalize(viewRay) - normalize(refractRay));
texCoord = texCoord + diff.xz;

as i am not sure this will keep me in UV space.

Any idea ?!

Thanks :-)

Advertisement

Hiya,

For refraction I just use the x,z (or x,y depending on coordinate space) of the bump map multiplied by a value that scales based on distance. I can only see weird things happening if you use the view ray.

ie.

texCoord = texCoord + bump.xz * refractScale;

You might also want to put another scaling factor in that is based on the distance of the viewer from the surface.

n!

Thanks for answering nfactorial.

I tried to scale the effect down by adding a 0.1f factor to it, and it does improve things. But i still have visual artefacts on the edges, I guess its the same artefacts i had before, but at a smaller scale.

rU2z8kZ.jpg

ktq99CN.jpg

New shader code :


float zw = gDepthMap.Sample(PointSampler, texCoord).x;

...

// Calculate sampling offset caused by refraction.
float3 diff = viewRay - refractRay;
diff = diff / zw;

texCoord = texCoord + (diff.xz * 0.1f);

Any thoughts ?

You need to be careful around the edges, as the offset can bring the sample outside of the water. You generally check the depth of the refracted point and if it's closer than the water surface, you chose something else (I normally take the screen position of the original water surface).

n!

Thanks a lot, I'll try that !

This topic is closed to new replies.

Advertisement