I am trying to create a screen-space distortion effect using shaders. This image demonstrating the effect I'm after is from Nvidia:


Let's consider that I have access to the background texture. How can I create this kind of effect? What should I do in the vertex and fragment function?

It seems that I need to retrieve screen-space normals of my object, but how?

  • 1
    \$\begingroup\$ key is changing the coordinates with which you sample the background texture \$\endgroup\$ – ratchet freak Dec 11 '14 at 12:31
  • \$\begingroup\$ Are you trying to simulate (approximately) refraction? I'm guessing from the small image you pasted. \$\endgroup\$ – david van brink Dec 12 '14 at 3:14

Simple lens shader that uses object's normals to distort the background. Render texture without this object, use it as "ScreenMapSampler" and then render all scene including this object in final frame. Not best implementation, but it works.

struct PS_OUTPUT{float4 Color : COLOR0;};    

struct VS_Lens
float4 Position: POSITION;
float4 ScreenMapSamplingPos: TEXCOORD0;
float3 Normal: TEXCOORD1;
float4 RefractionPosition: TEXCOORD2;
float Depth : TEXCOORD3;

    VS_Lens vs_Lens( float4 inPos : POSITION, float3 vNormal: NORMAL)
VS_Lens Output = (VS_Lens)0;
float4x4 preViewProjection = mul (matView, matProjection);
float4x4 preWorldViewProjection = mul (matWorld, preViewProjection);

matrix viewProjectWorld = mul(matView, matProjection);
viewProjectWorld = mul(matWorld, viewProjectWorld);

float4x4 worldViewProj = mul(matWorld, matView);
worldViewProj = mul(worldViewProj, matProjection);
Output.RefractionPosition = mul(inPos, worldViewProj);

Output.ScreenMapSamplingPos = mul(inPos, preWorldViewProjection);

Output.Position = mul(inPos, preWorldViewProjection);
Output.Normal = vNormal;
Output.Depth = Output.Position.z;

return Output;

    PS_OUTPUT ps_Lens(VS_Lens In)

float4 TextureCoords = In.RefractionPosition;
TextureCoords.xyz /= TextureCoords.w;
TextureCoords.x = 0.5f*TextureCoords.x + 0.5f;
TextureCoords.y = -0.5f*TextureCoords.y + 0.5f;
TextureCoords.z = .1f / TextureCoords.z;
Output.Color = tex2D(ScreenMapSampler, TextureCoords.xy - TextureCoords.z * In.Normal.xz);

return Output;

technique Lens
pass Pass0
VertexShader = compile vs_3_0 vs_Lens();
PixelShader = compile ps_3_0 ps_Lens();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.