Support me!
If you enjoy these webpages and you want to show your gratitude, feel free to support me in anyway!
Like Me On Facebook! Megabyte Softworks Facebook
Like Me On Facebook! Megabyte Softworks Patreon
Donate $1
Donate $2
Donate $5
Donate $10
Donate Custom Amount
10.) Skybox
<< back to OpenGL 3 series

Welcome to the 10th OpenGL 3.3 tutorial. This time we are going to discuss a simple, but powerful effect, that adds realism to our scene - skybox. No more single color backgrounds, this time we'll have nice skies and mountains in the background! So let's get right into the topic.

Skybox

For those of you that don't know what a skybox is - it's nothing but a big box that's around our world and has some textures of skies and mountains mapped onto it. These textures are seamless, so you don't see any box edges or anything and the whole thing will look as one continuous sky. We don't need any new OpenGL knowledge, but some implementation details of how to add skybox to the world will be useful. But first, let's have a look at single skybox, so that you have an idea what it looks like:

As you can see, skybox is just a textured cube and when we unfold its faces, we will get such a shape, as if we wanted to cut out a cube from the paper and then fold it. This idea is very simle, but yet very powerful. As usual, we will create a class for skybox, to have everything we need in one place:

class CSkybox
{
public:
	void loadSkybox(string a_sDirectory, string a_sFront, string a_sBack, string a_sLeft, string a_sRight, string a_sTop, string a_sBottom);
	void renderSkybox();

	void releaseSkybox();
private:
	UINT uiVAO;
	CVertexBufferObject vboRenderData;
	CTexture tTextures[6];
	string sDirectory;
	string sFront, sBack, sLeft, sRight, sTop, sBottom;
};

We can briefly have a look at load function:

void CSkybox::loadSkybox(string a_sDirectory, string a_sFront, string a_sBack, string a_sLeft, string a_sRight, string a_sTop, string a_sBottom)
{
	tTextures[0].loadTexture2D(a_sDirectory+a_sFront);
	tTextures[1].loadTexture2D(a_sDirectory+a_sBack);
	tTextures[2].loadTexture2D(a_sDirectory+a_sLeft);
	tTextures[3].loadTexture2D(a_sDirectory+a_sRight);
	tTextures[4].loadTexture2D(a_sDirectory+a_sTop);
	tTextures[5].loadTexture2D(a_sDirectory+a_sBottom);

	sDirectory = a_sDirectory;

	sFront = a_sFront;
	sBack = a_sBack;
	sLeft = a_sLeft;
	sRight = a_sRight;
	sTop = a_sTop;
	sBottom = a_sBottom;

	FOR(i, 6)
	{
		tTextures[i].setFiltering(TEXTURE_FILTER_MAG_BILINEAR, TEXTURE_FILTER_MIN_BILINEAR);
		tTextures[i].setSamplerParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		tTextures[i].setSamplerParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

	glGenVertexArrays(1, &uiVAO);
	glBindVertexArray(uiVAO);

	vboRenderData.createVBO();
	vboRenderData.bindVBO();

	// Proceed with VBO creation...
}

What we do is load 6 textures - front, back, left, right, top and bottom texture, then we create a rendering VBO for the skybox, and we're done loading. Additionaly, we set texture wrapping parameters to GL_CLAMP_TO_EDGE. Without setting it we would be able to see edges of the box in the sky, and it doesn't help realism much . More interesting part is rendering. This will also be the only trickier thing in this tutorial (as I said, there's nothing difficult this time). Let's have a look at it:

void CSkybox::renderSkybox()
{
	glDepthMask(0);
	glBindVertexArray(uiVAO);
	FOR(i, 6)
	{
		tTextures[i].bindTexture();
		glDrawArrays(GL_TRIANGLE_STRIP, i*4, 4);
	}
	glDepthMask(1);
}

This may require a little explanation. As I said, we want the skybox to surround us, so it must be big enough. But what value is big enough? 200? 1000? Far clipping plane distance ? Maybe some of these is enough, but there is more elegant solution and it's this: Skybox will be rendered before everything else, but with depth buffer writing disabled (glDepthMask(0) does just that). What shall we achieve with this? With the first thing rendered, we can be sure, that the box will pass depth tests, because it's the first thing rendered and it's size isn't too big (it's 50.0 in our case). With depth buffer writing disabled, the cube will get rendered, but the depth values will remain in depth buffer, as if nothing was rendered, so practically we just change colors in framebuffer before whole scene, and then we start rendering scene. And actually, it doesn't matter which constant we use as size of skybox, I went for 50.0, but you can try changing it to see that really nothing happens. And the last thing we must do before rendering skybox is to translate it to position of camera, so that it moves with us and we cannot escape it now. After rendering, don't forget to restore writing to depth buffer (glDepthMask(1)). That's absolutely all you need to know for basic skybox.

Conclusion

Result is nice, it adds a real feel to the scene - no more single colored backgrounds!

Some things to be considered - when rendering skybox, you probably don't want to use directional light or any lighting on it, maybe just some simple color modulation depending on time of the day. So it would be probably better to create another shader program for skybox, or generally for rendering in 3D without lighting with color modulation. But I was lazy and I rather set ambient intensity of skybox to 1.0, so that I don't have to do it . The scene is just a pile of boxes, and one interesting object made from 3 tori . Oh, and another thing - starting from this tutorial, the application data (textures, shaders etc...) will only be in the root directory of tutorial (by now, they were copied in the root, so that you could run tutorial right away, and second copy was in source directory, so that after compilation you can run it). Anyway, after compilation you still had to copy DLLs to debug directory in order to run tutorial, so it's a waste of space to copy this data twice, especially now, when their amount is getting bigger each tutorial. So just copy DLLs and data yourself to proper place and you're good to modify code and learn something .

And that's all for today! This tutorial was probably the shortest so far, I hope you enjoyed it. Took me a little longer to write, it was because of duties in my work. I'm not sure what next tutorial will be, so I let it to be a surprise and I hope I will write it in reasonable small time, like one week .

Download 2.12 MB (11366 downloads)