Environment Mapping

There's another trick you can do with cubemaps. You can make objects in the scene reflect them. This is mostly useful for water, chrome, and other highly reflective materials. If you bounce a ray from the eye onto the surface, it will reflect perfectly about the surface's normal. That reflected vector shoots out from the surface and hits the skybox somewhere. The color it hits is the color that the fragment should be.

This renderer applies environment mapping to an amorphous blob:

Move around the blob with the WASD keys and mouse.

To implement environment mapping, you need a vector from the eye to the fragment. You've computed this before when adding specular lighting. Lighting is simplest in eye space, but environment mapping is simplest in world space, because the skybox is a fixture of the world.

That means several world space ingredients are needed. You need the fragment's world space position and world space normal from the vertex shader, the eye's world space position as a uniform, and the cubemap texture:

uniform samplerCube skybox;
uniform vec3 worldEyePosition;
in vec3 mixWorldPosition;
in vec3 mixWorldNormal;
out vec4 fragmentColor;

Then you compute the incident vector and reflect it about the normal. The texture lookup uses the reflection vector for its coordinates:

void main() {
  vec3 eyeToPosition = normalize(mixWorldPosition - worldEyePosition);
  vec3 normal = normalize(mixWorldNormal);
  vec3 reflection = reflect(eyeToPosition, normal);
  fragmentColor = texture(skybox, reflection);
}

Note that only the skybox colors appear on the reflective surface. No other objects in the scene are reflected because they are not present in the texture.