These notes assume you are loading the skybox from a file. There is one available here for you to download: Skybox.rar. This is a .x file in text format so you can edit the texture names to use different skybox textures. Plenty of these are available on the Internet and quite a few in my T2 program.
The skybox is defined in the x file as a cube with its insides textured with the sky and some sea. A skybox can therefore be loaded in exactly the same way as other models (see XNA Models ). The difference in implementation comes in the render function only.
We want our skybox to always appear in the distance, therefore it should always be the same distance from the camera. For this reason you can think of the skybox as being a box positioned over the viewers head. So when we come to render the skybox we need to position the viewer to be bang in the centre of the box. As we know from the XNA Matrices notes this information is held in the view matrix.
The view matrix is set each time the camera moves so when we come to render our skybox we need to:
To position the view matrix at 0,0,0 we can directly modify our current view matrix like so:
viewMatrix.M41=0;
viewMatrix.M42=0;
viewMatrix.M43=0;
The second value can be altered to change the y horizon position of the skybox. Note though that this is not a simple y value. Experimentation works well here.
When rendering the skybox we know it is the most distant thing we will draw so we could disable the depth buffer checks and also the depth buffer writes (see also the advanced note below). Note that disabling depth buffer checks only works if we draw the skybox first. We also do not want the skybox to be lit (its textures encode lighting), so we turn lighting off. A further issue is that we want our textures to be clamped to the internal box rather than wrapped else a seam will appear. We must remember to enable these things after we have finished rendering our skybox, to disable them:
// Turn off Z buffer and also change texture wrapping
Device.RenderState.DepthBufferWriteEnable = false;
Device.RenderState.DepthBufferEnable = false;
Device.SamplerStates[0].AddressU = TextureAddressMode.Clamp;
Device.SamplerStates[0].AddressV = TextureAddressMode.Clamp;
It may seem best to simply render the skybox first and then the rest of the world, however if your game is fill rate limited (the time taken to draw to the screen is the limiting factor) it might be better to draw it last. If drawing last you will need to keep the depth buffer tests but not the depth buffer writes. By drawing it last only the visible parts will be drawn saving your fill rate. This is only an optimisation if you are fill rate limited so you need to do some timing tests before trying this.