Sky Box
From GDWiki
A skybox is a trick used in 3d graphics to display a horizon (or other far-away stuff) without rendering enormous amounts of geometry. A box (cube) is rendered around the camera with a texture that contains the far-away scene. Then the other stuff is drawn over that, obscuring the parts that should not be visible. Sometimes no box is used, but some other shape. Sky domes (half sphere) and half skyboxes can be used if you know for sure that 'ground-geometry' will obscure the lower part of the world at all times. In typical outdoor scenes you do not have to worry about the player looking down and seeing the sky, so there's no point of rendering a sky below him or her.
I won't go into skydomes here, and half skyboxes are very similar to normal sky boxes. There are a number of things you should understand to implement a regular skybox. I'll use some OpenGL code here and there, but everything will also be described in English.
Contents |
[edit] Textures
The textures used on the skybox have to fit together to create the illusion of a continuous world. If you are drawing this or using photos, you're up for a challenge (although it might be possible to find some free skyboxes online). The 6 textures (one for each face of the cube) have to represent the world as seen through a camera with a 90° camera looking in that direction. That means the camera's view cone has a square base and straight angles at the top. In OpenGL you specify the camera like this:
glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(1, -1, -1, 1, 1, far_z_plane); glMatrixMode(GL_MODELVIEW);
Where far_z_plane is the distance from the camera at which stuff gets clipped, which is specific to an application. You'll also have to set up a square viewport (glViewPort in OpenGL) After setting up a camera and viewport you point it in the direction of the side of the cube you want to create a texture for and render the 'far-away scene'. Then load the current viewport into a texture (in OpenGL you use glCopyTexImage2D for this) and store it. Repeat this for all of the six sides of the cube. Make sure you use a consistent orientation for each of these (which side is 'up') so you can draw them in the correct orientation again later.
Another issue is the texture size. Fortunately graphics cards have quite a lot of memory these days and allow big textures, but if you want your application to work with old cards you'll be stuck with a maximum of 256x256, which looks grainy at most screen resolutions. Remember the texture will be stretched out over most of the screen, so the difference between the view size and the texture size will result in stretching, which gives a blurry effect. Fortunately, this does not look too bad as long as it is not too strong. Things in the distance often look hazy in real life.
[edit] Displaying the sky box
If you have 6 textures, either by rendering them yourself or from some other source, you can use the skybox to create a sky (or starfield, or psychedelic background, or whatever). There are some things to keep in mind here.
Firstly, you have to make sure the skybox does not obscure the other geometry. A good way to do this is to start by drawing the skybox, and then draw the other stuff. When you draw the skybox, you make sure z-writing is off (glDepthMask). Then you turn z-writing back on and draw your scene. A disadvantage of this is overdraw - first you fill the screen with skybox and then you draw other stuff over it. Drawing the skybox after the scene, using the z-buffer to prevent the skybox from obscuring the scene solves this, but you have to make sure that you draw the skybox further away than anything in the scene (or fiddle with the z-pass-function).
Since the skybox will not write to the z-buffer it does not matter where you put it, as long as it is between the near and far clip planes. A box with a rib length of 5 will work fine. When drawing the sides make sure the correct texture is on the right side and the correct side of the texture is up.
Typically, the skybox moves along with the camera. This means the sky will not get any closer or further away as the camera moves. This usually works, you don't see the moon getting any closer when you walk towards it. If you have stuff in your skybox that is not quite as far away as the moon and the horizon this can look weird though. Another approach is to have a real huge skybox drawn at a fixed position, this might work for some situations, but then you have to be very careful about stuff going outside of the skybox.
[edit] C++ SkyBox Source Code
Hi, my name is Dawid and here is the source code I use for my OpenGL application. This may not be the best way to do it but when rendering 6 quads optimization is not an issue.
/************************************************************************/ /* Render a skybox with center point position and dimension sizes size */ /************************************************************************/ void RenderSkybox(CVector3 position,CVector3 size,unsigned int *SkyBox) { // djoubert187 _at_ hotmail.com // Begin DrawSkybox glColor4f(1.0, 1.0, 1.0,1.0f); // Save Current Matrix glPushMatrix(); // Second Move the render space to the correct position (Translate) glTranslatef(position.x,position.y,position.z); // First apply scale matrix glScalef(size.x,size.y,size.z); float cz = -0.0f,cx = 1.0f; float r = 1.0f; // If you have border issues change this to 1.005f // Common Axis Z - FRONT Side glBindTexture(GL_TEXTURE_2D,SkyBox[4]); glBegin(GL_QUADS); glTexCoord2f(cx, cz); glVertex3f(-r ,1.0f,-r); glTexCoord2f(cx, cx); glVertex3f(-r,1.0f,r); glTexCoord2f(cz, cx); glVertex3f( r,1.0f,r); glTexCoord2f(cz, cz); glVertex3f( r ,1.0f,-r); glEnd(); // Common Axis Z - BACK side glBindTexture(GL_TEXTURE_2D,SkyBox[5]); glBegin(GL_QUADS); glTexCoord2f(cx,cz); glVertex3f(-r,-1.0f,-r); glTexCoord2f(cx,cx); glVertex3f(-r,-1.0f, r); glTexCoord2f(cz,cx); glVertex3f( r,-1.0f, r); glTexCoord2f(cz,cz); glVertex3f( r,-1.0f,-r); glEnd(); // Common Axis X - Left side glBindTexture(GL_TEXTURE_2D,SkyBox[3]); glBegin(GL_QUADS); glTexCoord2f(cx,cx); glVertex3f(-1.0f, -r, r); glTexCoord2f(cz,cx); glVertex3f(-1.0f, r, r); glTexCoord2f(cz,cz); glVertex3f(-1.0f, r,-r); glTexCoord2f(cx,cz); glVertex3f(-1.0f, -r,-r); glEnd(); // Common Axis X - Right side glBindTexture(GL_TEXTURE_2D,SkyBox[2]); glBegin(GL_QUADS); glTexCoord2f( cx,cx); glVertex3f(1.0f, -r, r); glTexCoord2f(cz, cx); glVertex3f(1.0f, r, r); glTexCoord2f(cz, cz); glVertex3f(1.0f, r,-r); glTexCoord2f(cx, cz); glVertex3f(1.0f, -r,-r); glEnd(); // Common Axis Y - Draw Up side glBindTexture(GL_TEXTURE_2D,SkyBox[0]); glBegin(GL_QUADS); glTexCoord2f(cz, cz); glVertex3f( r, -r,1.0f); glTexCoord2f(cx, cz); glVertex3f( r, r,1.0f); glTexCoord2f(cx, cx); glVertex3f(-r, r,1.0f); glTexCoord2f(cz, cx); glVertex3f(-r, -r,1.0f); glEnd(); // Common Axis Y - Down side glBindTexture(GL_TEXTURE_2D,SkyBox[1]); glBegin(GL_QUADS); glTexCoord2f(cz,cz); glVertex3f( r, -r,-1.0f); glTexCoord2f( cx,cz); glVertex3f( r, r,-1.0f); glTexCoord2f( cx,cx); glVertex3f(-r, r,-1.0f); glTexCoord2f(cz, cx); glVertex3f(-r, -r,-1.0f); glEnd(); // Load Saved Matrix glPopMatrix(); };

