Hi Paul, Bug 4733554 - OrientedShape3D scale not work when set before live
is filed for this. To workaround ,please set the scale after shape live. Thanks for your bug report. - Kelvin -------------- Java 3D Team Sun Microsystems Inc. Paul Pantera wrote: > > OK, I've found a bug and an RFE in OrientedShape 3D with > constantScaleEnable: > > 1) The contructor for OrientedShape3D that takes a "scale" doesn't work > correctly - it always sets the scale to 1.0. In the example program > I'm setting the scale to 10, but it's getting 1 (zoom into the sphere > and you can see the label very small). You have to use the view menu > to set it to 1 and then back to 10 to get it to work right. > > Also, it's not clear to me why I need to set the scale to 10 in order > to see the label. The documentation says that the default scale is > 1.0 meters. It's coming out of Text2D with a size of 20/256 = > 0.078 meters, but I have to set the scale to about 5 to make it > seem that big. > > 2) Setting constantScale makes OrientedShape3D useless for labels (which > is one of its major purposes). When you move in and out the label > appears to move in and out with respect to the sphere it's labelling. > This is because the label is remaining at a constant position in Z. > So when the user moves in, the sphere appears to move closer, but > the label remains at the same distance. This is not the desired > effect. > Believe it or not, what we need is constant scale in X and Y and *not* > constant scale in Z. > > -Paul > > > ------------------------------------------------------------------------ > > import java.awt.*; > import java.awt.event.*; > import java.awt.Rectangle; > import java.util.AbstractList; > import java.util.ArrayList; > import java.util.Enumeration; > import java.util.Iterator; > > import javax.media.j3d.*; > import javax.vecmath.*; > import javax.swing.*; > > import com.sun.j3d.utils.geometry.Sphere; > import com.sun.j3d.utils.universe.PlatformGeometry; > import com.sun.j3d.utils.universe.SimpleUniverse; > import com.sun.j3d.utils.universe.ViewingPlatform; > import com.sun.j3d.utils.image.TextureLoader; > import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; > import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior; > import com.sun.j3d.utils.applet.JMainFrame; > import org.j3d.geom.RasterTextLabel; > > > import org.j3d.geom.*; > > public final class OS3DBugs extends JApplet { > > private static final Geometry sphereGeometry; > > private KeyNavigatorBehavior keyBehavior; > > private TransformGroup vptg; > > private static final float MOVE_BACK = 2.0f; > > private BranchGroup objRoot = null; > > private static final Color3f BLACK = new Color3f(0f, 0f, 0f); > private static final Color3f WHITE = new Color3f(1f, 1f, 1f); > private static final Color3f GREEN = new Color3f(0.5f, 1f, 0.5f); > > private SimpleUniverse u; > > private PlatformGeometry pg; > > private BoundingSphere bounds; > > private static final Point3d D_ORIGIN = new Point3d(0, 0, 0); > private static final Point3f F_ORIGIN = new Point3f(0, 0, 0); > > private Canvas3D c3d; > > private boolean constantScale = true; > private boolean scaleOne = false; > > private OrientedShape3D os3d; > > private boolean parallel = false; > > private static final float SPHERE_RADIUS = 0.2f; > > static { > final int SPHERE_TESSELATION = 20; > > Sphere s = > new Sphere(1.0f, Sphere.GENERATE_NORMALS, SPHERE_TESSELATION, null); > sphereGeometry = s.getShape().getGeometry(); > } // End of static initializer > > > > /** > * Set up keyboard navigation. > */ > private void addKeyBehavior(BranchGroup b) { > // Set up keyboard navigation > keyBehavior = new KeyNavigatorBehavior( > u.getViewingPlatform().getViewPlatformTransform()); > keyBehavior.setSchedulingBounds(bounds); > // Add behavior to scenegraph > b.addChild(keyBehavior); > } // End of addKeyBehavior > > > /** > * Initialize and return the Canvas3D we'll be using for rendering. > */ > public void init() { > > bounds = new BoundingSphere(D_ORIGIN, Double.POSITIVE_INFINITY); > > // Use utility to get the right graphics destination > GraphicsConfiguration config = > SimpleUniverse.getPreferredConfiguration(); > > // Create a canvas on the device > c3d = new Canvas3D(config); > > Container contentPane = getContentPane(); > contentPane.setLayout(new BorderLayout()); > contentPane.add(c3d, "Center"); > JPopupMenu.setDefaultLightWeightPopupEnabled(false); > JMenuBar menuBar = new JMenuBar(); > setJMenuBar(menuBar); > > JMenu viewMenu = new JMenu("View"); > menuBar.add(viewMenu); > > JMenuItem constantScaleItem = new JMenuItem("not constantScale"); > viewMenu.add(constantScaleItem); > constantScaleItem.addActionListener( > new ActionListener() { > public void actionPerformed(ActionEvent e) { > JMenuItem constantScaleItem = (JMenuItem)e.getSource(); > constantScale = !constantScale; > os3d.setConstantScaleEnable(constantScale); > if (constantScale) { > constantScaleItem.setText("not constantScale"); > } else { > constantScaleItem.setText("constantScale"); > } > } > } > ); > JMenuItem scaleOneItem = new JMenuItem("scale = 1"); > viewMenu.add(scaleOneItem); > scaleOneItem.addActionListener( > new ActionListener() { > public void actionPerformed(ActionEvent e) { > JMenuItem scaleOneItem = (JMenuItem)e.getSource(); > scaleOne = !scaleOne; > if (scaleOne) { > scaleOneItem.setText("scale = 10"); > os3d.setScale(1.0); > } else { > scaleOneItem.setText("scale = 1"); > os3d.setScale(10.0); > } > } > } > ); > JMenuItem projectionItem = new JMenuItem("Parallel Projection"); > viewMenu.add(projectionItem); > projectionItem.addActionListener( > new ActionListener() { > public void actionPerformed(ActionEvent e) { > JMenuItem projectionItem = (JMenuItem)e.getSource(); > parallel = !parallel; > if (parallel) { > c3d.getView().setProjectionPolicy(View.PARALLEL_PROJECTION); > } else { > c3d.getView().setProjectionPolicy(View.PERSPECTIVE_PROJECTION); > } > } > } > ); > > > // Use utility to create default universe > u = new SimpleUniverse(c3d); > > // Set the viewpoint back from the origin and point toward the origin > ViewingPlatform vp = u.getViewingPlatform(); > > vp.setNominalViewingTransform(); > vptg = vp.getViewPlatformTransform(); > Transform3D vpt = new Transform3D(); > vptg.getTransform(vpt); > Transform3D translate = new Transform3D(); > translate.setTranslation(new Vector3f(0f,0f,MOVE_BACK)); > vpt.mul(translate); > vptg.setTransform(vpt); > > // Allow mouse manipulation > OrbitBehavior orbit = new OrbitBehavior(c3d, OrbitBehavior.REVERSE_ALL); > > // Behavior is only enabled within its bounds > bounds = new BoundingSphere(D_ORIGIN, 100.0); > orbit.setSchedulingBounds(bounds); > > // Attach behavior to ViewingPlatform > vp.setViewPlatformBehavior(orbit); > > // Will add lights here so they are "headlights" > // that move with the viewer > pg = new PlatformGeometry(); > > // Set up the ambient light > Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f); > AmbientLight ambientLightNode = new AmbientLight(ambientColor); > ambientLightNode.setInfluencingBounds(bounds); > pg.addChild(ambientLightNode); > > // Set up the directional lights > Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); > Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f); > Color3f light2Color = new Color3f(1.0f, 1.0f, 1.0f); > Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f); > > DirectionalLight light1 > = new DirectionalLight(light1Color, light1Direction); > light1.setInfluencingBounds(bounds); > pg.addChild(light1); > > DirectionalLight light2 > = new DirectionalLight(light2Color, light2Direction); > light2.setInfluencingBounds(bounds); > pg.addChild(light2); > > vp.setPlatformGeometry(pg); > > objRoot = new BranchGroup(); > objRoot.setCapability(objRoot.ALLOW_DETACH); > objRoot.setCapability(objRoot.ALLOW_CHILDREN_EXTEND); > objRoot.setCapability(objRoot.ALLOW_CHILDREN_WRITE); > > addKeyBehavior(objRoot); > > objRoot.compile(); > > u.addBranchGraph(objRoot); > > addNode(); > > } // End of init > > > /** > * Add a node to the graph. > */ > public void addNode() > { > // Each node is connected by a BranchGroup (to allow it to > // be removed) > BranchGroup root = new BranchGroup(); > > // Transform Group to hold position transform > TransformGroup posTg = new TransformGroup(); > Transform3D pos = new Transform3D(); > Vector3f translate = new Vector3f(0.2f,0f,0f); > pos.setTranslation(translate); > posTg.setTransform(pos); > root.addChild(posTg); > > // TransformGroup to hold scale transform > TransformGroup scaleTg = new TransformGroup(); > Transform3D scale = new Transform3D(); > scale.setScale(SPHERE_RADIUS); > scaleTg.setTransform(scale); > posTg.addChild(scaleTg); > > // Set appearance of node > RenderingAttributes ra = new RenderingAttributes(); > Material mat = new Material(BLACK, BLACK, GREEN, WHITE, 128.0f); > Appearance a = new Appearance(); > a.setMaterial(mat); > a.setRenderingAttributes(ra); > > Shape3D shape = new Shape3D(sphereGeometry, a); > > scaleTg.addChild(shape); > > BranchGroup bg = new BranchGroup(); > > MyText2D t2d = new MyText2D("OrientedShape3D constantScaleEnable", > WHITE, null, 20, 0); > QuadArray qa = (QuadArray)t2d.getGeometry(); > float[] ar = new float[12]; > qa.getCoordinates(0, ar); > float width = t2d.getImageWidth(); > float height = t2d.getImageHeight(); > for (int i = 0 ; i < 4 ; i++) { > // Center > ar[0 + i * 3] -= width / 2; > ar[1 + i * 3] -= height / 2; > // Move forward in front of sphere > ar[2 + i * 3] = SPHERE_RADIUS; > } > qa.setCoordinates(0, ar); > Appearance labelApp = t2d.getAppearance(); > os3d = new OrientedShape3D(qa, labelApp, > OrientedShape3D.ROTATE_ABOUT_POINT, F_ORIGIN, true, 10.0); > os3d.setCapability(OrientedShape3D.ALLOW_SCALE_WRITE); > posTg.addChild(os3d); > > root.compile(); > > objRoot.addChild(root); > } // End of addNode > > > public static void main(String[] args) { > new JMainFrame(new OS3DBugs(args), 500, 500); > } > > public OS3DBugs(String[] args) > { > } > > public OS3DBugs() > { > } > } // End of file RenderEngine.java > > > ------------------------------------------------------------------------ > > import java.awt.image.BufferedImage; > import java.awt.image.WritableRaster; > import java.awt.image.DataBufferInt; > import java.awt.Color; > import java.awt.Font; > import java.awt.FontMetrics; > import java.awt.Graphics; > import java.awt.Toolkit; > import java.util.Hashtable; > > import javax.media.j3d.*; > import javax.vecmath.Color3f; > > > /** > * A Text2D object is a representation of a string as a texture mapped > * rectangle. The texture for the rectangle shows the string as rendered in > * the specified color with a transparent background. The appearance of the > * characters is specified using the font indicated by the font name, size > * and style (see java.awt.Font). The approximate height of the rendered > * string will be the font size times the rectangle scale factor, which has a > * default value of 1/256. For example, a 12 point font will produce > * characters that are about 12/256 = 0.047 meters tall. The lower left > * corner of the rectangle is located at (0,0,0) with the height > * extending along the positive y-axis and the width extending along the > * positive x-axis.<p> > * Java 3D texture maps must be a power of two. Therefore, > * the texture mapped onto the quad by Text2D (and the quad) > * may be much bigger than they need to be. The only way to > * get the actual size of the text is withing Text2D, so we'd > * have to import the utility into our code. > */ > public class MyText2D extends Shape3D { > > // This table caches FontMetrics objects to avoid the huge cost > // of re-retrieving metrics for a font we've already seen. > private static Hashtable metricsTable = new Hashtable(); > float rectangleScaleFactor = 1f/256; > > Color3f color = new Color3f(); > String fontName; > int fontSize, fontStyle; > > String text; > > float imageWidth, imageHeight; > > > /** > * Creates a Shape3D object which holds a > * rectangle that is texture-mapped with an image that has > * the specified text written with the specified font > * parameters. > * > * @param text The string to be written into the texture map. > * @param color The color of the text string. > * @param fontName The name of the Java font to be used for > * the text string. > * @param fontSize The size of the Java font to be used. > * @param fontStyle The style of the Java font to be used. > */ > public MyText2D(String text, Color3f color, String fontName, > int fontSize, int fontStyle) { > > this.color.set(color); > this.fontName = fontName; > this.fontSize = fontSize; > this.fontStyle = fontStyle; > this.text = text; > > updateText2D(text, color, fontName, fontSize, fontStyle); > } > > /* > * Changes text of this Text2D to 'text'. All other > * parameters (color, fontName, fontSize, fontStyle > * remain the same. > * @param text The string to be set. > */ > public void setString(String text){ > this.text = text; > ImageComponent imageComponent = setupImage(text, color, fontName, > fontSize, fontStyle); > getAppearance().getTexture().setImage(0, imageComponent); > } > > private void updateText2D(String text, Color3f color, String fontName, > int fontSize, int fontStyle) { > ImageComponent imageComponent = setupImage(text, color, fontName, > fontSize, fontStyle); > > Texture2D t2d = setupTexture(imageComponent); > > QuadArray rect = setupGeometry(imageComponent.getWidth(), > imageComponent.getHeight()); > setGeometry(rect); > > Appearance appearance = setupAppearance(t2d); > setAppearance(appearance); > } > > > /** > * Sets the scale factor used in converting the image width/height > * to width/height values in 3D. > * > * @param newScaleFactor The new scale factor. > */ > public void setRectangleScaleFactor(float newScaleFactor) { > rectangleScaleFactor = newScaleFactor; > } > > /** > * Gets the current scale factor being used in converting the image > * width/height to width/height values in 3D. > * > * @return The current scale factor. > */ > public float getRectangleScaleFactor() { > return rectangleScaleFactor; > } > > /** > * Create the ImageComponent and Texture object. > */ > private Texture2D setupTexture(ImageComponent imageComponent) { > Texture2D t2d = new Texture2D(Texture2D.BASE_LEVEL, > Texture.RGBA, > imageComponent.getWidth(), > imageComponent.getHeight()); > t2d.setMinFilter(t2d.BASE_LEVEL_LINEAR); > t2d.setMagFilter(t2d.BASE_LEVEL_LINEAR); > t2d.setImage(0, imageComponent); > t2d.setEnable(true); > > return t2d; > } > > /** > * Creates a ImageComponent2D of the correct dimensions for the > * given font attributes. Draw the given text into the image in > * the given color. The background of the image is transparent > * (alpha = 0). > */ > private ImageComponent setupImage(String text, Color3f color, > String fontName, > int fontSize, int fontStyle) { > Toolkit toolkit = Toolkit.getDefaultToolkit(); > Font font = new java.awt.Font(fontName, fontStyle, fontSize); > > FontMetrics metrics; > if ((metrics = (FontMetrics)metricsTable.get(font)) == null) { > metrics = toolkit.getFontMetrics(font); // deprecated > metricsTable.put(font, metrics); > } > int width = metrics.stringWidth(text); > int descent = metrics.getMaxDescent(); > int ascent = metrics.getMaxAscent(); > int leading = metrics.getLeading(); > int height = descent + ascent; > > imageWidth = (float)width * rectangleScaleFactor; > imageHeight = (float)height * rectangleScaleFactor; > > // Need to make width/height powers of 2 because of Java3d texture > // size restrictions > int pow = 1; > for (int i = 1; i < 32; ++i) { > pow *= 2; > if (width <= pow) > break; > } > width = Math.max (width, pow); > pow = 1; > for (int i = 1; i < 32; ++i) { > pow *= 2; > if (height <= pow) > break; > } > height = Math.max (height, pow); > > // For now, jdk 1.2 only handles ARGB format, not the RGBA we want > BufferedImage bImage = new BufferedImage(width, height, > BufferedImage.TYPE_INT_ARGB); > Graphics offscreenGraphics = bImage.createGraphics(); > > // First, erase the background to the text panel - set alpha to 0 > Color myFill = new Color(0f, 0f, 0f, 0f); > offscreenGraphics.setColor(myFill); > offscreenGraphics.fillRect(0, 0, width, height); > > // Next, set desired text properties (font, color) and draw String > offscreenGraphics.setFont(font); > Color myTextColor = new Color(color.x, color.y, color.z, 1f); > offscreenGraphics.setColor(myTextColor); > offscreenGraphics.drawString(text, 0, height - descent); > > ImageComponent imageComponent = > new ImageComponent2D(ImageComponent.FORMAT_RGBA, > bImage); > return imageComponent; > } > > /** > * Creates a rectangle of the given width and height and sets up > * texture coordinates to map the text image onto the whole surface > * of the rectangle (the rectangle is the same size as the text image) > */ > private QuadArray setupGeometry(int width, int height) { > float zPosition = 0f; > float rectWidth = (float)width * rectangleScaleFactor; > float rectHeight = (float)height * rectangleScaleFactor; > float[] verts1 = { > rectWidth, 0f, zPosition, > rectWidth, rectHeight, zPosition, > 0f, rectHeight, zPosition, > 0f, 0f, zPosition > }; > float[] texCoords = { > 0f, -1f, > 0f, 0f, > (-1f), 0f, > (-1f), -1f > }; > > QuadArray rect = new QuadArray(4, QuadArray.COORDINATES | > QuadArray.TEXTURE_COORDINATE_2); > rect.setCoordinates(0, verts1); > rect.setTextureCoordinates(0, 0, texCoords); > > return rect; > } > > /** > * Creates Appearance for this Shape3D. This sets transparency > * for the object (we want the text to be "floating" in space, > * so only the text itself should be non-transparent. Also, the > * appearance disables lighting for the object; the text will > * simply be colored, not lit. > */ > private Appearance setupAppearance(Texture2D t2d) { > TransparencyAttributes transp = new TransparencyAttributes(); > transp.setTransparencyMode(TransparencyAttributes.BLENDED); > transp.setTransparency(0f); > Appearance appearance = new Appearance(); > appearance.setTransparencyAttributes(transp); > appearance.setTexture(t2d); > > Material m = new Material(); > m.setLightingEnable(false); > appearance.setMaterial(m); > > return appearance; > } > > /** > * Returns the text string > * > */ > public String getString() { > return text; > } > > /** > * Returns the color of the text > * > */ > public Color3f getColor() { > return color; > } > > /** > * Returns the font > * > */ > public String getFontName() { > return fontName; > } > > /** > * Returns the font size > * > */ > public int getFontSize() { > return fontSize; > } > > /** > * Returns the font style > * > */ > public int getFontStyle() { > return fontStyle; > } > > public float getImageWidth() { > return imageWidth; > } > > public float getImageHeight() { > return imageHeight; > } > > } > > > > > > =========================================================================== To unsubscribe, send email to [EMAIL PROTECTED] and include in the body of the message "signoff JAVA3D-INTEREST". For general help, send email to [EMAIL PROTECTED] and include in the body of the message "help".