Cubemaps
You may need to read the articles about lighting and textures before this one.
A cubemap is a type of texture that consists of six faces, each referenced by their direction from the center of a cube. Cubemaps are sampled using normals that represent the direction from the origin to the desired texel (rather than texture coordinates). A cubemap can be sampled using a samplerCube
variable.
#version 300 es
precision mediump float;
in vec3 v_normal;
uniform samplerCube u_texture;
out vec4 outColor;
void main() {
vec3 normal = normalize(v_normal);
outColor = texture(u_texture, normal);
}
Environment Maps
The most common thing that cubemaps are used for are environment maps, which represent the environment of a scene. Environment maps are a way to approximate reflections. If a fragment shader knows the position and normal of its fragment relative to the origin, it can use the reflect
function to calculate a reflection.
#version 300 es
precision mediump float;
in vec3 v_worldPos;
in vec3 v_normal;
uniform samplerCube u_texture;
uniform vec3 u_camPos;
out vec4 outColor;
void main() {
vec3 normal = normalize(v_normal);
vec3 camToSurfaceDir = normalize(v_worldPos - u_camPos);
vec3 reflectDir = reflect(camToSurfaceDir, normal);
outColor = texture(u_texture, reflectDir);
}
You can find the source of the example texture here.
Skyboxes
A skybox is a cubemap that represents the background of a scene (often a sky). Skyboxes can be implemented by using the inverse of the view projection matrix to sample the skybox onto a plane that covers the entire rendering context.
The vertex shader should ensure that the skybox is always at the back of the depth buffer.
#version 300 es
in vec4 a_position;
out vec4 v_position;
void main() {
gl_Position = a_position;
gl_Position.z = 1.0;
v_position = a_position;
}
The skybox is treated as being infinitely far away from the camera, so calculations involving it should use a view direction matrix, which is a view matrix with the translation component removed.
A fragment shader can multiply a fragment's position by the inverse of a view direction projection matrix (a product of a projection matrix a view direction matrix) to undo it. Then, it needs to manually divide the xyz
vector by w
to apply perspective. The result can be sampled from the environment map to make a skybox.
#version 300 es
precision mediump float;
in vec4 v_position;
uniform samplerCube u_texture;
uniform mat4 u_inverseViewDirProjMat;
out vec4 outColor;
void main() {
vec4 t = u_inverseViewDirProjMat * v_position;
vec3 skyboxNormal = normalize(t.xyz / t.w);
outColor = texture(u_texture, skyboxNormal);
}
The next article is about shadows.