Refraction shader

Hi, :slight_smile:
I would like to program a shader that does refract the scene on an object that is being displayed. So far that’s what I’ve done :

Vertex Shader :


varying vec3 Position;
varying vec3 Normal;

void main()
{
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
	gl_FrontColor = gl_Color;
	
	Position = vec3(gl_ModelViewProjectionMatrix * gl_Vertex);
	Normal = normalize(gl_NormalMatrix * gl_Normal);
} 

Fragment Shader :


varying vec3 Position;
varying vec3 Normal;

uniform sampler2D Texture;
uniform float ScreenResX, ScreenResY;

void main()
{

	vec2 PixelTexCoords = vec2(gl_FragCoord.x / ScreenResX, gl_FragCoord.y / ScreenResY);

	gl_FragColor = (gl_Color + texture2D(Texture, PixelTexCoords))/2.0;
}

This shader only blends the colors of the object with the scene behind, and what I would like it to do is to refract, that’s why I passed the position and the normal, but I do not know really how to proceed next, especially : If I calculate the refraction vector, how do I pass it to texture2D wich works with texel coordinates ?

Thank you :slight_smile:

Most GPUs I know of don’t provide the background colors in the shader, so you need to have the background you’re drawing over in a separate texture.

As for looking up the texture coordinate, that’s another matter. This is a very popular paper for performing refraction. You should read it a few times to get a idea of what you should do.

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.115.2481&rep=rep1&type=pdf

Thank you for the link :slight_smile:
It seems quite complex actually :sick:
In my case, it would be ok to refract only through the surface facing the camera. The background that I want to refract is passed trough the uniform “Texture” in my fragment shader.
My main problem actually is to have precisely the “offset.xy” in the texture2D command, since I do not know how to “convert” a vector in space coordinate into a vector in texels coordinates

Well you can play with hacks if you want to avoid the actual math : something as simple as PixelTexCoords+normal.xy/10.0 can be a start

I added something like that, and it works very well indeed :

Fragment shader :


varying vec3 Position;
varying vec3 Normal;

uniform sampler2D Texture;
uniform float ScreenResX, ScreenResY;
uniform float Alpha;

void main()
{

	vec2 PixelTexCoords = vec2(gl_FragCoord.x / ScreenResX, gl_FragCoord.y / ScreenResY);

	vec3 Refract = Normalize(Refract(Position, Normal, 1.20));

	gl_FragColor.rgb = mix(texture2D(Texture, PixelTexCoords + Refract.xy*0.1), gl_Color, Alpha).rgb;
	gl_FragColor.a = gl_Color.a;
}


Since the Refract vector is normalized, it works for any resolution

Thank you for your help :slight_smile: