So, we have created a basic shape and believe it or not, that is quite a step towards creating a more complicated shape. That doesn’t sound as surprising as I thought it was going to. Anyway, next we are going to extend our shape that we created to make something that is loosely approximate to scenery. I’m not about to introduce you to terrain generation, largely because I’m a long way from mastering that myself, but we can whip up a slightly random shape that will then be the “landscape”our character walks on.
I am basing this on a piece of work I did a while ago for a project that needed us to be able to see a house in a plot of land. The part the house was on needed to be flat but I wanted some variety in the landscape at the edges. This proves to be a very convenient for our purposes and it gives us a chance to take a look at some more complex geometry and some basic texture mapping.
Just like OurShape2D the SimpleLand extends Shape3D and does all it’s work in the creation clause. Basically, it takes a length, a width and a url as it’s parameters and creates a rectangle length*width which is divided into 5 sub-rectangles to form a grid. I did this because light falls uniformly on any face –if the house was between you and the light source and the ground was lit as brightly behind the house as in front, that looked a little bit odd, so I broke it up to allow some variety in shading across the flat surface.
Around the flat grid is another strip, the same width as the ones in the grid which has random y values, making it bumpy and creating the crinkled “landscape”type effect I was looking for. When I say “landscape”I could probably more accurately say “crumpled up piece of paper”.
So, without further
ado, lets take a look at the code:
Most of this should be fairly obvious: we are initialising our length and width units according to the size of the grid (dividing by 4 because our first value is zero) and loading them into the xPoints and yPoints arrays. The pts array is 144 long because although we only have 49 points marking out 36 squares we need to separate out the vertices for each one, which gives us 36 * 4 points total. The texts array is an array of texture co-ordinates, we have two co-ordinates for every point of every square, but it is fairly simple to build. Edge size sets the distance from the edge of the defined flat grid to the edge of our shape. Next we create and populate our grid:
int moderator=2;This looks quite complicated but actually it is reasonably simple to understand. The moderator is just a number I multiply the random number by to make the scene a little steeper and more interesting- higher values will make steeper edges to the scene. We load the 20 (enough to go around the outside of the grid) values that we have created into the zlist array. This will be the position on the z axis of the edge points.
Next up we loop across the top line setting the x and y points to their respective values and taking every z value from the zlist. We go through the next four rows just adding the unusual z values at beginning and end and then in the final row we once again take all z values from the zlist to make our last crinkly edge. That has defined our grid of point3d[] objects so now we can simply load them into the points array and away we go:
for (int i=0;i<6;i++)This should all be fairly familiar to you by now from the previous exercise, the only other part being the setting up of texture co-ordinates. Because we have a standard square we are texturing we simply mark each corner of the square with a corner of the texture so corner 0 is at (0, 0) on the texture and so on. This is followed by the standard creation of geometry from the last exercise:
GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);The only difference is that we are setting the texture coordinate parameters ( we have 1 set if textures and they are 2 dimensional) and then the textureCoordinates themselves are added to the geometry (the zero indicates they belong to the first set.)
The next bit is new, and this is where we describe the appearance of our shape and apply a texture.
The start of this is very similar to what we have done before but this time we create a default material and set different properties of it. It’s all fairly self explanatory anyway so we’ll get onto the next part.
This is to load our Texture file and apply it to the material. TextureLoader does most of the work for us, loading the texture up from file. The texture image must have sides that are a power of two ( 64 * 64, 32 * 32, 64 * 32 and so on) for this to work correctly. We then create a new Texture2D from the TextureLoader and create a TextureAttributes to describe it. The important thing about this is that we are using the “TextureAttributes.BLEND”mode that will blend the colours of the Texture with the colours of the underlying Shape. We want to use this because it is the only mode that will allow our textured shape to be lit- otherwise it just lies over the object and replaces the colour altogether. We need the try –catch statement because if “texture”is not a good url TextureLoader could fail. If the image is the wrong size the Texture2D creation will fail anyway but that is a bit less of a common occurrence. That concludes the creation of our SimpleLand object so lets adapt our simple applet to a slightly different simple applet that will let us look at this shape.
The ShowLand applet is basically the same as the StartHere one we looked at before, but the createSceneGraph method is a little different:
We create the root BranchGroup as before but this time we have to find a path to the texture we are looking for- I am using the user directory and assuming that you are running the program from the directory that contains the class file and that the texture is called “stone.jpg”and is in the same directory. This is also a bit Windows-Centric of me - on Linux (and probably other *nix type environments) you don't need the "file://localhost" part of the path. The same applies for any other file paths throughout this tutorial.
If you run it out of Forte (or Sun One Studio or whatever they call it these days) and probably out of other IDEs it will take the user directory of the ide and not work properly unless you hardcode the location of the file.
Next up I create a new SimpleLand object 10 by 10 metres. I create the ambient light as I did before but now I am adding a DirectionalLight as well. This has a colour and a direction of shine vector and it behaves a lot like sunlight, lighting everything uniformly from the same direction. We don’t do any appearance handling here because the SimpleLand is doing that for us. After that we just have to change “main”to create a ShowLand and we are away- a little slightly ruffled landscape to look at. You may find that you need to move the camera about to get a decent view of everything, but the OrbitBehaviour makes this fairly easy to do. Eventually, you should have something looking a bit like this:

Previous: Creating The Scene | Back to the Index | Next: Importing A Model