Hi everyone,
I currently received a job to fix a project that was developed 15 years ago and was still running 2 years ago. It was using an ancient version of Java3d 1.5.2 before and it is no longer work on the Mac OSX. So I ported this project to Java3d 1.6.0 from here and Java 1.8. The problem is that everything works fine with no warning or errors but only a black background is rendered in the window. I attached the code I used to test. It should render a color cube however nothing is actually rendered. Only a window with black background is shown. I am new to Java3d so please correct me if I am wrong. I feel the problem happens with the GraphicsContext3D's draw method as I tried with several different test code snippet and only the code uses GraphicsContext3D failed to render. However, I have no idea how to fix this problem without changing the structure too much. I tried this project on both Mac Mojave, High Sierra, and El Capitan but none of the operating system worked. Any suggestion would be helpful. Thanks in advance. ------------------------------------------------------------------------------------------ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.GraphicsConfiguration; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.Canvas3D; import javax.media.j3d.Geometry; import javax.media.j3d.GraphicsContext3D; import javax.media.j3d.Transform3D; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.SimpleUniverse; /** * Pure immediate mode example program. In pure immediate mode, the renderer * must be stopped on the Canvas being rendered into. In our example, this is * done immediately after the canvas is created. A separate thread is started up * to do the immediate mode rendering. */ public class PureImmediate extends Applet implements Runnable { private Canvas3D canvas; private GraphicsContext3D gc = null; private Geometry cube = null; private Transform3D cmt = new Transform3D(); // One rotation (2*PI radians) every 6 seconds private Alpha rotAlpha = new Alpha(-1, 6000); private SimpleUniverse u = null; // // Renders a single frame by clearing the canvas, drawing the // geometry, and swapping the draw and display buffer. // public void render() { if (gc == null) { // Set up Graphics context gc = canvas.getGraphicsContext3D(); gc.setAppearance(new Appearance()); // Set up geometry cube = new ColorCube(0.4).getGeometry(); } // Compute angle of rotation based on alpha value double angle = rotAlpha.value() * 2.0 * Math.PI; cmt.rotY(angle); // Render the geometry for this frame gc.clear(); gc.setModelTransform(cmt); gc.draw(cube); canvas.swap(); } // // Run method for our immediate mode rendering thread. // public void run() { System.out.println("PureImmediate.run: starting main loop"); while (true) { render(); Thread.yield(); } } public PureImmediate() { } // // init: create the canvas, stop the renderer, // create the universe, and start the drawing thread. // public void init() { setLayout(new BorderLayout()); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); canvas = new Canvas3D(config); canvas.stopRenderer(); add("Center", canvas); // Create the universe and viewing branch u = new SimpleUniverse(canvas); // This will move the ViewPlatform back a bit so the // objects in the scene can be viewed. u.getViewingPlatform().setNominalViewingTransform(); // // Start a new thread that will continuously render new Thread(this).start(); } public void destroy() { u.cleanup(); } // // The following allows PureImmediate to be run as an application // as well as an applet // public static void main(String[] args) { System.setProperty("sun.awt.noerasebackground", "true"); new MainFrame(new PureImmediate(), 256, 256); } } |
Hi,
Thanks for this bug report. I see that the example you've given is basically the pure immediate mode from the java3d-examples. The good news is that this code also doesn't work for me, so I will start stepping through to see if I can find the problem. I would note that I've never seen this example code working so it might take a little longer to track down the issue. Thanks, Phil. |
Thanks for your quick reply.
I have found this post that is very similar to my problem. http://forum.jogamp.org/Java3D-stereo-td4029914.html In this post the StereoTestJava3D which used GraphicsContext3D didn't work. However, the code for StereoTestJogl actually worked after I made some minor changes in importing package's name. All code in other thread that didn't use GraphicsContext3D is working. I tried to solve this problem by following the solution mentioned here but it didn't solve my problem. Hope these information can bring more context to you and help you identify the problem easier. Thanks, Wenlin |
Ok good news, I've discovered the source of the problem, but I may need GouesseJ's advice on how to fix it correctly.
Here is a listing of the verbose output from the JoglPipeline of a Retained mode rendering cycle, that simply renders the same cube onto the same canvas. Retained mode is the "normal" Java3D mode where the rendering thread simply loops and renders constantly (where needed). Note I've trimmed away the setup calls as they are identical (because the code calling them is also identical - the createUniverse method) JoglPipeline.validGraphicsMode() Returning true JoglPipeline.createNewContext() JoglPipeline.updateSeparateSpecularColorEnable() JoglPipeline.setSceneAmbient() JoglPipeline.disableFog() JoglPipeline.resetRenderingAttributes() JoglPipeline.resetTextureNative() JoglPipeline.resetTexCoordGeneration() JoglPipeline.resetTextureAttributes() JoglPipeline.resetPolygonAttributes() JoglPipeline.resetLineAttributes() JoglPipeline.resetPointAttributes() JoglPipeline.resetTransparency() JoglPipeline.resetColoringAttributes() JoglPipeline.updateMaterialColor() JoglPipeline.useCtx() JoglPipeline.setViewport() JoglPipeline.setRenderMode() JoglPipeline.clear() JoglPipeline.setRenderMode() JoglPipeline.setProjectionMatrix() JoglPipeline.setVertexFormat() JoglPipeline.setModelViewMatrix() JoglPipeline.setLightEnables() JoglPipeline.setSceneAmbient() JoglPipeline.disableFog() JoglPipeline.disableModelClip() JoglPipeline.resetRenderingAttributes() JoglPipeline.resetPolygonAttributes() JoglPipeline.resetTransparency() JoglPipeline.updateMaterialColor() JoglPipeline.resetColoringAttributes() JoglPipeline.setModelViewMatrix() JoglPipeline.execute() JoglPipeline.executeGeometryArray() JoglPipeline.testForInterleavedArrays() JoglPipeline.setRenderMode() JoglPipeline.syncRender() JoglPipeline.swapBuffers() JoglPipeline.releaseCtx() Compare with the same output for the immediate mode example JoglPipeline.validGraphicsMode() Returning true JoglPipeline.createNewContext() JoglPipeline.updateSeparateSpecularColorEnable() JoglPipeline.setSceneAmbient() JoglPipeline.disableFog() JoglPipeline.resetRenderingAttributes() JoglPipeline.resetPolygonAttributes() JoglPipeline.resetLineAttributes() JoglPipeline.resetPointAttributes() JoglPipeline.resetTransparency() JoglPipeline.resetColoringAttributes() JoglPipeline.updateMaterialColor() JoglPipeline.activeTextureUnit() JoglPipeline.resetTransparency() JoglPipeline.getNumCtxLights() JoglPipeline.clear() JoglPipeline.setViewport() JoglPipeline.setProjectionMatrix() JoglPipeline.setModelViewMatrix() JoglPipeline.activeTextureUnit() JoglPipeline.resetTransparency() JoglPipeline.setModelViewMatrix() JoglPipeline.setSceneAmbient() JoglPipeline.setLightEnables() JoglPipeline.setModelViewMatrix() JoglPipeline.setVertexFormat() JoglPipeline.execute() JoglPipeline.executeGeometryArray() JoglPipeline.testForInterleavedArrays() JoglPipeline.syncRender() JoglPipeline.swapBuffers() Apart from some texture calls that differ (we have no textures in the example) and a few order of operations the most significant difference is the lack of useCtx and releaseCtx calls. So when I insert the function from useCtx context(ctx).makeCurrent(); into the first interesting render operation for immediate mode - updateSeparateSpecularColorEnable I get Woot! so to get your code going, if you have the source for 1.6.0 and are willing to compile it, in the JoglPipeline class add this line // Native method to update separate specular color control @Override void updateSeparateSpecularColorEnable(Context ctx, boolean enable) { if (VERBOSE) System.err.println("JoglPipeline.updateSeparateSpecularColorEnable()"); context(ctx).makeCurrent(); GL2 gl = context(ctx).getGL().getGL2(); if (enable) { gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); } else { gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SINGLE_COLOR); } } I will now put together a fix that involves the renderer always using and releasing the context on pure immediate calls, along with the first create of context in GraphicsContext3D.doClear using the context correctly as well. Note the fix I'm proposing will require all pure immedate systems to call doClear on the GraphicContext3D immedately after creation like this public void render() { System.out.println("render"); if (gc == null) { // Set up Graphics context gc = canvas.getGraphicsContext3D(); gc.clear();// clear must be the first call for pure immediate to set up the context and pipeline gc.setAppearance(new Appearance());// calls GraphicsContext3D.doSetAppearance a sync // Set up geometry cube = new ColorCube(0.4).getGeometry(); } ... Julien, Harvey I'll put together a git pull request with the changes I think are required shortly, can you check it and see if it will cause trouble or be incomplete or there is a better way to solve the problem. Thanks, Phil. |
Administrator
|
I'll review your pull request with pleasure but I'd like to know Harvey's opinion.
It looks good to me. I'm a bit annoyed by the necessary call to clear().
Julien Gouesse | Personal blog | Website
|
Yes, the doClear call seems needless, however in the entire code base there are only 3 calls to Canvas3d.createNewContext().
Two of them are in the Renderer class loop in the retained mode section (after the immediate mode if case) called whenever retained mode is doing anything and it checks for a context and lazily creates if needed. The other one is in the immediate mode doClear call. I would like to take the immediate mode create call out into the Renderer and have it run as a lazy init before any of the immediate mode calls, just like the retianed is doing now. But that's a fairly major code change that may have unknown impacts. |
Ok I've done a pull request that should fix it and does not demand the doClear
|
Administrator
|
Good job :)
Julien Gouesse | Personal blog | Website
|
In reply to this post by philjord
Thanks for fixing this bug. Now everything works.
|
That's good news.
Please post any other questions/problems you come across in the future. The link to the pull (in case anyone needs it): https://github.com/hharrison/java3d-core/pull/27 |
Free forum by Nabble | Edit this page |