Hi,
I've encountered some problems using Java3D 1.6-pre9 with updating the Texture3D and offscreen canvas rendering. It works fine on Java3D 1.5.2 so I assume this is some kind of bug. I am running Linux x86_64. The problem is the same on Java 6, Java 7 and all tested JREs. The case is as follows: - the universe has some geometry using Texture3D - a default Canvs3D is used for Swing view and manipulation - additional offscreen Canvas3D is used for writting JPEGs - every off screen JPEG is rendered fine, as long as the texture doesn't change - after texture change with appearance.setTexture method, every offscreen rendered frame is identical to the one saved before texture change The code to reproduce is below. Set the path to store images. Left-click to switch texture, right-click to save JPEG. Reproduce problem by following steps: run application, right click to save image, left click to change texture, rotate, right click to save image again. Both saved images are the same. This is of course just a simplified extracted example. The full scenario is much more complex and it is required to set texture of different dimensions sometimes, so the code of switching texture could not be much simplified. Any ideas? <pre> import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.universe.SimpleUniverse; import java.awt.BorderLayout; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.FileImageOutputStream; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.GeometryArray; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.ImageComponent3D; import javax.media.j3d.Node; import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture3D; import javax.media.j3d.TransparencyAttributes; import javax.media.j3d.View; import javax.swing.JFrame; import javax.swing.JPanel; import javax.vecmath.Point3d; public class Texture3DTest { private static int counter = 0; private static int textureType = 1; private static String pathPrefix = "/tmp"; public static void main(String[] args) { JFrame frame = new JFrame("test frame"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(0, 0, 640, 480); frame.setLayout(new BorderLayout()); JPanel canvasParent = new JPanel(); canvasParent.setLayout(new BorderLayout()); GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); GraphicsConfiguration gcfg = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getBestConfiguration(template); Canvas3D canvas = new Canvas3D(gcfg); BoundingSphere universeBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100000.0); SimpleUniverse universe = new SimpleUniverse(canvas); View view = canvas.getView(); view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION); view.setTransparencySortingPolicy(View.TRANSPARENCY_SORT_GEOMETRY); OrbitBehavior orbit = new OrbitBehavior(universe.getCanvas(), OrbitBehavior.REVERSE_ALL); orbit.setSchedulingBounds(universeBounds); universe.getViewingPlatform().setViewPlatformBehavior(orbit); BranchGroup scene = new BranchGroup(); //-----------------add 3D textured planes--------------------------- Shape3D tr = new Shape3D(); final Appearance ap = new Appearance(); ap.setCapability(Appearance.ALLOW_TEXTURE_WRITE); tr.setCapability(Shape3D.ALLOW_APPEARANCE_READ); tr.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); tr.setCapability(Shape3D.ALLOW_GEOMETRY_READ); tr.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); tr.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ); TransparencyAttributes ta = new TransparencyAttributes(); ta.setTransparencyMode(TransparencyAttributes.BLENDED); ta.setCapability(TransparencyAttributes.ALLOW_VALUE_READ); ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); ap.setTransparencyAttributes(ta); setTexture(ap,textureType); tr.setAppearance(ap); QuadArray volMesh = new QuadArray(12, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_3); volMesh.setCapability(GeometryArray.ALLOW_TEXCOORD_READ); volMesh.setCapability(GeometryArray.ALLOW_TEXCOORD_WRITE); volMesh.setCapability(GeometryArray.ALLOW_COORDINATE_READ); volMesh.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE); float[] textureCoords = new float[]{ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,}; for (int i = 0; i < textureCoords.length; i++) { if (textureCoords[i] == 1.0f) { textureCoords[i] -= 0.25f; } if (textureCoords[i] == 0.0f) { textureCoords[i] += 0.25f; } } volMesh.setTextureCoordinates(0, 0, textureCoords); float[] coords = new float[]{ -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, -0.5f, 0.5f, 0.0f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f,}; volMesh.setCoordinates(0, coords); tr.setGeometry(volMesh); scene.addChild(tr); universe.addBranchGraph(scene); universe.getViewingPlatform().setNominalViewingTransform(); canvasParent.add(canvas, BorderLayout.CENTER); frame.add(canvasParent, BorderLayout.CENTER); frame.setVisible(true); //------------------add off screen canvas----------------------- final Canvas3D offScreenCanvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration(), true); int w = canvas.getWidth(); int h = canvas.getHeight(); final BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); ImageComponent2D imC = new ImageComponent2D(ImageComponent2D.FORMAT_RGB, im, true, false); imC.setCapability(ImageComponent2D.ALLOW_IMAGE_READ); offScreenCanvas.setOffScreenLocation(0, 0); offScreenCanvas.setOffScreenBuffer(imC); offScreenCanvas.getScreen3D().setSize(w, h); offScreenCanvas.getScreen3D().setPhysicalScreenWidth(0.0254 / 90.0 * canvas.getWidth()); offScreenCanvas.getScreen3D().setPhysicalScreenHeight(0.0254 / 90.0 * canvas.getHeight()); universe.getViewer().getView().addCanvas3D(offScreenCanvas); canvas.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { switch(e.getButton()) { case MouseEvent.BUTTON1: //left click to change texture if(textureType == 0) { textureType = 1; } else { textureType = 0; } setTexture(ap, textureType); break; case MouseEvent.BUTTON3: //right click to write image offScreenCanvas.renderOffScreenBuffer(); offScreenCanvas.waitForOffScreenRendering(); BufferedImage img = new BufferedImage(im.getWidth(), im.getHeight(), BufferedImage.TYPE_INT_RGB); img.createGraphics().drawImage(im, null, null); String filePath = String.format(pathPrefix+File.separator+"image%03d.jpg",counter++); writeJpeg(img, filePath); break; } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }); } private static void writeJpeg(BufferedImage img, String filePath) { try { Iterator iter = ImageIO.getImageWritersByFormatName("jpeg"); ImageWriter writer = (ImageWriter) iter.next(); ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); iwp.setCompressionQuality(1.0f); File f = new File(filePath); FileImageOutputStream output = new FileImageOutputStream(f); writer.setOutput(output); IIOImage image = new IIOImage(img, null, null); writer.write(null, image, iwp); writer.dispose(); } catch(IOException ex) { } } private static void setTexture(Appearance ap, int type) { BufferedImage[] texImages = new BufferedImage[2]; if(type == 0) { //gray texture texImages[0] = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); WritableRaster raster0 = texImages[0].getRaster(); raster0.setPixel(0, 0, new int[]{255, 255, 255, 0}); raster0.setPixel(0, 1, new int[]{255, 255, 255, 0}); raster0.setPixel(1, 0, new int[]{255, 255, 255, 255}); raster0.setPixel(1, 1, new int[]{255, 255, 255, 255}); texImages[1] = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); WritableRaster raster1 = texImages[1].getRaster(); raster1.setPixel(0, 0, new int[]{255, 255, 255, 0}); raster1.setPixel(0, 1, new int[]{255, 255, 255, 0}); raster1.setPixel(1, 0, new int[]{255, 255, 255, 255}); raster1.setPixel(1, 1, new int[]{255, 255, 255, 255}); } else { //colored texture texImages[0] = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); WritableRaster raster0 = texImages[0].getRaster(); raster0.setPixel(0, 0, new int[]{255, 0, 0, 0}); raster0.setPixel(0, 1, new int[]{255, 0, 0, 0}); raster0.setPixel(1, 0, new int[]{255, 0, 0, 255}); raster0.setPixel(1, 1, new int[]{255, 0, 0, 255}); texImages[1] = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB); WritableRaster raster1 = texImages[1].getRaster(); raster1.setPixel(0, 0, new int[]{0, 255, 0, 0}); raster1.setPixel(0, 1, new int[]{0, 255, 0, 0}); raster1.setPixel(1, 0, new int[]{0, 255, 0, 255}); raster1.setPixel(1, 1, new int[]{0, 255, 0, 255}); } ImageComponent3D i3d = new ImageComponent3D(ImageComponent3D.FORMAT_RGBA, texImages, true, true); Texture3D tx3d = new Texture3D(Texture3D.BASE_LEVEL, Texture3D.RGBA, 2, 2, 2); tx3d.setMagFilter(Texture3D.BASE_LEVEL_LINEAR); tx3d.setMinFilter(Texture3D.BASE_LEVEL_LINEAR); tx3d.setEnable(true); tx3d.setImage(0, i3d); ap.setTexture(tx3d); } } </pre> |
Administrator
|
Do you reproduce this bug when you create a new Appearance each time you use another texture?
Julien Gouesse | Personal blog | Website
|
Yes. The behaviour is exactly the same. |
I'm getting the sneaking suspicion this is related to another bug:
http://forum.jogamp.org/Texture2D-and-offscreen-rendering-problem-td4030882.html I thought this was all related to the offscreen image capture, but I wonder if there is confusion in the joglpipeline with texture binding, thanks for another breadcrumb! Harvey |
This one behaves even more strange. However, the one reported by me with texture 3D has one workaround - captured images look fine when you create new offscreen after setting new Texture3D. This does not fix the bug with 2D texture. |
Free forum by Nabble | Edit this page |