I have not been reading this list for a while. I was having some trouble
with the java3d api (specifically the overlays and also recording to a
video) and my employer decided to switch to another development path. (An
ActiveX rendering control called 3DLinX (www.3dlinx.com).) I personally
have always reviled Visual Basic and getting the opportunity to work with
it in depth has done nothing but strengthen my resolve. =) I am trying to
get switched back over to java3d but still have the same issues that I did
before.
I noticed that an overlay library recently was posted. I looked at it and
it is beyond my current experience but I'm sure some playing would be
productive.
I never have understood though why exactly I can't just draw onto the
image after it has been rendered. I am a far cry from a 3d guru (or any
kind of guru really) =) but it seems like you have to end up with a 2d
image in the end, right? Why can't you just manipulate the information in
the 2d image after the rendering process is done?
I included a little test program that I was playing with. It tries writing
on the image in a couple of ways. One is using getGraphics() and the other
is using the getGraphics2D() function. The thing with the getGraphics() is
that it flickers like I am not double buffering. Like maybe I am writing
on the front buffer and then it is getting overwritten causing the
flicker. Seems like if I could get access to the back buffer I could just
write to it. The render is done using native code and stuff, but is it
not accessible through some sort of java abstraction?
I was thinking about trying to set up an off-screen canvas and rendering
on it and then copying the image out of it, writing something on it and
then painting it onto the screen. Would that work?
The getGraphics2D() function works, but it slows my PIII 550, GeForce 256,
128mb of ram to like 3 frames per second drawing a color cube. The little
testing program has 3 modes controlled by a bit mask. One is the
getGraphics and the other two are getGraphics2D both with waiting and not
waiting for the render to stop. (It has a negligible effect.) You can
specify any of the bit masks with a little scrollbar, so you can try them
all out.
Anyhow, I was just wondering if anyone could tell me why using the
getGraphics2D().flush() method takes so much time. And also if someone
could tell me why I can't just write on the 2d image after the 3d scene
has been rendered to it.
Or barring that maybe just some place I could go to find out these sorts
of things. =)
Thanks
Will Holcomb
P.S. Is anyone working on bridging the java3d api and the jmf? I am
working on something that makes a Canvas3D a jmf PushBufferStream but it
is still very buggy. I have had to put it off to do this VB stuff but I
was wondering if anyone else was working on something like this that they
were planning on releasing under some sort of open licence. The stuff I
have is at:
http://www.himinbi.org/public-cvsweb/cvsweb.cgi/RecordingCanvas3D
specfically the main class is at the very long url: (all jmf media sources
have to be in a media/protocol/protocolname structure so the other
classes can find them)
http://www.himinbi.org/public-cvsweb/cvsweb.cgi/RecordingCanvas3D/org/himinbi/media/protocol/c3d/StreamingCanvas3D.java
I want to provide read only cvs access to the repository soon but I have
to get it to the point where I can protect my non-public stuff else my
employer would likely not be very happy. =)
P.P.S. I read the stuff about floating point errors and what not in large
transformations and I was wondering if this was the cause of the problem
shown in:
http://www.himinbi.org/jars/Translation_Test.html
When you run the distance up to around a million meters you start seeing a
jitter that gets worse and worse as you get farther out. It looks like a
rounding error somewhere, but it would have to do with the Transform3D
class.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.*;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
public class ImageDrawHUD extends Applet {
HUDCanvas3D canvas = new HUDCanvas3D();
Scrollbar scrollbar = new Scrollbar(Scrollbar.HORIZONTAL,
canvas.getDrawMode(),
1,
HUDCanvas3D.DRAW_NONE,
HUDCanvas3D.DRAW_ALL + 1);
double cubeSize = 1;
public ImageDrawHUD() {
View view = new View();
view.setPhysicalBody(new PhysicalBody());
view.setPhysicalEnvironment(new PhysicalEnvironment());
view.addCanvas3D(canvas);
ViewPlatform viewPlatform = new ViewPlatform();
view.attachViewPlatform(viewPlatform);
BranchGroup sceneRoot = new BranchGroup();
sceneRoot.addChild(viewPlatform);
Transform3D initialCubePosition = new Transform3D();
initialCubePosition.setTranslation(new Vector3d(0, 0, -cubeSize * 5));
TransformGroup cubeMovement = new TransformGroup(initialCubePosition);
cubeMovement.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
cubeMovement.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
BoundingSphere bounds = new BoundingSphere(new Point3d(0, 0, 0), 100);
MouseRotate rotateBehavior = new MouseRotate(cubeMovement);
rotateBehavior.setSchedulingBounds(bounds);
cubeMovement.addChild(rotateBehavior);
MouseZoom zoomBehavior = new MouseZoom(cubeMovement);
zoomBehavior.setSchedulingBounds(bounds);
cubeMovement.addChild(zoomBehavior);
sceneRoot.addChild(cubeMovement);
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, 4000);
TransformGroup cubeRotation = new TransformGroup();
cubeRotation.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, cubeRotation, yAxis,
0, (float)(Math.PI * 2));
rotator.setSchedulingBounds(bounds);
sceneRoot.addChild(rotator);
cubeMovement.addChild(cubeRotation);
cubeRotation.addChild(new ColorCube(cubeSize));
sceneRoot.compile();
VirtualUniverse universe = new VirtualUniverse();
Locale locale = new Locale(universe);
locale.addBranchGraph(sceneRoot);
scrollbar.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
canvas.setDrawMode(scrollbar.getValue());
}
});
setLayout(new BorderLayout());
add(BorderLayout.CENTER, canvas);
add(BorderLayout.SOUTH, scrollbar);
}
public static void main(String[] args) {
new MainFrame(new ImageDrawHUD(), 512, 512);
}
}
class HUDCanvas3D extends Canvas3D {
public final static int DRAW_GRAPHICS = Integer.parseInt("1", 2);
public final static int DRAW_JGRAPHICS_WAIT = Integer.parseInt("10", 2);
public final static int DRAW_JGRAPHICS_NOWAIT = Integer.parseInt("100", 2);
public final static int DRAW_NONE = 0;
public final static int DRAW_ALL = (DRAW_GRAPHICS | DRAW_JGRAPHICS_WAIT |
DRAW_JGRAPHICS_NOWAIT);
int drawMode = DRAW_ALL;
boolean displayElapsedTime = true;
J3DGraphics2D jg2;
Graphics2D g2;
int lineHeight = 12;
int margin = 10;
Color color = Color.white;
public HUDCanvas3D() {
this(SimpleUniverse.getPreferredConfiguration());
}
public HUDCanvas3D(GraphicsConfiguration configuration) {
super(configuration);
}
public void postRender() {
if(jg2 == null) {
jg2 = getGraphics2D();
}
if(g2 == null) {
g2 = (Graphics2D)getGraphics();
}
double initialTime = 0, currentTime = 0, lastTime = 0;
if(displayElapsedTime) {
lastTime = initialTime = System.currentTimeMillis();
System.out.print("Draw:");
}
int lineCount = 0;
if((drawMode & DRAW_GRAPHICS) == DRAW_GRAPHICS) {
g2.setColor(color);
g2.drawString("Drawn using Component.getGraphics()",
margin, lineHeight * ++lineCount);
if(displayElapsedTime) {
currentTime = System.currentTimeMillis();
System.out.print(" g2d:" + (currentTime - lastTime));
lastTime = currentTime;
}
}
if((drawMode & DRAW_JGRAPHICS_WAIT) == DRAW_JGRAPHICS_WAIT) {
jg2.setColor(color);
jg2.drawString("Drawn using Canvas3D.getGraphics2D(), waiting on flush",
margin, lineHeight * ++lineCount);
jg2.flush(true);
if(displayElapsedTime) {
currentTime = System.currentTimeMillis();
System.out.print(" jg2d(w):" + (currentTime - lastTime));
lastTime = currentTime;
}
}
if((drawMode & DRAW_JGRAPHICS_NOWAIT) == DRAW_JGRAPHICS_NOWAIT) {
jg2.setColor(color);
jg2.drawString("Drawn using Canvas3D.getGraphics2D(), not waiting on
flush",
margin, lineHeight * ++lineCount);
jg2.flush(false);
if(displayElapsedTime) {
currentTime = System.currentTimeMillis();
System.out.print(" jg2d(nw):" + (currentTime - lastTime));
lastTime = currentTime;
}
}
if(displayElapsedTime) {
currentTime = System.currentTimeMillis();
System.out.println(" fr(ms/f):" + (currentTime - initialTime));
}
}
public int getDrawMode() {
return drawMode;
}
public void setDrawMode(int drawMode) {
this.drawMode = drawMode;
}
}