< Zurück | Inhalt | Weiter >

9.12 TransparencyAttributes

java.lang.Object

|

+−−javax.media.j3d.SceneGraphObject

|

+−−javax.media.j3d.NodeComponent

|

+−−javax.media.j3d.TransparencyAttributes


Table 9.13 Capability bits for the TransparencyAttributes class


MODE

VALUE

OpenGL Reference: glBlendFunc

The TransparencyAttributes class allows the transparency of objects to be specified. Transparency is set using an Alpha value (table 9.13). Alpha values range from 0.0, representing complete opacity, to 1.0, representing complete transparency. Like color, transparency can either be set on a per−vertex basis or, by using the TransparencyAttributes class, for an entire Shape3D. Per−vertex transparency (set using COLOR_4 per−vertex colors) takes precedence over the transparency value specified in the Shape3D’s TransparencyAttributes. The examples to follow will help to illustrate this.


Transparency should be used with care, because, as the OpenGL reference indicates, it is a blending operation between pixels that have their source geometry located at different positions within the scene.

Using transparency slows rendering considerably because the renderer must track the transparency of every pixel in the frame. Without transparency the color of a pixel in the frame is dictated by the color of the geometry closest to the viewer. All other geometry that would be mapped into the frame pixel location can be discarded since it is occluded by the geometry closest to the viewer. If some of the elements in the scenegraph are transparent, however, the renderer must perform a sequence of complex blending operations between the colors generated for a single pixel in the frame.


image


Figure 9.18 Five Sphere primitives with varying transparency, from left to right 100%, 70%, 50%, 30%, and 10%. All of the Spheres have the same color (black)


Here is what the Microsoft/Silicon Graphics OpenGL reference says about using transparency: “Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with primitives sorted from farthest to nearest. Note that this transparency calculation does not require the presence of alpha bitplanes in the frame buffer. You can also use glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for rendering antialiased points and lines in arbitrary order.” The key phrase in the description is, “with primitives sorted from farthest to nearest.” This is where the problems with using transparency in Java 3D occur. Because transparency is a Shape3D object attribute, Java 3D users naturally assume that they merely have to set the object or vertex transparency and Java 3D will take care of everything else. Sadly, this is not the case, as Java 3D provides very little support for sorting the primitives “from farthest to nearest.” This should be changing however, as Java 3D 1.3 will implement depth−sorted transparency—as demonstrated as a Sun presentation at the JavaOne 2001 conference.


Traditional 3D rendering techniques rely on the Z−buffer to ensure objects nearer to the viewer are rendered on top of objects further away.


The Z−buffer is essentially an array of depth values, one element in the array for each pixel in the frame. As the scene is rendered, the Z−buffer is updated with the distance of the source location for each pixel from the viewer. The Color buffer tracks the color of the closest source location for each pixel in the frame, as shown in the following sequences:


Rendering for Surface 1

Prerender pixel at location 5,10.

Get depth to geometry for pixel (10 meters).

Update Z−buffer with depth to geometry and update Color buffer with color of pixel.

Rendering for Surface 2

Prerender pixel at location 5,10.

Get depth to geometry for pixel (15 meters).

Do not update Z−buffer as 15 > 10 and do not update Color buffer as pixel is not closer to viewer.


In this way, when all the geometry in the scene has been prerendered, the Z−buffer contains the depth values for each pixel to the nearest geometry and the Color buffer contains the color for each pixel. When transparency is used, however, the color of a pixel cannot be solely determined from the color of the closest geometry; instead, a complex blend of the colors of all geometry gets mapped to the pixel location. In general, the blending will only be calculated correctly if the geometry is rendered from back to front, which is of

course view−dependent.


The problem therefore becomes one of sorting geometry from front to back before rendering takes place. For general scenes this is extremely difficult, especially for scenes that are composed of overlapping or interpenetrating objects. Such objects will have to be decomposed into nonpenetrating subsections before rendering.


Without sorting, you will only get reasonable results if most of your objects are opaque and you have only a few, nonoverlapping, transparent surfaces. The Java 3D rendering order is as follows:


1. Opaque objects

2. Ordered objects (OrderedGroups)

3. Transparent objects


Within the opaque and transparent groups no sorting is performed. Therefore, transparent objects will overlap opaque or ordered objects in front of them, whereas, because transparent objects are not depth−sorted, there are no guarantees that transparent objects will be rendered correctly.


Figures 9.19 through 9.29 illustrate some of the potential rendering problems. The scene for the following figures was composed of a single Box primitive with one face (LEFT) removed. The LEFT face was replaced with a new, slightly smaller face that included per−vertex colors (COLOR_4). The code used to replace the LEFT face follows:


//create a Box with Normal vectors and texture coordinates 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;


//define the geometry for the left face final float[] verts =

{

−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

};


//define the colors for the left face. Note we are using RGBA

//colors and include per−vertex transparency final float[] colors =

{ 1,0,0,0,

0,1,0,0.2f,

0,0,1,0.8f,

0,0,0,1,

};


//define the texture coordinates for the left face

float[] tcoords =

{

1, 0,

1, 1,

0, 1,

0, 0

};


//define the normal vector for the new left face

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


//assign the colors to the QuadArray geometry.setColors( 0, colors, 0, 4 );


//assign the normal vector for each vertex in the QuadArray for( int n = 0; n <4; n++ )

geometry.setNormal( n, normalVector );


//assign the texture coordinates for each vertex in the QuadArray geometry.setTextureCoordinates( 0, tcoords, 0, 4 );


//finally, assign the vertices themselves into the QuadArray geometry.setCoordinates( 0, verts );


NOTE All rendering was performed with

PolygonAttributes.CULL_NONE; so

all the faces of the Box were rendered.


 

9.12.1 A warning about transparency