![]() | ![]() | ![]() |
|
Geometry© Justin Couch 1999Now that you have a basic handle on what comprises the major portions of a scene graph, it is time to move onto the useful bits - creating objects that you can see on screen. In a word: Geometry. Geometry consists of a collection of points in 3D space. As seen in earlier parts of the tutorial, this 3D space may occupy one of several different roles such as world space or display space. While a collection of 3D dots in space may be a useful form of visualisation technique for your data, it is not the most common mechanism. To make the objects look solid, we then form a relationship between these points to produce a surface. Combine a number of these surfaces together, throw a splash of colour about, and you end up with a solid looking 3D object on the screen. BranchGroupsOne offshoot of capabilities is the effect it has on grouping nodes in particular. The idea of a group is to bring together related sub-graphs. In a lot of visualisation type applications, you want to be constantly adding and removing items from these groups.
It has been mentioned several times already that
Apart from the obvious option to be able to compile a scene graph, the branch group also does a number of other optimisation and handling functions for user input handling. The various pickX methods allow you to deal with pointer input and selection of objects. These will be covered in the later chapter of Chapter 7 Navigation and Chapter 8 User feedback. Picking may also be used for much more that just user input too. When you compile a scene graph, the only point that you can guarantee will always remain the same is the branch group. It does not contain any information itself, but holds all of the information about its children. Thus, when you want to remove a part of the scene graph, you can take a single compiled and optimised chunk in a single hit. There are no problems about having to decompile the scene graph just to remove a portion of it and then recompile it again afterwards. Removing a branch group causes minimal interruption to the rendering process. One interesting part of this is the observation that a branch group will contain other branch groups as children. Thus, all through the scene graph will be little collection points of optimisations. Because you've probably lost the parent node of the branch group during the compilation, you may not be able to directly remove the branch group at a later date. Since you will probably be keeping around references to branch groups (you might be wanting to remove one or more of them) you would need to keep around references to their parent objects as well. These parent objects, under compilation may or may not exist under the hood. To alleviate this problem, a detach method is provided. Calling this automatically removes the branch group from its parent object.
Geometry ArraysBefore moving onto building up your own pieces of geometry, you first need to understand how their most basic component, theGeometryArray works. The GeometryArray class
is the base of the different attributes that need 2D or 3D coordinates
to represent them. That is, everything in Java 3D geometry. A geometry
array performs the following tasks:
A single geometry array instance represents a single piece of geometry and contains at least one of the attributes mentioned above. At all times it must include the coordinates, then other flags in the constructor allow you to add other values for each coordinate.
Geometry arrays are an abstract class, so you can't create one directly.
Instead, you will need to use one of the derived classes like
IndexedQuadArray . The
following code would be used.
int flags = GeometryArray.COORDINATES | GeometryArray.COLOR_4 | GeometryArray.NORMALS; IndexedQuadArray geom = new IndexedQuadArray(4, flags, 4);You will note that the first argument is the number four. This is because we know that we need 4 vertices to describe a flat square. You always need to provide a number indicating the number of vertices in the object when you create a geometry array. After creating the basic array, we need to fill it with some data. First, the coordinates. Since we are dealing with a simple object, we'll declare all the points in a single hit as an array of floats. double[] coordinates = { 0.5, 0.5, 0, 0.5, -0.5, 0, -0.5, -0.5, 0, -0.5, 0.5, 0 }; int[] indices = { 0, 1, 2, 3 }; geom.setCoordinates(0, coordinates); geom.setCoordinateIndices(0, indices);Note that we've declared the coordinates in a clockwise fashion, in order. Like most of the geometry arrays, the final derived classes make assumptions about the ordering of the vertices that you've given the base class. We need to explicitly set them using the last line. It is much easier to make the match up between the two arrays if you keep the coordinate declarations in a nice, logical order. The next step in building our flat square is to give the object some color at each corner. Colors follow the same pattern for the coordinates. First declare an array of the values, the indices and then use the appropriate set method. We can reuse the indices array from the first set of coordinates to make life easy for ourselves. The only gotcha to remember here is that we have specified four components for each color. float[] colors = { 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 }; geom.setColors(0, colors); geom.setColorIndices(0, indices);Finally, we add the finishing touches by declaring normals for each vertex. For this simple example, we declare them all to be pointing directly up (along the Z axis). Normals should always be normalised too. This time, an alternative approach is taken: float[] normal = { 0, 0, 1 }; geom.setNormal(0, normal); geom.setNormal(1, normal); geom.setNormal(2, normal); geom.setNormal(3, normal);which results in all for vertices all having the same normal direction.
That is your basic Shape3D shape = new Shape3D(geom); branch_group.addChild(shape); Customised GeometryBuilding a basic square is a relatively trivial exercise. When it comes to more complex items like a car engine block, you need to start thinking much more carefully about how you are going to create it in terms of Java3D's node structure.The major decision to make is how far down the object chain of derived classes do you go? For a complex object like the engine block, a standard quadarray probably wouldn't be sufficient. Instead, you might want an object that is represented by a parametric surface like NURBS or quadratics that are custom built from parameters rather than pure coordinates. Building primitive objects like cubes, spheres and similar fixed shaped objects it is usually preferable to extend or just use one of the indexed base classes. It is typical that these sorts of objects directly extend one of the grouping classes and then build the geometry internally in one or more shape nodes.
When you have an object whose shape is not directly determinable at
creation time, it is usually easier to extend the basic
AppearanceIf you supplied just the basic geometry array, with no vertex colors specified, to theShape3D class, you end up with a default
appearance - a mid-greyish plastic looking object. The idea of the
Appearance class is to provide global information about a
particular shape. When you set an appearance, it effects all of the
shape.
Before we even dig into the
Color settings are only part of the function performed by the
appearance. The
Code ImplementationNow we need to relate this to the code example that we are building up for this chapter. The geometry is contained in a class calledExampleGeometry . This class extends Shape3D so
that we can keep it all clean. It looks something like this:
public class ExampleGeometry extends Shape3D { private IndexedQuadArray geom; private Appearance appearance; private Texture texture; public ExampleGeometry() { constructGeometry(); constructAppearance(); } private void constructGeometry() { } private void constructAppearance() { } }Inside the constructGeometry() method, we perform the steps of
creating the IndexedQuadArray that you saw earlier in the chapter.
The final step of the method is to add the quad array to the class:
addGeometry(geom);rather than adding it to a separate class.
Back in the main window class, we can now add some code to the
private void constructWorld() { // create the basic universe universe = new UniverseManager(); ExampleGeometry geom = new ExampleGeometry(); universe.addWorldObject(geom); } |
|