Areas


Topics

j3d.org

Object manipulation

  1. Can I add/substract two pieces of geometry?
  2. Why does my application hang when I call View.setMinimumFrameCycle()
  3. I can't understand these Quaternion things - help!
  4. Problems with "get" methods
  5. Detaching a BranchGroup or Behavior
  6. Breaking up polygons into triangles
  7. Generating normals
  8. Null pointer exceptions from Triangulator
  9. "IllegalArgumentException: Index lists must all be the same length" error from GeometryInfo.
  10. Why can't I share nodes across multiple universes?
  11. Moving an object on the screen with a scrollbar
  12. How do I pick points and lines?
  13. Why do I get a RestrictedAccessException when setting a capability on one of Sun's primitives before adding it to the scene graph?
  14. Why does my Transform3D scale get reset after a rotate?
  15. How do I add and remove objects at runtime?
  16. Why doesn't Java3D's collision system stop me from walking through objects?
  17. How do I stop exceptions in MasterControlThread?

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

 

1. Can I add/substract two pieces of geometry?

This is called boolean or Constructive Solid Geometry (CGS). CSG is not supported by Java 3D. You will need to implement your own routines as we are unaware of any packages currently available.

 

2. Why does my application hang when I call View.setMinimumFrameCycle()

This is a bug that was introduced with Java3D 1.3 (Bug ID 4732333). It typically happens when you attempt to set the coordinate values or some other form of geometry in a behaviour callback although other calls are known to trigger the problem too. The only work-around known is to remove the call completely and control your framerates with different behaviours conditions (such as waking up every given number of milliseconds or every 4th frame).

 

3. I can't understand these Quaternion things - help!

Congratulations! You are just like almost every other beginner 3D graphics programmer. The most common problem is the question: I want to rotate my object by X degrees about some arbitrary axis.

The simplest way to think about quaternions is to think of two things - an axis and an amount of rotation. The axis is where you rotate the object. The angle is how much you rotate that object about the given axis. As the whole object moves, so it doesn't really matter what the angle is relative too, just that everything moves by that angular amount. The axis provides the pivot point for the rotation. Want to rotate the box 90 degrees so that the front now faces the side - the axis has to be the Y axis (the vertical one). All the points now rotate about the vertical axis by 90 degrees.

There is a much better collection of quaternion information that is maintained as a subsection of this site at the following urls:

 

4. Problems with "get" methods

Frequently, if you're having a problem (such as a null pointer exception) using one of Java 3D's "get" methods, you've forgotten to allocate the object needed to extract the data you're trying to retrieve. For example, calling the getCoordinates() in GeometryArray appears to allocate objects for you, and return the array elements that were allocated within the method. This is not the case.

By requiring that the array elements already exist, objects that were subclassed from Point3d can be passed into the method, and the method will still work correctly. If they hadn't done it this way, you would have to allocate your own array, a Point3d array and then copy the Point3d info into your own objects after the method call completed.

 

5. Detaching a BranchGroup or Behavior
Contributor: Doug Gehringer

To add/remove a subgraph at runtime you need to put the stuff to be added/removed into a BranchGroup and set the capability bits on the parent and child to allow the runtime changes:

   Behavior yourBehavior; // this is what you want to remove
   Group    parent;       // this is where you want to add/remove

   BranchGroup removableBehavior = new BranchGroup();
   removeableBehavior.addChild(yourBehavior);
   removeableBehavior.setCapability(BranchGroup.ALLOW_DETACH);

   parent.setCapability(Group.ALLOW_CHILDREN_READ);
   parent.setCapability(Group.ALLOW_CHILDREN_WRITE);
   parent.setCapability(Group.ALLOW_CHILDREN_EXTEND);
   parent.addChild(removeableBehavior);

With this, you can now add/remove after the scene graph is live. Call removableBehavior.detach() to remove the behavior from the scene and parent.addChild(removeableBehavior) to add it.

Note: you may not need to add/remove the behavior from the graph. In many cases you can use the setEnable() method to turn the behavior on and off.

If you're seeing an error that looks something like this:

Exception occurred during event dispatching:
javax.media.j3d.CapabilityNotSetException: Locale: no capability to
detach BranchGroup

You might have noticed that locale doesn't have setCapability method. The error is a bit misleading. The BranchGroup needs the BranchGroup.ALLOW_DETACH capability set. That should fix the problem.

 

6. Breaking up polygons into triangles

You can break up polygons into triangles using some utility objects that Sun provides. Fill in the GeometryInfo object, and call the triangulate method of the Triangulator object.

More information on GeometryInfo and the Triangulator class can be found in the Geometry Info Quick Fix Tutorial

The j3d.org Code Repository also contains a simplified triangulator that will work with individual polygons. Look for the class org.j3d.geom.TriangulationUtils for more details.

 

7. Generating normals

Sun provides an object for generating normals. Fill in the GeometryInfo object, call the generateNormals method of the NormalGenerator object, and that should do it. You may want to use the setCreaseAngle before you generate the normals. Further information about that is available in the NormalGenerator javadoc.

 

8. Null pointer exceptions from Triangulator

If you get a null pointer excepting when trying to use Triangulator, this can be caused by a couple things. You may have forgotten to call the setStripCounts method of GeometryInfo. If you don't set this, the Triangulator has no way of telling how big each of the polygons are that you've given it.

More information on GeometryInfo and the Triangulator class can be found in the Geometry Info Quick Fix Tutorial

 

9. "IllegalArgumentException: Index lists must all be the same length" error from GeometryInfo.

This is a bug in Triangulator, and is listed as such in the README.

 

10. Why can't I share nodes across multiple universes?

Sharing nodes across multiple universes is not permitted. See section 3.1 and appendix D.5 of the Java 3D specification.

 

11. Moving an object on the screen with a scrollbar

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

 

12. How do I pick points and lines?

Doug Gehringer posted some new picking utilities on the Java 3D mailing list that address this. J3d.org has a copy of these available in the utilities area for you to look at.

 

13. Why do I get a RestrictedAccessException when setting a capability on one of Sun's primitives before adding it to the scene graph?

This problem occurs when you have added one instance of the object to the scene graph already and want to add another of the same time (eg sphere). By default the geometry primitive utilities cache and share Geometry objects. So, if one already exists in the scene graph, the Geometry could already be live. A quick check is to check the value of Geometry.isLive(). To turn off this sharing, create the Sphere with the Primitive.GEOMETRY_NOT_SHARED flag.

 

14. Why does my Transform3D scale get reset after a rotate?

I have the following code and after the rotation, the scale component is always reset back to 1.0:

  tg.getTransform(t3d);
  t3d.rotX(Rot);
  tg.setTransform(t3d);

The rotate methods specifically say that it sets the entire transform to only the rotation values, hence scale information is wiped out. To combat this, you need to actually create a separate Transform3D with the rotation set and then multiply the two matrices together to get the correct result. For example:

  Transform3D mul = new Transform3D;
  mul.rotX(Rot);

  tg.getTransform(t3d);
  t3d.mul(mul);

  tg.setTransform(t3d);

 

15. How do I add and remove objects at runtime?

Java3D requires that dynamic modification of the scene graph is only performed through the use of BranchGroup objects. If you want to add or remove an object, you must wrap it first in a BranchGroup and then set the appropriate capability bit. If you do not use a BranchGroup, then you will see IllegalAccessExceptions being generated.

 

16. Why doesn't Java3D's collision system stop me from walking through objects?

Java3D's collision system is not designed for this sort of work. All it does is detect a collision after it has already happened. The behaviour you are looking for is called collision avoidance and there are two tutorials on this at this site: Java3D's Collision Detection System and Collision Detection and Terrain Following.

 

17. How do I stop exceptions in MasterControlThread?

Despite Java3D claiming to be able to work in a completely asynchronous manner, there are quite a few restrictions. Typically this exception is generated when you attempt to change view information without going through a behaviour. This seems to be particularly problematic if you are making the changes from within a user interface callback. The easiest way to control this problem is to have a behaviour that buffers your UI input choice and calls it during the Java3D behaviour processing loop. If you don't have a global behaviour already, then making use of the Post ID criteria is a good way to have this work and not overload the processing cycles of the application or Java3D with unnecessary work.