I've now added a Skybox facility. This was quite a simple modification in that the Skybox is just a large cube with inward facing textured sides. The key difference between the Skybox object and all other objects in the scene is that the Skybox does not translate with the rest of the scene, i.e. does not move relative to the camera. However, it does rotate with the camera. In this way the distance between camera/player and Skybox is pretty much constant (allowing for rotation) and the illusion is of far away scenery within the current world space. As with previous demos, use the cursor keys to move and 'a' to jump. Try climbing to the top of the tower for a better view.
Within the 'objectfactory' class I've defined a new 'skybox' object type, which requires a dimension and six materials/textures to use for the inward facing sides. The dimension should be a value large enough to place the Skybox beyond other scene objects but still within the far clipping distance.
public static nw3d_object Skybox(double d, nw3d_material front, nw3d_material back, nw3d_material left, nw3d_material right, nw3d_material top, nw3d_material bottom) {
double hd=d/2;
nw3d_object obj = new nw3d_object();
//The cuboid has 24 vertices (non shared)
obj.addTexVert(-hd, hd,-hd,1,0);
obj.addTexVert( hd, hd,-hd,0,0);
obj.addTexVert( hd,-hd,-hd,0,1);
obj.addTexVert(-hd,-hd,-hd,1,1);
obj.addTexVert( hd, hd,-hd,1,0);
obj.addTexVert( hd, hd, hd,0,0);
obj.addTexVert( hd,-hd, hd,0,1);
obj.addTexVert( hd,-hd,-hd,1,1);
obj.addTexVert(-hd, hd, hd,0,0);
obj.addTexVert( hd, hd, hd,1,0);
obj.addTexVert( hd,-hd, hd,1,1);
obj.addTexVert(-hd,-hd, hd,0,1);
obj.addTexVert(-hd, hd,-hd,0,0);
obj.addTexVert(-hd, hd, hd,1,0);
obj.addTexVert(-hd,-hd, hd,1,1);
obj.addTexVert(-hd,-hd,-hd,0,1);
obj.addTexVert(-hd, hd, hd,0,1);
obj.addTexVert( hd, hd, hd,1,1);
obj.addTexVert( hd, hd,-hd,1,0);
obj.addTexVert(-hd, hd,-hd,0,0);
obj.addTexVert(-hd,-hd, hd,0,0);
obj.addTexVert( hd,-hd, hd,1,0);
obj.addTexVert( hd,-hd,-hd,1,1);
obj.addTexVert(-hd,-hd,-hd,0,1);
//6 sides, 12 triangles, wound clockwise
obj.addTriMat(2,3,0,1); //Back
obj.addTriMat(1,2,0,1); //Back
obj.addTriMat(6,7,4,3); //Right
obj.addTriMat(5,6,4,3); //Right
obj.addTriMat(11,10,9,0); //Front
obj.addTriMat(8,11,9,0); //Front
obj.addTriMat(15,14,13,2); //Left
obj.addTriMat(12,15,13,2); //Left
obj.addTriMat(18,19,16,4); //Top
obj.addTriMat(17,18,16,4); //Top
obj.addTriMat(21,20,23,5); //Bottom
obj.addTriMat(22,21,23,5); //Bottom
//6 materials
obj.addMat(front);
obj.addMat(back);
obj.addMat(left);
obj.addMat(right);
obj.addMat(top);
obj.addMat(bottom);
obj.VertNorms(true); //shared vertex normals for smooth join
obj.Centroid();
return obj;
}
The Skybox object is identified and treat differently by the scene class through addition of the following entries.
public boolean skyboxUsed;
public int skyboxObject;
An 'addSkybox' method has also been added.
public void addSkybox(int d, nw3d_material front, nw3d_material back,
nw3d_material left, nw3d_material right,
nw3d_material top, nw3d_material bottom) {
addObj(nw3d_objectfactory.Skybox(d, front, back, left, right, top, bottom));
skyboxUsed = true;
skyboxObject = o.length-1;
}
Finally, a condition is added to the scene translation method to ensure that the Skybox does not move.
for (int i = o.length; --i>=0;) {
if (!(skyboxUsed && skyboxObject == i)) o[i].Translate(x,y,z);
}
I'm rendering the Skybox last in order to minimise overdraw and take advantage of an early z-check exit within the render loop. At the moment ensuring that the Skybox is drawn last is simply down to it always being the last object created within the scene, so not ideal.
loadMap("map2.txt");
scene.addSkybox(400, front, back, left, right, top, bottom);
Despite this, I've recorded a c.30% reduction in frame rate with Skybox enabled, so some further optimisation is needed!