An Overview of Loader3D


Adjusting a Model's Shape Attributes

After reporting on the model's scene graph, WrapLoaderInfo3D's last task is to modify the model's appearance according to the user's supplied adaptation number. Many aspects of a model can be easily changed once its individual Shape3D nodes are accessible. This

Figure 16-9. The dolphins modeldD


can be done with a variant of the examineNode( ) pseudocode, concentrating only on Leaf nodes that are Shape3Ds:

     visitNode(node) {       if the node is a Group {         for each child of the node           visitNode(child);  // recursive call       }       else if the node is a Shape3D          adjust the node's attributes;     }

This pseudocode is the basis of visitNode( ) in WrapLoaderInfo3D.

The manipulation of the shape's attributes is initiated in adjustShape3D( ), which uses the adaptation number entered by the user to choose between six possibilities:

0 Makes the shape blue with makeBlue( )

1 Draws the shape in outline with drawOutline( )

2 Renders the shape almost transparent with makeAlmostTransparent( )

3 Lays a texture over the shape with addTexture( )

4 Makes the shape blue and adds a texture by calling makeBlue( ) and addTexture( )


Anything else

Makes no changes at all

Turning the Shape Blue

Figure 16-10 shows the rendering of the dolphins model after being turned blue.

Figure 16-10. Blue dolphins


The Material node used in makeBlue( ) is:

     Material blueMat = new Material(black, black, blue, white, 20.0f);

The use of black as the ambient color (Color3f(0.0f, 0.0f, 0.0f)) means unlit parts of the shape are rendered in black, which looks like shadow on the model. However, the model doesn't cast shadows onto other surfaces, such as the floor:

     private void makeBlue(Shape3D shape)     {       Appearance app = shape.getAppearance( );       Material blueMat = new Material(black, black, blue, white, 20.0f);       blueMat.setLightingEnable(true);       app.setMaterial(blueMat);       shape.setAppearance(app);     }

The appearance is obtained from the shape, its material attribute changed, and then the appearance component assigned back to the shape; only the attribute of interest is modified.

Drawing a Shape in Outline

Figure 16-11 shows a VRML model of a box, cone, and sphere rendered in outline:

Figure 16-11. Shapes in outline


The original colors of the three objects (yellow, red, blue) are still visible in their line colors.


The effect is achieved by setting the POLYGON_LINE mode in PolygonAttribute in drawOutline( ):

     private void drawOutline(Shape3D shape)     {       Appearance app = shape.getAppearance( );       PolygonAttributes pa = new PolygonAttributes( );       pa.setCullFace( PolygonAttributes.CULL_NONE );       pa.setPolygonMode( PolygonAttributes.POLYGON_LINE );       app.setPolygonAttributes( pa );       shape.setAppearance(app);     }

Culling is disabled so that the lines are visible from every direction.


Making a Shape Almost Transparent

Figure 16-12 shows a model of the gun rendered almost transparent.

This is done in makeAlmostTransparent( ) by setting the transparencyAttributes of the shape's Appearance:

     private void makeAlmostTransparent(Shape3D shape)     {       Appearance app = shape.getAppearance( );

Figure 16-12. Semi-transparent gun


       TransparencyAttributes ta = new TransparencyAttributes( );       ta.setTransparencyMode( TransparencyAttributes.BLENDED );       ta.setTransparency(0.8f);     // 1.0f is totally transparent       app.setTransparencyAttributes( ta );       shape.setAppearance(app);     }

Various transparency mode settings affect how the original color of the shape is mixed with the background pixels. For example, blended transparency (used here) mixes the color of the transparent shape with the color of the background pixels. Screen door transparency (transparencyAttributes.SCREEN_DOOR) renders a mesh-like pattern of pixels with the color of the transparent shape, leaving gaps where the background pixels show through. More details can be found in the documentation for the transparencyAttributes class.

A comparison of the last three examples shows the general strategy for manipulating a shape: create an attribute setting, and add it to the existing Appearance component of the shape.

Adding a Texture to a Shape

Figure 16-13 shows a castle with a rock texture wrapped over it.

A quick look at Figure 16-13 reveals some of the texturing is unrealistic: clear stripes of textures run down the walls. Once you understand how the texture is mapped, the reasons for this striping will be clear.

Figure 16-13. Castle rock


A texture is made in two stages. First, a TextureLoader object is created for the file holding the texture image, then the texture is extracted from the object:

     private Texture2D texture = null;  // global     private void loadTexture(String fn)     {       TextureLoader texLoader = new TextureLoader(fn, null);       texture = (Texture2D) texLoader.getTexture( );       if (texture == null)         System.out.println("Cannot load texture from " + fn);       else {         System.out.println("Loaded texture from " + fn);         texture.setEnable(true);       }     }

The call to setEnable( ) switches on texture mapping, which allows the texture to be wrapped around a shape.

TextureLoader can handle JPEGs and GIFs (which are useful if transparency is required), and it can be employed in conjunction with Java Advanced Imaging (JAI) to load other formats, such as BMP, PNG, and TIFF files. The loader can include various flags, such as one for creating textures at various levels of resolution for rendering onto small areas. Aside from Textures, the loader can return ImageComponent2D objects, the Java 3D format for images used in backgrounds and rasters.

Textures can be 2D (as shown here) or 3D: Texture3D objects are employed for volumetric textures, typically in scientific applications and visualization.

The if test in loadTexture( ) checks if the texture was successfully created. A common reason for the texture being null is that the source image's dimensions are invalid. The image must be square, with its dimensions a power of two. Keeping this in mind, I made the rock image's size 256 x 256 pixels.

For a texture to be applied to a shape, three conditions must be met:

  • The shape must have texture coordinates, either set through its geometry or using a TexCoordGeneration object (as detailed in the next section).

  • The shape's appearance must have been assigned a Texture2D.

  • The texture must be enabled (which was done in loadTexture( )).

Texture coordinates

Texture2D coordinates are measured with (s, t) values that range between 0 and 1. Texture mapping is the art of mapping (s, t) values (sometimes called texels) onto geometry coordinates (x, y, z) to create a realistic looking effect.

One mapping approach is to tile the texture in one-by-one patches over the geometry's surface. However, tiling may create excessive repetition of the pattern, and after the geometry has been scaled down for the Java 3D world, the texture's details may be too small to see.

A more flexible mapping approach is to utilize a TexCoordGeneration object, which lets the programmer define equations stating how geometry coordinates (x, y, z) values are converted into texels (s, t). The simplest equations are linear, of these forms:

  • s = (x*planeS.xc) + (y*planeS.yc) + (z*planeS.zc) + (planeS.w)

  • t = (x*planeT.xc) + (y*planeT.yc) + (z*planeT.zc) + (planeT.w)

planeS and planeT are vectors that contain the xc, yc, zc, and w constants, which define the equations. Specifying these equations can be tricky, so I'll use a simple technique based on the bounding box for the shape.

Figure 16-14 shows a shape's bounding box, with its upper and lower points highlighted. The upper point contains the maximum x, y, and z values, and the lower point has the minima. Texture mapping becomes a matter of mapping the (x, y, z) coordinates of the box to the (s, t) coordinates of the texture.

The height and width of the bounding box is easily calculated:

  • height = ymax - ymin

  • width = xmax - xmin

Two simple equations for s and t are then given:

  • s = x/width - xmin/width

  • t = y/height - ymin/height

This is expressed in vector form:

  • planeS = [1/width, 0, 0, -xmin/width]

  • planeT = [0, 1/height, 0, -ymin/height]

Figure 16-14. From bounding box to texture


Unfortunately, the z-coordinate isn't used in the equations. I'll explain what this means in a moment.


This bounding box algorithm is implemented in stampTexCoords( ):

     private TexCoordGeneration stampTexCoords(Shape3D shape)     {       BoundingBox boundBox = new BoundingBox( shape.getBounds( ) );       Point3d lower = new Point3d( );       Point3d upper = new Point3d( );       boundBox.getLower(lower);  boundBox.getUpper(upper);       double width = upper.x - lower.x;       double height = upper.y - lower.y;       Vector4f planeS = new Vector4f( (float)(1.0/width), 0.0f, 0.0f,                                                  (float)(-lower.x/width));       Vector4f planeT = new Vector4f( 0.0f, (float)(1.0/height), 0.0f,                                                  (float)(-lower.y/height));       // generate texture coordinates       TexCoordGeneration texGen = new TexCoordGeneration( );       texGen.setPlaneS(planeS);       texGen.setPlaneT(planeT);       return texGen;     } // end of stampTexCoords( )

The (s, t) equations are encoded as two Java 3D Vector4f objects: planeS and planeT. They're used to initialize a TexCoordGeneration object, which becomes the return result of the method.

A tendency to strip

Figure 16-13 shows stripes of textures running down the castle walls. However, this orientation is due to the model being rotated 90 degrees clockwise around the x-axis. In fact, the stripes are running along the z-axis of the model.

This z-striping is the visible consequence of not using the z-coordinate in the (s, t) equations. It means that (x, y, z) coordinates with the same (x, y) value but different z-values will all map to the same (s, t) texel.

Applying the texture to the shape

The texture is applied to the shape by the addTextureGA( ) method, which has four main duties:

  • To switch off face culling so the texture appears on all sides of the shape

  • To generate a TexCoordGeneration object, using stampTexCoords( )

  • To modulate the texture mode so the underlying color and texture are combined

  • To assign the texture to the shape, done by calling setTexture( )

Here is the code:

     private void addTextureGA(Shape3D shape)     {       Appearance app = shape.getAppearance( );       // make shape two-sided, so texture appears on both sides       PolygonAttributes pa = new PolygonAttributes( );       pa.setCullFace( PolygonAttributes.CULL_NONE );       app.setPolygonAttributes( pa );       // generate texture coords       app.setTexCoordGeneration( stampTexCoords(shape) );       // modulate texture with color and lighting of underlying surface       TextureAttributes ta = new TextureAttributes( );       ta.setTextureMode( TextureAttributes.MODULATE );       app.setTextureAttributes( ta );       // apply texture to shape       if (texture != null) {    // loaded at start, from adjustShapes( )         app.setTexture(texture);         shape.setAppearance(app);       }     }  // end of addTextureGA( )

The modulation task utilizes a Java 3D TextureAttributes object to control how the texture is combined with the surface colors of the shape.

There are four texture modes:


REPLACE

The texture replaces any shape color.


MODULATE

The texture and color are combined (as here).


DECAL

The transparent areas of the texture aren't drawn onto the shape.


BLEND

A varying mix of texture and color is possible.

The MODULATE mode is often used to combine an underlying Material with a texture, which allows lighting and shading effects to be seen alongside the texture. Figure 16-15 shows the dolphins models turned blue and with a texture.

Figure 16-15. Textured, blue dolphins


This effect should be compared with the purely blue dolphins of Figure 16-10.




Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net