Areas


Topics

j3d.org

Scene appearance

  1. Where did these stripes across my object come from?
  2. Objects don't appear in the 'right' order
  3. Why can I only see one side of a flat object?
  4. Shading does not appear to be correct
  5. Transparency not working with multiple transparent objects
  6. Displaying only the points of an object
  7. Automatically placing an object in the center of the Canvas3D
  8. Non-congruent transforms above ViewPlatform
  9. Why does my object disappear when I set a Material?

Return to the main FAQ page for more questions and answers.

 

1. Where did these stripes across my object come from?

The stripes are due to an effect called Z-buffer tearing. Boiled down to its simplest explanation, it means that the video card, when it tries to render objects, does not have enough precision to make the correct decision about which bit to render. This normally happens when the two objects are very close together such as in this picture (supplied courtesy of Kevin Copps)

In order to fix your problem, you have to look at the settings for controlling precisions, known as the clipping planes. These tell Java3D, and hence the underlying graphics renderer, how to set up the precision. Put the near and far planes too far apart and you loose precision. Put them too close together and you end up chopping off bits of geometry that you really want to see. For Java3D, the recommendation is to set a ratio of the front / back distances to a value less than 3000. You can find the API calls to set these values in the class javax.media.j3d.View.

 

2. Objects don't appear in the 'right' order

Sometimes when you place objects in a scene, the objects in the back appear to be in the front.

There are a couple of ways to fix this, depending on what effect you are trying to achieve.

The easiest way is to turn on Z-buffering. You can do this by setting the RenderingAttributes object within the Appearance Node in a Shape3D object.

  Appearance app = new Appearance();
  //
  // set Appearance attributes as you'd like
  //
  RenderingAttributes ra = new RenderingAttributes();
  ra.setDepthBufferEnable(true);
  app.setRenderingAttributes(ra);

 

3. Why can I only see one side of a flat object?

The reason you're seeing this is that the faces are only visible in the direction that the normals are pointing. There are couple of different ways to do what you want. One way is to take the faces you currently have, duplicate them, wind the polygons in the opposite direction, and set the normals in the opposite direction from the original. Another (easier) way is to take an appearance ("app" in the example below) and do the following:

    PolygonAttributes pa = new PolygonAttributes();
    pa.setCullFace(PolygonAttributes.CULL_NONE);
    app.setPolygonAttributes(pa);

Note that if you are also using textures, you will want to make sure that they are visible on both sides by allowing the back-face normal to be flipped. By default, even with back facing polygons not being culled, the lighting equations will point the surface normal in the other direction and the result is you still don't see anything. In your polygon attributes, also make sure you have the following code:

    pa.setBackFaceNormalFlip(true);

 

4. Shading does not appear to be correct

Sometimes an object may appear to be correctly colored on one side, and not the other. This problem is the same as only seeing one side of a polygon. Please see the answer for that question

 

5. Transparency not working with multiple transparent objects
Contributor: Kevin Rushforth

The basic problem is that transparency is inherently an order-dependent operation. For the rendering to be correct in all cases, all triangles must be rendered from back to front. In cases without a lot of overlapping transparent objects, you can usually get good results by rendering all of the opaque objects, freezing the Z-buffer, and then rendering all of the transparent objects. However, this sometimes has the side-effect of causing transparent objects that are further away to look like they are in front of transparent objects that are closer. Turning on the Z-buffer (by disabling DepthBufferFreezeTransparent) fixes this, but creates other problems.

Java3D 1.3 and later have this correctly implemented, though there are still a few bugs in corner cases. If you are using Java3D 1.2 then the following advice may be useful.

Without sorting your geometry--and breaking it up in the case of intersecting objects--there is no solution. To get this looking somewhat correct, make use of the blending mode information.

The blend modes to look for are found in the TransparencyAttributes. Look for the methods setTransparencyMode() and set[Src|Dst]BlendFunction().

Sun have acknowledged a bug in Java 3D 1.2 with multiple transparent objects. There is a work-around:

TransparencyAttributes t_attr =
    new TransparencyAttributes(
          TransparencyAttributes.BLENDED,
          transparencyValue,
          TransparencyAttributes.BLEND_img_ALPHA,
          TransparencyAttributes.BLEND_ONE);

Appearance windowApp = new Appearance();
windowApp.setTransparencyAttributes( t_attr );
windowApp.setRenderingAttributes( new RenderingAttributes() );

However, this will not work for all cases - particularly transparent textures applied to objects. A more complete solution should be forth-coming in Java3D v1.3 and 1.4.

 

6. Displaying only the points of an object

The example program, DisplayPoints.java shows how to do this. Thanks to Doug Gehringer for providing this example.

 

7. Automatically placing an object in the center of the Canvas3D
Contributor: Doug Gehringer

If you have the "usual" scene graph structure which puts the object in one BranchGraph and the view in another BranchGraph you can inquire the bounds of the object and modify the view to show the object. An example of this is the X3DViewer (available from the Web3D consortium).

The basic idea is to add the object to the scene, inquire the bounds of the object and then modify the view to show the object. Set the view by translating the view so that it is located at the center of the bounds and then translating the view "back" far enough to display the entire diameter of the bounds.

Another way to do this is to use a fixed position viewpoint and modify a transform above the object to translate and scale the object to fit in the view.

 

8. Non-congruent transforms above ViewPlatform

The problem should be exactly what the error message says. The transform3d you set is non-congruent, meaning that it does something you can't do with any combination of rotation, translation and mirroring (scale of -1).

The key words are "above the View platform". I usually use Transform3D.lookAt() to point my View where I want to look. lookAt() requires, among other things, a vector which tells the rest of the plumbing where I think "up" is (usually 0,1,0). Given an "up" vector pointing in the +Y direction, I'm not allowed to "look" in that same direction. The "up" vector specifies which way will be "up" on my screen, and if I look in exactly this direction, any screen view rotation will be equally valid, or wrong, so J3D doesn't let you do this.

In other words, you will get this answer if you try to look straight up or straight down.If you really want to look in this direction, then change the direction of the "up" reference vector before you look there.

Unfortunately, there is a bug in J3D that classifies mirroring transformations as non-congruent. So until next release, you (and I) have to use only rotation and translation in transforms above viewplatform (and also in transforms in View object, at least in compatibility mode)

If you do lots of strange matrix calculations, it is possible that some rounding error accumulates in your matrix and tweaks it enough to make it non-rigid. But probably it's the bug.

 

9. Why does my object disappear when I set a Material?

If your object disappears when you explicitly set a Material then it means you have not set up all of the information in the geometry correctly.

When geometry is rendered, the rendering engine uses two separate pieces of information to paint your object to screen. Firstly it checks to see which polygons are visible. Visible polygons are ones that face toward you. Those that face away (see the question on back-face culling on this page) are removed. After this first pass is performed, a second pass then uses the normal information provided in the geometry to vary colour information.

To determine which polygons to remove, the rendering engine looks at the vertex information for each polygon defined in the provided geometry and creates a normal for the surface. This normal is calculated based on a clockwise ordering of the points. So, if you have a box and you can't see a particular side of the box, check to make sure that the points, as you look at the box, are declared in a clockwise order.

The reason that this effects geometry when you set a Material instance is that when no material is set, the renderer does not remove any polygons for that geometry. When the material is set, the default behaviour for the material is to cull backward facing polygons. Get the vertex orderin wrong and your object seems to disappear.

Why does the code ignore my normals that I provide as part of the geometry? Simple, the normals that you provide for the geometry are only used for lighting effects. They do not provide information about any given surface "direction". Colouring and shading effects are a completely separate process from the initial cull and the code has to work for cases when there are no normals provided. There is also a significant performance boost too because you only need to send one lot of data (vertex info) rather than two lots (vertex + normals). Thus, the behavior is to always use just the purely vertex information regardless of whether you supply lighting information.