Skip to main content

newbie question: how to dynamically add varying colored shapes

4 replies [Last post]
Joined: 2006-02-17

Hi Guys,

I'm a newbie and am trying to dynamically add different spheres with different colors in different locations to my universe at runtime. So far, the only way I have seen to add shapes dynamically has been by adding Geometry to a Shape3D object that is already in the tree....but I need a way to specify the shape and color of this new object....does anyone know of a way to do this?

thanks a billion in advance,

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Matthew Hilliard

In a nutshell, allocate a BranchGroup to your universe to hold your
spheres. Branchgroups are the best way to get things in and out of a
scengraph after it has been created, so what you'll do then is add and
remove spheres from the Branchgroup.

See if this RandomSpheres class is helpful at all:

import java.util.Random;

import javax.vecmath.Color3f;
import javax.vecmath.Point3f;

import com.sun.j3d.utils.geometry.Sphere;

public class RandomSpheres {

// units from 0 your sphere may appear
private float MAX_DIST = 100;

// maximum diamater of a sphere
private float MAX_SPHERE_DIAMETER = 5;

public static void addSpheresToBranchGroup( BranchGroup allSpheres,
int numSpheres ) {

Random rand = new Random( System.currentTimeMillis() );

for ( int i = 0; i < numSpheres; i++ ) {

float randomRadius = rand.nextFloat() * MAX_SPHERE_DIAMETER;

// random colour to assign new sphere
Color3f randomColour = new Color3f(
rand.nextFloat(), rand.nextFloat(), rand.nextFloat() );

// diffuse colour is most obvious, play around with others if
you like
Material sphereMaterial = new Material();
sphereMaterial.setDiffuseColor( randomColour );

Appearance sphereAppearance = new Appearance();
sphereAppearance.setMaterial( sphereMaterial );

// sphere utility class
Sphere currSphere = new Sphere( randomRadius, sphereAppearance );

// random position coordinates for sphere
float randomX = rand.nextFloat()
* (rand.nextBoolean() ? -MAX_DIST : MAX_DIST);
float randomY = rand.nextFloat()
* (rand.nextBoolean() ? -MAX_DIST : MAX_DIST);
float randomZ = rand.nextFloat()
* (rand.nextBoolean() ? -MAX_DIST : MAX_DIST);

Point3f randomPosition = new Point3f( randomX, randomY, randomZ );
Transform3D randomMovement = new Transform3D();
randomMovement.transform( randomPosition );

// offset to mave a sphere randomly given the randomMovement
TransformGroup randomSphereMovement = new TransformGroup(
randomMovement );
randomSphereMovement.addChild( currSphere );

allSpheres.addChild( randomSphereMovement );

} // addSpheresToBranchGroup
} // fin

To unsubscribe, e-mail:
For additional commands, e-mail:

Joined: 2006-02-17

Thank you for your reply,

Unfortunately I am still getting errors :(
I created a BranchGroup (called it root) and added it to the universe. Then, from a button event handler I called the function you gave me, passing root as an argument. The following error was resulted: Group: only a BranchGroup node may be added

I also tried creating a new BranchGroup at runtime and adding that to the root, but that gave me this: Group: no capability to append children

Any thoughts?

thanks a million (again) in advance,

Joined: 2006-02-17


My bad.

You'll need to wrap my call in a *new* BranchGroup (call it wrapper or somesuch) *every time* you want to add something to the root BranchGroup. Which is to say you can only add BranchGroups to BranchGroups in a *live* scene.

the quick fix is to replace the last line:
allSpheres.addChild( randomSphereMovement );

with these 3 lines:
BranchGroup wrapper = new BranchGroup();
wrapper.addChild( randomSphereMovement );
allSpheres.addChild( wrapper );

Also, make sure root has the method "setCapability()" called with the paramters: Group.ALLOW_CHILDREN_EXTEND and Group.ALLOW_CHILDREN_WRITE, *before* it goes live. If you intend to add branchgroups often ("often" is subjective you may want to benchmark or not worry about it at all) you may also call "setCapabilityIsFrequent()" with the same paramters, and j3d will know to alter its performance accodingly. Much of j3d's performance and behavior is regulated by what capabilities are set for specific nodes. Whenever you get a CapabilityNotSetException, some node somewhere needs to have "setCapability()" with the appropriate parameter called before it goes live.


Joined: 2006-02-17

Thank you very much Matt, I really appreciate you helping me out.