As far as tutorials go, I'll just recommend this one.
- In contrast sampling a 2D texture works simply by passing UV
coordinates and getting the current pixel color at that UV location
in the texture.
- While cubemaps use a 3D directional vector that starts from the
center of the cube and travels along until it hits one of the sides
allowing it to sample the pixel from that side in that particular texture.
The reason to have a separate shader for a skybox is probably convenience. You might want to make special modifications some time in the future. But also the fact that we can do this pos.xyww;
to ignore writing to the depth buffer.
Now notice in the vertex shader we set texture direction vector (texDirection) equal to the position of the current vertex. Remember that all vectors interpolate when they get to the fragment shader, and so texDirection will interpolate it self from one side of the cube to the other, going all around.
Vertex Shader:
in vec3 position;
out vec3 texDirection;
uniform mat4 projection;
uniform mat4 view;
void main() {
vec4 pos = projection * view * vec4(position, 1.0);
gl_Position = pos.xyww; // We ignore the depth buffer here
texDirection = position; // Let it interpolate
}
Inside the fragment shader we sample a pixel from the skybox by shooting in the direction of our lovely interpolated texDirection. It hits one of the sides and returns a color that we store in output variable color.
Fragment Shader:
in vec3 texDirection;
out vec4 color;
uniform samplerCube skybox; // The cubemap is a uniform!
void main() {
color = texture(skybox, texDirection); // Get the pixel in direction of texDirection!
}