I have the following code that paints 4 points in a canvas3D window
public final class energon extends JPanel {
int s = 0, count = 0;
public energon() {
setLayout(new BorderLayout());
GraphicsConfiguration gc=SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas3D = new Canvas3D(gc);//See the added gc? this is a preferred config
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
scene.compile();
// SimpleUniverse is a Convenience Utility class
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
// This moves the ViewPlatform back a bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTransform();
simpleU.addBranchGraph(scene);
}
public BranchGroup createSceneGraph() {
BranchGroup lineGroup = new BranchGroup();
Appearance app = new Appearance();
ColoringAttributes ca = new ColoringAttributes(new Color3f(204.0f, 204.0f, 204.0f), ColoringAttributes.SHADE_FLAT);
app.setColoringAttributes(ca);
Point3f[] plaPts = new Point3f[4];
for (int i = 0; i < 2; i++) {
for (int j = 0; j <2; j++) {
plaPts[count] = new Point3f(i/10.0f,j/10.0f,0);
//Look up line, i and j are divided by 10.0f to be able to
//see the points inside the view screen
count++;
}
}
PointArray pla = new PointArray(4, GeometryArray.COORDINATES);
pla.setCoordinates(0, plaPts);
Shape3D plShape = new Shape3D(pla, app);
TransformGroup objRotate = new TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRotate.addChild(plShape);
lineGroup.addChild(objRotate);
return lineGroup;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new JScrollPane(new energon()));
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now i want to add a timertask that regularly updates the position of one of the points in the plaPts Point3f array. However, when i call plaPts[1].setX(2), nothing happens on the screen, they remain in the same position.
Do you have to have each point in a separate TransformGroup (consisting of a shape3D with a Point3f array of size 1) for this to be possible? I'm later going to use 100000 points, is it bad for performance if they all are in separate TransformGroups? Is there an easier way of doing this? Something like shape3D.repaint(), that automatically updates the position of the points based on the new values in plaPTS.
Do not use 10000 TransformGroup
instances, it will lead to horrible performance (compared to a single PointArray
).
You should have a look at the GeometryArray
JavaDocs, particularly about the distiction between using data by copying and by reference.
Newer versions of Java3D only support the by copying method. (Your approach would have worked with the by reference method, but you still would have to trigger an update).
The fact that the data is used by copying means that a copy of your Point3f
array is created when you pass it to the constructor of the PointArray
method. So modifications of these points will not affect the PointArray
.
Instead, you can use the setCoordinate
method to modify the points. Here is an example, you can simply add this method and pass your PointArray
to it:
private static void moveOnePointOf(final PointArray pa)
{
pa.setCapability(PointArray.ALLOW_COORDINATE_WRITE);
Thread t = new Thread(new Runnable()
{
Point3f p = new Point3f();
@Override
public void run()
{
while (true)
{
pa.getCoordinate(0, p);
p.x = (float)Math.sin(System.currentTimeMillis()/1000.0);;
pa.setCoordinate(0, p);
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
});
t.setDaemon(true);
t.start();
}
Further notes and hints:
Don't forget to set the capability for writing coordinates:
pointArray.setCapability(PointArray.ALLOW_COORDINATE_WRITE);
You might even consider to not use your Point3f
array at all, and set the coordinates directly in the PointArray
instead
On some systems, the native rendering components are somewhat odd. For Java3D or other OpenGL-based windows, this means that the window initially is gray, unless you resize or repaint it. You can avoid this by adding
System.setProperty("sun.awt.noerasebackground", "true");
as the first line of your main
method.