In this tutorial two reflection examples will be shown, based on cubemap textures and on an equirectangular textures.

Cubemap Reflections

A cubemap is made of six squared textures mapped into a cube centered on the camera. You can use the textureCube function to sample this texture in a spatial direction. Once you add the skybox property to the config object, you will get the same cubemap texture available in shader as a uniform with the name tCube. You will sample this cubemap texture to get a reflection color for your mesh surface.

For a basic cubemap reflection, you need the surface normal in world space and the view vector in world space. Then you can compute the reflected vector in world space and use it, normalized, to sample the cubemap.

Here is the vertex shader piece of code:

vec4 vertPos4 = modelMatrix * vec4(position, 1.0);
vertPos = vec3(vertPos4) / vertPos4.w;

viewVector = position - cameraPosition;

wNormalInterp = normal;

Note that all these vectors are computed in world space (look at the modelMatrix for the vertPos).

For the fragment part, you can perturbate the normal using a normal map and the per-pixel tangent space normal mapping shown in this tutorial. Then you can compute the reflected vector using the reflect GLSL function with the world-space perturbed normal and view vector.

vec3 reflectVec = normalize(reflect(viewVector, normal));
reflectVec.x *= -1.0;
gl_FragColor = textureCube(tCube, reflectVec);

It turns out that you have to flip the x coordinate of the reflected vector in order to correctly sample the reflection from the cubemap. This is required because some flipping occurs during the rendering of the cubemap texture to get a correct visualization of the images.

Cubemap reflections debug

You can use the following cubemap example texture to debug your reflection shader.

Check for these three rules for a correct reflection:

  • The text you read in the background is not flipped
  • The text reflected in the sphere is flipped
  • The face you see in the center of the sphere is always the opposite of the face you see behind the sphere

Equirectangular Map Reflections

An equirectangular (or spherical) texture represents a spherical projection where the x axis is the longitude from 0 to 360 degrees and the y axis is the latitude from -90 to 90 degrees. The width of this kind of texture is generally two times its height and to use it as a skybox you have to wrap it into a sphere centered on the camera. Once you add the skybox property to the config object, you will get the same equirectangular texture available in shader as a uniform with the name tEquirect. You will sample this equirectangular texture to get a reflection color for your mesh surface.

Once you have computed the reflected vector, you have to do a bit of math to get the corresponding sampling coordinates in the spherical (equirectangular) map. You have to compute the longitude and the latitude and normalize them in the [0, 1] range.

vec3 reflectVec = normalize(reflect(viewVector, normal));
vec2 uv;

// Computing longitude
uv.x = atan( -reflectVec.z, -reflectVec.x ) * RECIPROCAL_PI2 + 0.5;

// Computing latitude
uv.y = reflectVec.y * 0.5 + 0.5;

gl_FragColor = texture2D( tCube, uv );

Note that, for the y (latitude) coordinate of the UVs, the y component of the reflected vector has been used. This is actually an approximation of the latitude: the y component of the relfected vector is equal to the sin of the latitude; that value is then remapped from [-1, 1] to [0, 1] to match the UV coordinates domain. If you want to be more accurate, you should use the arcsin of the y component of the reflected vector to compute the exact latitude.

Equirectangular reflections debug

You can use the following equirectangular example texture to debug your reflection shader.

Check for these three rules for a correct reflection:

  • The text you read in the background is not flipped
  • The text reflected in the sphere is flipped
  • The face you see in the center of the sphere is always the opposite of the face you see behind the sphere