Last update: 2 September 2015

Tutorial 8: Cube mapping reflection

Also known as environment mapping. This tutorial shows how to achieve environment reflection over a surface object. This technique is used to simulate reflective surface in a scene. We use a cube map texture as a reflection texture. This texture is then sampled per fragment in the pixel shader to simulate the reflection of the environment on the object.

Code walkthrough


First we load the texture cube map that will be used as the reflection texture: 

CTextureCubeMap *textureCubeMap = crm.LoadTextureCube("cm.jpg");


Next, the camera position is sent to the shader in the model space, the camera position will be used to determine the reflection vector over the surface normal:

/*to find the camera position in the model space:
camera or eye position is located at the v0( 0, 0, 0 ), we multiply v0 by the inverse of the           view matrix (V) then by the inverse of model matrix ( M). camPos = inv(M) * inv(V) *                     vec4(0, 0, 0, 1); */

vec4f camera_pos = ( m_pCamera->GetViewMatrix() * model ).inverse() * vec4f(0, 0, 0, 1.f);
//send camera pos to shader
m_pShaderMesh->SetUniform4fv("camPosModel", 1, &camera_pos.x);

the reflection vector calculated in the vertex shader need to be multiplied by the rotation vector of the object to get the correct reflection, so we need to send the rotation part of the model matrix to the vertex shader to re-project the reflection vector in the world space.

//extract the rotation matrix
mat3f model_mat3 = mat3f(model); 
//send to shader
m_pShaderMesh->SetUniformMatrix3x3fv("matModelToWorld", 1, GL_FALSE, &model_mat3[0]);

On the GPU side, in the vertex shader we calculate the eye direction in the model space by substracting the camera position from the vertex position:

//get the eye direction vector in the model space
vec4 eyeDir = normalize(position - camPosModel);

Then we calculate the reflection vector: 

reflect(eyeDir.xyz, normal);

We need to transform the reflection vector back to world space: 

 /*find the reflection vector between the eye direction and the vertex normal, multiply the reflection vector by the rotation matrix of the model ( transform to world space)*/
v_reflectionVector = matModelToWorld * reflect(eyeDir.xyz, normal);

finally, In the pixel shader,  we sample the cube map texture using the interpolated reflection vector sent by the vertex shader: 

gl_FragColor = textureCube(textureCubeMap, v_reflectionVector); 

The screenshot bellow shows the reflection on a teapot. to render the skybox, uncomment the tollowing line in Tutorial.cpp:

/#define RENDER_SKYBOX