Bug 1006 - Transformation applied to a texture is also applied to post render graphics
Summary: Transformation applied to a texture is also applied to post render graphics
Status: RESOLVED FIXED
Alias: None
Product: Java3D
Classification: Unclassified
Component: core (show other bugs)
Version: unspecified
Hardware: All all
: --- normal
Assignee: Phil Jordan
URL:
Depends on:
Blocks:
 
Reported: 2014-05-06 14:20 CEST by Manu
Modified: 2016-10-26 02:00 CEST (History)
2 users (show)

See Also:
Type: DEFECT
SCM Refs:
Workaround: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Manu 2014-05-06 14:20:37 CEST
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);
  }
}
Comment 1 Phil Jordan 2015-08-07 10:55:42 CEST
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.
Comment 2 Manu 2016-10-18 12:09:45 CEST
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.
Comment 3 Phil Jordan 2016-10-26 02:00:42 CEST
Fixed in branch 1.7.0