Refraction: Part 1

So, that engine I was working on; I made quite a bit of progress and decided to try and actual project with it. The project is real time refraction using GLSL. The first step is very quick and easy.
One bounce refraction of an infinite environment.
First, create a skybox in order to create an infinite environment and render it to the screen. Next, enable the environment map (let’s assume it is stored as a texture cube map) and activate the GLSL program. Render the refractive object and disable everything you just enabled. The shaders I used are modified from the Orange Book.
First, the vertex shader. Two varying vec3s i stores the vertex position in eye space and n stores the vertex normal in eye space.
varying vec3 i;
varying vec3 n;
void main()
{
vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
i = ecPosition.xyz / ecPosition.w;
n = gl_NormalMatrix * gl_Normal;
gl_Position = ftransform();
}
Now, the fragment shader. Using i and n we find the vector that refracts off the surface of the object. This vector is multiplied by gl_TextureMatrix[0] which holds the inverted modelview matrix. This converts the refracted vector from eye space into world space. Using that vector to index into the cube map gives us our final color.
uniform samplerCube texture;
uniform float indexOfRefraction;
varying vec3 i;
varying vec3 n;
void main()
{
i = normalize(i);
n = normalize(n);
vec3 Refracted = refract(i, n, indexOfRefraction);
Refracted = vec3(gl_TextureMatrix[0] * vec4(RefractR, 1.0));
vec3 refractColor = vec3(textureCube(texture, RefractR));
gl_FragColor = vec4(refractColor, 1.0);
}
If you look at the Orange Book example, you see a few extra features to make the refracting object look more realistic. The first is the Fresnel Effect. This is when you view the refracting object at such an angle that you will actually see a reflection instead. Next is diffraction, or chromatic abberation. We boil it down to supplying a slightly different index of refraction for each color channel.
The vertex shader stays the same, but the fragment shader changes slightly. We find a different refraction vector for each color channel, and also a reflection vector. Look up the colors and mix them together based on the fresnel factor.
uniform samplerCube texture;
uniform vec4 indexOfRefraction; // {R, G, B, Fresnel}
varying vec3 i;
varying vec3 n;
const float FresnelPower = 5.0;
void main()
{
i = normalize(i);
n = normalize(n);
float Ratio = indexOfRefraction.a + (1.0 - indexOfRefraction.a) * pow((1.0 - dot(-i, n)), FresnelPower);
vec3 RefractR = refract(i, n, indexOfRefraction.r);
RefractR = vec3(gl_TextureMatrix[0] * vec4(RefractR, 1.0));
vec3 RefractG = refract(i, n, indexOfRefraction.g);
RefractG = vec3(gl_TextureMatrix[0] * vec4(RefractG, 1.0));
vec3 RefractB = refract(i, n, indexOfRefraction.b);
RefractB = vec3(gl_TextureMatrix[0] * vec4(RefractB, 1.0));
vec3 Reflect = reflect(i, n);
Reflect = vec3(gl_TextureMatrix[0] * vec4(Reflect, 1.0));
vec3 refractColor, reflectColor;
refractColor.r = vec3(textureCube(texture, RefractR)).r;
refractColor.g = vec3(textureCube(texture, RefractG)).g;
refractColor.b = vec3(textureCube(texture, RefractB)).b;
reflectColor = vec3(textureCube(texture, Reflect));
vec3 color = mix(refractColor, reflectColor, Ratio);
gl_FragColor = vec4(color, 1.0);
}