# Water refraction bug

This topic is 1608 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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.

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 :-)

##### Share on other sites

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!

##### Share on other sites

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.

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 ?

##### Share on other sites

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!

##### Share on other sites

Thanks a lot, I'll try that !

• 10
• 16
• 14
• 18
• 15