When a transformation is applied on a texture with a call to TextureAttributes#setTextureTransform, this transformation is also applied to the graphics drawn with a J3DGraphics2D instance returned by Canvas3D#getGraphics2D, when called in an postRender overridden method. In the following example, the red rectangle drawn in canvas postRender shouldn't be rotated. mport java.awt.*; import java.awt.image.BufferedImage; import javax.media.j3d.*; import javax.vecmath.Vector4f; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; public class TextureTransformTest { public static void main(String [] args) { // Create a box using a rotated texture BranchGroup scene = new BranchGroup(); Appearance appearance = new Appearance(); // Create a simple image with a white line BufferedImage image = new BufferedImage(4, 4, BufferedImage.TYPE_INT_ARGB); Graphics g = image.getGraphics(); g.setColor(Color.WHITE); g.drawLine(0, 0, 4, 0); g.dispose(); appearance.setTexture(new TextureLoader(image).getTexture()); // Rotate the texture TextureAttributes textureAttributes = new TextureAttributes(); Transform3D rotation = new Transform3D(); rotation.rotZ(Math.PI / 4); textureAttributes.setTextureTransform(rotation); appearance.setTextureAttributes(textureAttributes); appearance.setTexCoordGeneration(new TexCoordGeneration( TexCoordGeneration.OBJECT_LINEAR, TexCoordGeneration.TEXTURE_COORDINATE_2, new Vector4f(10, 0, 0, 10), new Vector4f(0, 10, -10, 10))); Box box = new Box(0.5f, 0.5f, 0.5f, appearance); scene.addChild(box); // Create a canvas 3D that post renders a red rectangle GraphicsConfiguration configuration = GraphicsEnvironment .getLocalGraphicsEnvironment().getDefaultScreenDevice() .getBestConfiguration(new GraphicsConfigTemplate3D()); Canvas3D canvas = new Canvas3D(configuration) { @Override public void postRender() { // Bug: The red rectangle is correct under Java 3D 1.3 // but is rotated under Java 3D 1.5.2 and 1.6 J3DGraphics2D g2D = getGraphics2D(); g2D.setColor(Color.RED); g2D.drawRect(10, 10, getWidth() - 20, getHeight() - 20); g2D.flush(true); } }; SimpleUniverse universe = new SimpleUniverse(canvas); universe.getViewingPlatform ().setNominalViewingTransform (); universe.addBranchGraph(scene); // Build a GUI that displays canvas Frame frame = new Frame("TextureTransformTest"); frame.add(canvas, BorderLayout.CENTER); frame.setSize(200, 200); frame.setVisible(true); } }
I can confirm this bug, it was killing me for years, I couldn't do a decent HUD. I have a workaround however. The issue (if it's the same as I've had) only occurs when teh transformation is on the last rendered object, the order of rendering being not controlable in normal usage. The work around is to render a trivial object in the postRender call just prior to getting the graphics, in Canvas3D sub class: // For reseting the texture binding in the pipeline private static Shape3D trivialShape = new Cube(0.01f); @Override public void postRender() { // if the last rendered texture on a canvas3d has a transformation // then calls to the J3DGraphics2D will inherit it. Easy way to ensure last texture is plain, render trival cube. getGraphicsContext3D().draw(trivialShape); J3DGraphics2D g = getGraphics2D(); //draw hud etc... } Hope this helps someone somewhere.
Thanks for the workaround, it works well. Trying to find a cleaner fix, I found that adding the following lines in JoglPipeline#texturemapping() after the call to gl.glEnable(GL.GL_TEXTURE_2D); would fix the problem: gl.glPushAttrib(GL2.GL_TRANSFORM_BIT); gl.glMatrixMode(GL.GL_TEXTURE); gl.glLoadIdentity(); gl.glPopAttrib(); I'm not sure that calls to gl.glPushAttrib and gl.glPopAttrib are mandatory. I borrowed this code from JoglPipeline#updateTextureAttributes method.
Fixed in branch 1.7.0