OpenGL Skybox Rendering

If you have ever played any polished game where there is specular reflections of the game world, it was probably implemented with environment maps.  An environment map can be implemented as a 6 textures mapped to the inner surface of a cube at infinity distance centered on the object being rendered.

Cube maps are handy for creating things like image based lighting and reflection. Each face of the cube map covers a 90 degree field of view both vertically and horizontally.

cube_map

Loading in the cub map faces.

After setting up a Vertex array object and vertex buffer object to render a cube. You will need to load in 6 textures that will make up a cube map. I used the SOIL image library to load in my 6 images that make up the skybox cube map

GLuint loadCubemap(std::vector<const GLchar*> faces)
{
	GLuint textureID;
	glGenTextures(1, &textureID);

	int width, height;
	unsigned char* image;

	glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
	for (int i = 0; i < faces.size(); i++)
	{
		image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
		SOIL_free_image_data(image);
	}
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

	return textureID;
}

Inside the loop iterating you when specifying the target for glTexImage2D you can see that GL_TEXTURE_CUBE_POSITIVE_X is being incremented by i, since OpenGL defines it’s target as hex numbers like:

#define GL_TEXTURE_CUBE_MAP_POSITIVE_X   0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y   0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z   0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A

You can simply increment it by the iterator counter which will get the next cube map face.

gl

Shaders for the sky box.

We can calculate a reflection vector to sample the cube map when the camera (viewer) looks at the model surface from an angle. A reflection vector is calculated as below:

image

GLSL has a built in function for reflect a vector, you can view it here: Link

To read the environment map texel that will correspond to the point on the surface of the object we take the incident vector from the camera to the point on the surface of the object and it reflect it around the normal of that point. The value of the texture coordinate is found when the reflection vector intersect the cube map. This texture coordinate can be used to access the individall face texture of the cubemap.

Fragment Shader

#version 330 core
in vec3 Normal;
in vec3 Position;
out vec4 color;

uniform vec3 cameraPos;
uniform samplerCube skybox;

void main()
{             
    vec3 I = normalize(Position - cameraPos);
    vec3 R = reflect(I, normalize(Normal));
    color = texture(skybox, R);
}

Vertex Shader

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

out vec3 Normal;
out vec3 Position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
    Normal = mat3(transpose(inverse(model))) * normal;
    Position = vec3(model * vec4(position, 1.0f));
} 

I have been working on learning a lot about OpenGL lately and this is one thing i have learned so far. I plan of making a tech demo like i did for my physics engine. With lighting, shadows, model loading and other goodies.

Reflections

Dynamic environment maps

I haven’t done Dynamic environment cube maps yet but i have mess around with frame buffers enough that when you could render the scene 6 times from the perspective of the Utah tea pot, in this case, and make sure the filed of view is 90 degrees to create a cube map.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s