Java 3D Programming by Daniel Selman - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

CHAPTER 9

Setting geometry appearances

9.1 Introduction

9.2 Appearance

9.3 ColoringAttributes

9.4 LineAttributes

9.5 Material

9.6 PointAttributes

9.7 PolygonAttributes

9.8 RenderingAttributes

9.9 TexCoordGeneration

9.10 TextureAttributes

9.11 Texture

9.12 TransparencyAttributes

9.13 Summary

The Java 3D Appearance class enables you to set rendering attributes for the geometric primitives in your scene—at startup, during scenegraph creation, or dynamically at runtime. After reading this chapter, you should be able to dynamically modify the appearance of the geometry within your scenegraph.

9.1 Introduction

Java 3D contains a host of classes to specify the rendering attributes for geometric primitives, such as color, texture, back-face removal, and so on. Java 3D defines “has-a” relationships between the classes that control overall rendering appearance. For example, an Appearance has a Material class, a PolygonAttributes class, a RenderingAttributes class, and so on. This is one of the best-designed areas of Java 3D; with a little experience you can quickly learn to navigate the various classes that, when combined, specify object appearance. Compared with learning the plethora of separate OpenGL methods to specify appearance, the OO nature of the Java 3D design pays dividends.

An instance of an Appearance object is associated with each Shape3D geometric object in the scenegraph. The Appearance object defines rendering state information that must be applied to the rendering pipeline before the raw geometry within the Shape3D is rendered.

It is useful to think of the Java 3D renderer traversing through the defined scenegraph; when it encounters TransformGroups, it applies matrix transformations; when it encounters a Shape3D Node, it applies the Shape3D’s Appearance state—all before executing the Shape3D object to generate native graphics API calls.

What follows is an overview of the NodeComponent-derived classes that define a Java 3D rendering state for a Shape3D object. Emphasis is placed on areas of potential confusion or typical problems. Consult the detailed Sun API reference for a method-by-method summary of the classes. I have prefaced each section with a table listing the capability bits that control access to the specific feature being discussed. The tables include references to OpenGL functions where appropriate and useful.

One of the lengthier examples of the book accompanies this chapter: AppearanceTest (illustrated in figure 9.1) allows you to dynamically modify most of the Appearance attributes on a simple scene. I encourage you to examine the code for the example and run it as you work through this chapter—most of the sections will be significantly clarified by this interactive example.

img77.png

Figure 9.1 The AppearanceTest example application allows Appearance settings to be modified at runtime

9.2 Appearance

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.Appearance

The Appearance class contains member variables that together define an appearance state for a Shape3D object. A Shape3D object basically contains Geometry and Appearance. The Appearance class itself does not define any of the properties that control Shape3D appearance, but instead packages Appearance subcomponents, such as PolygonAttributes, RenderingAttributes, and so on.

The Appearance class controls access to its member variables through the familiar, but rigorous, process of setting capability bits. That is, the application developer must specify which Appearance member variables will be modified after the Appearance is attached to a live scenegraph. A live scenegraph is one that has either been compiled or has been rendered.

The capability bits that control access to the member variables of the Appearance class are:

  • COLORING_ATTRIBUTES
  • LINE_ATTRIBUTES
  • MATERIAL
  • POINT_ATTRIBUTES
  • POLYGON_ATTRIBUTES
  • RENDERING_ATTRIBUTES
  • TEXGEN TEXTURE_ATTRIBUTES
  • TEXTURE
  • TRANSPARENCY

Preface the listed items with ALLOW_ and add _READ or _WRITE for read or write access respectively. For example, to allow read/write access to the Material and PolygonAttributes member variables, you would put the following in your code:

Appearance app = new Appearance();

app.setCapability( ALLOW_MATERIAL_READ );

app.setCapability( ALLOW_MATERIAL_WRITE );

app.setCapability( ALLOW_POLYGON_ATTRIBUTES_READ ); app.setCapability( ALLOW_ POLYGON_ATTRIBUTES_WRITE );

NOTE

Four separate calls must be made to the setCapability method—it is not possible to OR together the various capabilities. ORing together capability bits will lead to very unpredictable behavior. Public accessor methods to access the member variable are defined as:

app.setMaterial( new Material() );

app.setPolygonAttributes( new PolygonAttributes() );

PolygonAttributes polyAttribs = app.getPolygonAttributes(); Material material = app.getMaterial();

9.3 ColoringAttributes

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.ColoringAttributes

Table 9.1 Capability bits for the ColoringAttributes class

img78.png

The ColoringAttributes within a Shape3D’s Appearance are used to control the color of a Shape3D if a Material has not also been assigned to the Appearance. If a Material has been assigned, the ColoringAttributes are ignored and the more complex color and lighting information within the Material class are used instead. See table 9.1.

The colors of any vertices within the Shape3D that have per-vertex colors applied are unchanged by the ColoringAttributes.

The next example, from AppearanceTest.java, creates a standard Box and then replaces the LEFT face with a new face created with new geometry and per-vertex colors. When a ColoringAttributes object is assigned to the Appearance for the Box it will set the color for the five original faces but will not effect the LEFT face which has per-vertex colors assigned, as illustrated in figure 9.2.

img79.png

Figure 9.2 A Box primitive with an applied ColoringAttribute. The LEFT face has been removed and replaced with a QuadArray that includes per-vertex colors that are unaffected by the ColoringAttributes

int nScale = 50;

Box box = new Box( nScale,nScale,nScale, Primitive.GENERATE_NORMALS | Primitive.GENERATE_TEXTURE_COORDS, m_Appearance);

Shape3D frontFace = box.getShape( Box.LEFT );

//create a new LEFT face so we can assign per-vertex colors

GeometryArray geometry =

new QuadArray( 4, GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR_4 | GeometryArray.TEXTURE_COORDINATE_2 );

nScale = 40;

final float[] verts =

{

 // new LEFT face

 -1.0f * nScale, -1.0f * nScale,  1.0f * nScale,

 -1.0f * nScale,  1.0f * nScale,  1.0f * nScale,

 -1.0f * nScale,  1.0f * nScale, -1.0f * nScale,

 -1.0f * nScale, -1.0f * nScale, -1.0f * nScale

};

final float[] colors =

{

// left face

1,0,0,0,

0,1,0,0.2f,

0,0,1,0.8f,

0,0,0,1,

};

float[] tcoords =

{

 // texture coordinates for LEFT face

 1, 0,

 1, 1,

 0, 1,

 0, 0

};

Vector3f normalVector = new Vector3f(-1.0f,  0.0f,  0.0f);

geometry.setColors( 0, colors, 0, 4 );

for( int n = 0; n <4; n++ )

geometry.setNormal( n, normalVector );

geometry.setTextureCoordinates( 0, tcoords, 0, 4 );

geometry.setCoordinates( 0, verts );

9.4 LineAttributes

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.LineAttributes

Table 9.2 Capability bits for the LineAttributes class

img80.png

The LineAttributes class controls the style of lines used to draw the edges of surfaces. See table 9.2. The available styles are:

  • Antialiasing: on or off
  • Pattern: dash, dash dot, dot, or solid
  • Line width: In pixels

To see the effect of the LineAttributes class, the Appearance must be set to render in LINE (wire frame) mode:

Appearance app = new Appearance();

PolygonAttributes polyAttribs = new PolygonAttributes( PolygonAttributes.POLYGON_LINE, PolygonA

app.setPolygonAttributes(polyAttribs );

See section 9.7.1 for more detail on PolygonAttributes. Figures 9.3–9.6 show examples rendered using various LineAttribute styles.

img81.png

Figure 9.3 Rendering in LINE mode with a null LineAttributes

img82.png

Figure 9.4 Rendering with a LineAttributes of width 10 without antialiasing

img83.png

Figure 9.5 Rendering with a LineAttributes of width 10 with antialiasing

img84.png

Figure 9.6 Rendering with a LineAttributes of width 2 with a Dash Dot pattern

The lines rendered in LINE mode are effected by color, lighting, and texture applied to surfaces.

9.5 Material

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.Material

Table 9.3 Capability bits for the Material class

img85.png

The Material class specifies surface rendering characteristics (table 9.3) using the following parameters:

  • Surface colors

Ambient

Diffuse

Emissive

Specular

  • Lighting enable: Controls whether lighting is enabled for the Shape3D.
  • Shininess: Gloss parameter that controls the effect of specular lighting.

The effects of the various colors specified within the Material are described in detail in the context of lighting in chapter 10. Figure 9.7 shows a cube rendered with an applied Material, and per-vertex colors on four vertices of the cube.

img86.png

Figure 9.7 Appearance with an applied Material with Ambient, Diffuse, Emissive, and Specular colors. Lighting calculations determine the shade of each surface

9.6 PointAttributes

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.PointAttributes

Table 9.4 Capability bits for PointAttributes class

img87.png

The PointAttributes class specifies rendering information for rendered points (table 9.4).

PointAttributes encapsulates two appearance properties:

  • ANTIALIASING: Boolean to specify whether points are antialiased
  • SIZE: The size of each point in pixels

If antialiasing is enabled, points are rendered as circular; if antialiasing is disabled, points are rendered as square (size pixels by size pixels) as shown in figures 9.8 and 9.9.

img88.png

Figure 9.8 An array of colored points of size 8 pixels with antialiasing

img89.png

Figure 9.9 The same as in figure 9.8 but without antialiasing set in the PointAttributes

NOTE

The time taken to render a point (at least without hardware acceleration) is proportional to the size of the point in pixels.

Note that a single point, when antialiased, approximates a sphere, in that it is never possible to view the point “edge-on” as a disc. When points are rendered without antialiasing, the point approximates a cube with each front face always perpendicular to the viewer. Figures 9.10 and 9.11 illustrate.

img90.png

Figure 9.10 When rotated, antialiased points appear as spheres

img91.png

Figure 9.11 When rotated, nonantialiased points appear as squares aligned with the viewer

The figures are taken from the PointTest.java example. The example defines the points to be rendered, as well as Appearances, as follows:

//create a BranchGroup containing an nNumPoints x nNumPoints

//array of points

//the size of the points is set to nPointSize and antialiasing

//is set to bAliased

private BranchGroup createPoints( final int nPointSize, final int nNumPoints, boolean bAliased )

{

 BranchGroup bg = new BranchGroup();

 //create a Text3D label describing the points

 String szText = new String();

 szText += ( nNumPoints + "X, Size:" + nPointSize + ", aliased:

 " + bAliased );

 Font3D f3d = new Font3D( new Font( "SansSerif", Font.PLAIN, 1),

 new FontExtrusion() );

 Text3D label3D = new Text3D( f3d, szText, new Point3f(-5,0,0)

 ); Shape3D sh = new Shape3D( label3D );

 bg.addChild( sh );

 //create the PointArray used to hold the geometry for the points

 PointArray pointArray = new PointArray( nNumPoints * nNumPoints, GeometryArray.COORDINATES | GeometryArray.COLOR_3 );

 //populate the PointArray that we will be rendering

 int nPoint = 0;

 final double factor = 1.0 / nNumPoints;

 for( int n = 0; n <nNumPoints; n++ )

 {

  for( int i = 0; i  <nNumPoints; i++ )

  {

   Point3f point = new Point3f( n - nNumPoints/2,

i - nNumPoints/2, 0.0f );

   pointArray.setCoordinate( nPoint, point );

   pointArray.setColor( nPoint++,

    new Color3f( 0.5f, (float) (n * factor),

    (float) (i * factor) ) );

  }

 }

 //create the Appearance for the points

 Appearance pointApp = new Appearance();

 //enlarge the points and set antialiasing

 pointApp.setPointAttributes( new PointAttributes

 ( nPointSize, bAliased ) );

 //create a Shape3D for the PointArray and assign the appearance

 Shape3D pointShape = new Shape3D( pointArray, pointApp );

 //add the Shape3D to the BranchGroup and return

 bg.addChild( pointShape );

 return bg;

}

9.7 PolygonAttributes

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.PolygonAttributes

Table 9.5 Capability bits for the PolygonAttributes class

img92.png

The PolygonAttributes class encapsulates properties for how polygons are rendered (table 9.5). Polygon rendering is controlled by the following properties:

  • Cull face: Determines which surfaces of the polygon are rendered. Either all surfaces or the backward-facing surfaces or the front-facing surfaces are rendered. Backward-facing surfaces are backward facing by virtue of the direction of their normal vector (calculated from the winding order of the vertices). That is, the vector normal to the surface is currently pointing away from the viewer.
  • Rendering mode: Renders either the polygon as a filled triangular surface or just the edges of the surface as lines or just the vertices of the surface as points.
  • Normal vector compensation: Flips the orientation of surface normal vectors. This mode is useful for geometry that is defined using clockwise winding when counter-clockwise winding should be used for surface normal vector calculation.
  • Z-value offset: Shifts the geometry attached to the parent Appearance away from the eye (viewer) by the specified amount. By specifying an offset on one Shape3D it can be moved in front of or behind the other Shape3D. Because of differences in OpenGL/DirectX hardware implementation, however, it is very difficult to achieve consistent results using this method.

For example, to allow write access to the CULL_FACE property, use the following:

PolygonAttributes polyAttribs = new PolygonAttributes();

polyAttribs.setCapability(PolygonAttributes.ALLOW_CULL_FACE_WRITE );

Table 9.6 Cull face parameters

img93.png

Cull face parameters (table 9.6) can be implemented as follows:

polyAttribs.setCullFace( PolygonAttributes.CULL_BACK );

Table 9.7 Mode parameters

img94.png

Polygon fill-mode parameters are shown in table 9.7. For example, to set line-only (wire frame) mode, use the following:

polyAttribs.setPolygonMode( PolygonAttributes.POLYGON_LINE );

Figures 9.12 through 9.15 illustrate how normal vector flipping can influence both the lighting calculations, (compare the shading of the horizontal faces in figure 9.12 with figure 9.13), and surface culling (figure 9.14, 9.15).

img95.png

Figure 9.12 CULL_NONE, NORMAL_FLIP = false

img96.png

Figure 9.13 CULL_NONE, NORMAL_FLIP = true

img97.png

Figure 9.14 CULL_FRONT, NORMAL_FLIP = false

img98.png

Figure 9.15 CULL_FRONT, NORMAL_FLIP = true

9.8 RenderingAttributes

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.RenderingAttributes

Table 9.8 Capability bits for the RenderingAttributes class

img99.png

The RenderingAttributes class allows pixels within the final rendered scene to be included or excluded based on the pixel Alpha (transparency) value (table 9.8).

Assuming an Alpha test value of A, the test conditions listed in table 9.9 and shown in figure 9.16 are available.

img100.png

Figure 9.16 Using RenderingAttributes to control the portions of a QuadArray that are rendered. Vertex 0 has transparency 0.0, vertex 1 has transparency 0.2, vertex 2 has transparency 0.8, and vertex 3 has transparency 1.0. In all cases the Alpha test value was set to 0.5

Table 9.9 Alpha test modes

img101.png

The interpolation of transparency values across primitives (quads or triangles) can sometimes be surprising. Figure 9.17 illustrates what happens to a QuadArray when it is rotated. In this case vertexes 0 and 1 have a transparency of 0.0, and vertexes 1 and 2 have a transparency of 1.0.

img102.png

Figure 9.17 The lower two vertices have transparency 0.0, while the upper two vertices have transparency 1.0. The Alpha test value is 0.5 and Alpha test function is LESS. Note that, as the QuadArray rotates, the transparency interpolation changes as a function of the rotation and an apparent spike appears in the middle of the quad

9.9 TexCoordGeneration

java.lang.Object

 |

 +--javax.media.j3d.SceneGraphObject

  |

  +--javax.media.j3d.NodeComponent

   |

   +--javax.media.j3d.TexCoordGeneration

Table 9.10 Capability bits for the TexCoordGeneration class