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".