OK, Kelvin has filed two bugs on my behalf: > Hi Paul, > > I've filed bug 4732956 > - Raster z value set incorrectly when setDstOffset() or CLIP_IMAGE mode is used > > for problem (1). > Culling works fine if setDstOffset() and CLIP_IMAGE mode is not used.
> For (5) bug 4732965 > - Raster CLIP_IMAGE mode cause flickering when part of it is clipped Kelvin is right. If you don't use CLIP_IMAGE or setDstOffset, everything seems to work fine. Anyone have a workaround for the setDstOffset problem? I need the raster to be centered at its location, so this means I need to move it up and to the left by half its height and width. The width and height are measured in pixels. Since one pixel is a greater distance when further from the eye this will need to be a behavior that sets the offset in a transform depending on the current Z value. How do I compute that transform to convert pixels into object coordinates? My guess: (getLocalToVworld.mul(getVworldToImagePlate)).inverse. This should give me an image plate to local transform. I'll try that and see if it works. -Paul Paul Pantera wrote: > > OK, I've composed a small program demonstrating the problems I'm > seeing. It has a sphere and a label both at the same position. > >> 1) Rasters ignoring front and back clipping planes. > > > > Zoom way in, zoom way out. The sphere disappears, the label > never does. > > >> 2) Rasters ignoring setDepthBufferEnable and always doing depth >> buffer compare. > > > > This demo isn't showing this. Justin suggested that maybe it's a > rendering order issue. When alwaysOnTop is true (depth buffering > is disabled) the raster is always either entirely in front of > the sphere or entirely behind it. Justin suggested I use > OrderedGroup to make sure my rasters are rendered last. > > OrderedGroup may be the only way to do what I need to do. > Since I can't control the depth of my rasters, I can use > OrderedGroup to render my objects in a specific order so > that objects in front of the scene obscure labels behind > them. Any comments on this? Is the use of OrderedGroup > going to slow me down? I guess I'll find out soon enough. . . > >> 3) A raster and another Shape transformed by the same transforms >> end up at different depths. > > > Use the menu to turn off alwaysOnTop. Zoom in and notice how the > sphere comes right through the label. The label and the sphere > are at the same position, so the label should always be in the > center of the sphere. Depending on the position of the sphere, > the label moves relative to it in Z. > >> 4) Documentation unclear about the meaning of a Raster's position. >> (Perhaps more bugs here too, depending on the meaning.) > > > I'm not setting the raster's position in this example program, for > simplicity. > >> 5) CLIP_IMAGE causes flickering > > > Move the sphere over to the left so the left side of the raster is > clipped. Now spin the sphere and watch the label flicker. > >> 6) Sign problem with setDstOffset > > > This may not be a bug, but you may want to document it because it's > not clear to me why positive X and Y offsets move the raster up and > to the left. > > -Paul > > > ------------------------------------------------------------------------ > > /***************************************************************************** > * J3D.org Copyright (c) 2000 > * Java Source > * > * This source is licensed under the GNU LGPL v2.1 > * Please read http://www.gnu.org/copyleft/lgpl.html for more information > * > ****************************************************************************/ > > package org.j3d.geom; > > // Standard imports > import javax.media.j3d.*; > > import java.awt.AlphaComposite; > import java.awt.Color; > import java.awt.Font; > import java.awt.FontMetrics; > import java.awt.Graphics; > import java.awt.Graphics2D; > import java.awt.geom.Rectangle2D; > import java.awt.image.BufferedImage; > > import javax.vecmath.Point3f; > > // Application specific imports > > /** > * A text label for labelling objects on screen that uses a Java 3D Raster > * to produce the overlay effect. > * <p> > * > * If the label text is null, then no label will be displayed. All of the > * setup will be done, but no raster will be created. > * <p> > * > * The text label can come in a number of flavours depending on how you > * configure it through the constructors. You may build a label that is > * only static, always fixed size regardless of text length, and/or may > * be hidden from other objects v always on the top. Once configured to one > * of these versions, it cannot be changed. > * <p> > * > * If running dynamic text, the internal images will only resize to a > * larger size. That is, if a new string comes in that is smaller than > * the original string, the image will stay the larger length than the > * original. The idea is to reduce the amount of garbage generated. However, > * in some instances this may not produce acceptable visual behaviour, > * so the crop() method is introduced that will force the image size to > * be reduced to the smallest possible size for the next time a string > * is set. There are also variants on the setText() methods to do this > * as well with a flag. Cropping is independent of the fixedSize flag but is > * still subject to the dynamic flag on the constructor. > * > * @author Justin Couch > * @version $Revision: 2.0 $ > */ > public class RasterTextLabel extends Shape3D > { > /** Message when the text label is not setup for dynamic changes */ > private static final String CANT_CHANGE_MSG = > "Attempting to make a change to a label that was not originally " + > "configured to be dynamic"; > > /** The clear colour used to clear the background of the image */ > private static final Color CLEAR_COLOR = new Color(0, 0, 0, 0); > > /** The inset between the text and the border if one is required. */ > private static final int BORDER_INSETS = 2; > > /** The current color of the text */ > private Color textColor; > > /** The current color of the border. Null if not in use */ > private Color borderColor; > > /** The background color of the image */ > private Color backgroundColor; > > /** The font of the label. Null if using system default */ > private Font labelFont; > > /** The raster object that we put the information in */ > private Raster raster; > > /** The image component that holds the image used by the raster */ > private ImageComponent2D component; > > /** > * Flag to say if the implementation should resize the underlying label > * for each text update or not. > */ > private boolean adjustImageSize; > > /** Flag indicating if this is a dynamic label */ > private boolean isDynamic; > > /** Underlying image used. Only set if this is a dynamic label */ > private BufferedImage textImage; > > /** The current image width */ > private int imageWidth; > > /** The current image height */ > private int imageHeight; > > /** > * Create a new blank label with no text. It is located at the origin. It > * is assumed to be dynamic and always on top. > */ > public RasterTextLabel() > { > this(null, null, true, true, 0, 0, 0, null, null); > } > > /** > * Create a new blank label with the given text located at the origin. > * If the text color is not specified, white is used and the code assumes > * static text, it will always be on top. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > */ > public RasterTextLabel(String label, Color col) > { > this(label, col, false, true, 0, 0, 0, null, null); > } > > /** > * Create a new blank label with the given text located at the origin. > * If the text color is not specified, white is used and the code assumes > * static text, it will always be on top. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > * @param alwaysOnTop true if this should never be obscured by content > */ > public RasterTextLabel(String label, Color col, boolean alwaysOnTop) > { > this(label, col, alwaysOnTop, false, 0, 0, 0, null, null); > } > > /** > * Create a new blank label with the given text located at the origin. > * If the text color is not specified, white is used. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > * @param dynamic True if this will change text over time > * @param alwaysOnTop true if this should never be obscured by content > */ > public RasterTextLabel(String label, > Color col, > boolean alwaysOnTop, > boolean dynamic) > { > this(label, col, alwaysOnTop, dynamic, 0, 0, 0, null, null); > } > > /** > * Create a new blank label with the given text located at a specific > * point in 3D world coordinates. The code assumes a static label. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > * @param alwaysOnTop true if this should never be obscured by content > * @param x The x world coordinate to place the label > * @param y The y world coordinate to place the label > * @param z The z world coordinate to place the label > */ > public RasterTextLabel(String label, > Color col, > boolean alwaysOnTop, > float x, > float y, > float z) > { > this(label, col, alwaysOnTop, false, x, y, z, null, null); > } > > /** > * Create a new blank label with the given text located at a specific > * point in 3D world coordinates. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > * @param x The x world coordinate to place the label > * @param y The y world coordinate to place the label > * @param z The z world coordinate to place the label > * @param alwaysOnTop true if this should never be obscured by content > * @param dynamic True if this will change text over time > */ > public RasterTextLabel(String label, > Color col, > boolean alwaysOnTop, > boolean dynamic, > float x, > float y, > float z) > { > this(label, col, alwaysOnTop, dynamic, x, y, z, null, null); > } > > /** > * Create a new blank label with the given text located at a specific > * point in 3D world coordinates and an option to show a border and > * selected font. If the border color is specified, it will show a 1 > * pixel wide border in that color. If no font is defined, the system > * default font will be used. > * > * @param label The string to use on the label > * @param col The text color to be drawn in > * @param x The x world coordinate to place the label > * @param y The y world coordinate to place the label > * @param z The z world coordinate to place the label > * @param border The color to use for the border or null for none > * @param font The font to draw the string in or null for default > * @param dynamic True if this will change text over time > */ > public RasterTextLabel(String label, > Color col, > boolean alwaysOnTop, > boolean dynamic, > float x, > float y, > float z, > Color border, > Font font) > { > adjustImageSize = false; > > textColor = (col != null) ? col : Color.white; > borderColor = border; > labelFont = font; > isDynamic = dynamic; > > Appearance app = new Appearance(); > RenderingAttributes ra = new RenderingAttributes(); > ra.setAlphaTestFunction(RenderingAttributes.GREATER); > > if(alwaysOnTop) > { > ra.setDepthBufferEnable(false); > ra.setDepthBufferWriteEnable(false); > } > > app.setRenderingAttributes(ra); > setAppearance(app); > > // create a disposable 1x1 image so that we can fetch the font > // metrics associated with the font and text label. This will allow > // us to determine the real image size. This is kludgy, but I can't > // think of a better way of doing it! > BufferedImage tmp_img = > new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); > > Graphics graphics = tmp_img.getGraphics(); > FontMetrics fm; > > if(labelFont == null) > fm = graphics.getFontMetrics(); > else > fm = graphics.getFontMetrics(labelFont); > > int width = 0; > int height = 0; > > if(label == null) > { > // No label? Create an empty (default) raster object then. This > // should result in nothing being rendered on screen, but leaves > // us a placeholder for later. > raster = new Raster(); > raster.setPosition(new Point3f(x, y, z)); > } > else > { > // now we have the metrics, let's work out how big the label is! > Rectangle2D dimensions = fm.getStringBounds(label, graphics); > > graphics.dispose(); > tmp_img.flush(); > tmp_img = null; > > width = (int)dimensions.getWidth(); > height = (int)dimensions.getHeight(); > int ascent = fm.getMaxAscent(); > > if(border != null) > { > width += BORDER_INSETS * 2 + 2; // one pixel border * 2 > height += BORDER_INSETS * 2 + 2; > } > > textImage = new BufferedImage(width, > height, > BufferedImage.TYPE_INT_ARGB); > > graphics = textImage.getGraphics(); > > renderImage(graphics, label, width, height, ascent); > > graphics.dispose(); > > component = new ImageComponent2D(ImageComponent2D.FORMAT_RGBA, > textImage); > > raster = new Raster(new Point3f(x, y, z), > Raster.RASTER_COLOR, > 0, > 0, > width, > height, > component, > null); > > // clear the reference if not dynamic > if(!dynamic) > { > component = null; > textImage = null; > } > } > > if(dynamic) > { > component.setCapability(ImageComponent2D.ALLOW_IMAGE_WRITE); > raster.setCapability(Raster.ALLOW_SIZE_WRITE); > raster.setCapability(Raster.ALLOW_IMAGE_WRITE); > raster.clearCapabilityIsFrequent(Raster.ALLOW_IMAGE_WRITE); > } > > setGeometry(raster); > } > > /** > * Set the label string that is to be rendered. This maintains the > * current text color. If this was not set up to be a dynamic image, an > * exception is thrown. > * > * @param text The string to be rendered > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void setText(String text) throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > updateText(text); > } > > /** > * Set the label string that is to be rendered with the option of croping > * it to the length of the string. This maintains the current text color. > * If this was not set up to be a dynamic image, an exception is thrown. > * > * @param text The string to be rendered > * @param crop true to crop the underlying raster > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void setText(String text, boolean crop) throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > if(crop) > textImage = null; > > updateText(text); > } > > /** > * Set the label string that is to be rendered and changes the color > * to the new value. If this was not set up to be a dynamic image, an > * exception is thrown. > * > * @param text The string to be rendered > * @param col The new color to be used or null for the default (white) > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void setText(String text, Color col) throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > textColor = (col != null) ? col : Color.white; > > updateText(text); > } > > /** > * Set the label string that is to be rendered and changes the color > * to the new value. If this was not set up to be a dynamic image, an > * exception is thrown. > * > * @param text The string to be rendered > * @param col The new color to be used or null for the default (white) > * @param crop true to crop the underlying raster > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void setText(String text, Color col, boolean crop) > throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > if(crop) > textImage = null; > > textColor = (col != null) ? col : Color.white; > > updateText(text); > } > > > /** > * Set the condition of whether the implementation should resize the > * canvas after each new label is set or just stick to a fixed size > * canvas. A fixed size label is useful when you are making fast updates > * such as a counter. When this is called, the label will not be resized > * from it's current dimensions. This may be changed dynamically and will > * only take effect next time a text string is set and the size is based > * on the biggest image used to date, not on the next string that is > * set. > * > * @param fixed true if the label size should remain fixed > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void fixSize(boolean fixed) > throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > adjustImageSize = fixed; > } > > /** > * Crop the image used for the raster to the length of the string the next > * time a string is set. This will not crop the current string, only the > * next one. > * > * @throws IllegalStateException The label was not set up to be dynamic > * in the constructor > */ > public void crop() > throws IllegalStateException > { > if(!isDynamic) > throw new IllegalStateException(CANT_CHANGE_MSG); > > // easiest way to force a rebuild is to remove the textImage reference > // completely and treat it like a new image with no text set. > textImage = null; > } > > /** > * Update the raster to display the new text. > * > * @param label The new text string to draw > * @param fontChanged true if the font changed > */ > private void updateText(String label) > { > // If we have no text to display, just set the size to display > // nothing and leave immediately. > if(label == null) > { > raster.setSize(0, 0); > return; > } > > int width = 0; > int height = 0; > FontMetrics metrics = null; > Graphics graphics = null; > > // Work on the null image first because adjustSize may also be set > // but would crash with a null source image. > if(textImage == null) > { > BufferedImage tmp_img = > new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); > > graphics = tmp_img.getGraphics(); > > if(labelFont == null) > metrics = graphics.getFontMetrics(); > else > metrics = graphics.getFontMetrics(labelFont); > > Rectangle2D dimensions = metrics.getStringBounds(label, graphics); > > graphics.dispose(); > tmp_img.flush(); > > width = (int)dimensions.getWidth(); > height = (int)dimensions.getHeight(); > > if(borderColor != null) > { > width += BORDER_INSETS * 2 + 2; // one pixel border * 2 > height += BORDER_INSETS * 2 + 2; > } > > textImage = new BufferedImage(width, > height, > BufferedImage.TYPE_INT_ARGB); > > graphics = textImage.createGraphics(); > renderImage(graphics, label, width, height, metrics.getAscent()); > > component = new ImageComponent2D(ImageComponent2D.FORMAT_RGBA, > textImage); > component.setCapability(ImageComponent2D.ALLOW_IMAGE_WRITE); > > raster.setSize(width, height); > raster.setImage(component); > } > else if(adjustImageSize) > { > // recalc size and compare against current. > graphics = textImage.getGraphics(); > > if(labelFont == null) > metrics = graphics.getFontMetrics(); > else > metrics = graphics.getFontMetrics(labelFont); > > Rectangle2D dimensions = metrics.getStringBounds(label, graphics); > > width = (int)dimensions.getWidth(); > height = (int)dimensions.getHeight(); > > if(borderColor != null) > { > width += BORDER_INSETS * 2 + 2; // one pixel border * 2 > height += BORDER_INSETS * 2 + 2; > } > > // So now we know the required size. Is it bigger than the current > // image size? Resize if new size if bigger than the old. > if((width > textImage.getWidth(null)) || > (height > textImage.getHeight(null))) > { > textImage.flush(); > textImage = new BufferedImage(width, > height, > BufferedImage.TYPE_INT_ARGB); > > graphics = textImage.createGraphics(); > > // Probably superfluous, but in for correctness. > if(labelFont == null) > metrics = graphics.getFontMetrics(); > else > metrics = graphics.getFontMetrics(labelFont); > > renderImage(graphics, label, width, height, metrics.getAscent()); > > component = new ImageComponent2D(ImageComponent2D.FORMAT_RGBA, > textImage); > component.setCapability(ImageComponent2D.ALLOW_IMAGE_WRITE); > > raster.setSize(width, height); > raster.setImage(component); > } > else > { > renderImage(graphics, label, width, height, metrics.getAscent()); > > component.set(textImage); > raster.setSize(width, height); > } > } > else > { > // fixed size > graphics = textImage.createGraphics(); > > if(labelFont == null) > metrics = graphics.getFontMetrics(); > else > metrics = graphics.getFontMetrics(labelFont); > > Rectangle2D dimensions = metrics.getStringBounds(label, graphics); > > width = (int)dimensions.getWidth(); > height = (int)dimensions.getHeight(); > > if(borderColor != null) > { > width += BORDER_INSETS * 2 + 2; // one pixel border * 2 > height += BORDER_INSETS * 2 + 2; > } > > renderImage(graphics, label, width, height, metrics.getAscent()); > > component.set(textImage); > raster.setSize(width, height); > } > > graphics.dispose(); > } > > /** > * Convenience method to render the image given the font information. When > * this method exits, it will have changed the global imageWidth and > * imageHeight variables to the given width and height values. > * > * @param graphics The graphics context for textImage > * @param label The string to render > * @param width The width of the image drawn to > * @param height The height of the image drawn to > * @param ascent The ascent of the font in use > */ > private void renderImage(Graphics graphics, > String label, > int width, > int height, > int ascent) > { > Graphics2D g = (Graphics2D)graphics; > g.setComposite(AlphaComposite.Src); > > g.setColor(CLEAR_COLOR); > g.fillRect(0, 0, imageWidth, imageHeight); > > if(borderColor != null) > { > g.setColor(borderColor); > g.drawRect(0, 0, width - 1, height - 1); > > g.setColor(textColor); > g.setFont(labelFont); > g.drawString(label, > BORDER_INSETS + 1, > ascent + BORDER_INSETS + 1); > } > else > { > g.setColor(textColor); > g.setFont(labelFont); > g.drawString(label, 0, ascent); > } > > imageWidth = width; > imageHeight = height; > } > } > > > ------------------------------------------------------------------------ > > 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 RasterBugs 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 Canvas3D c3d; > > private boolean alwaysOnTop = true; > > private RenderingAttributes ra; > > 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 inFrontItem = new JMenuItem("not alwaysOnTop"); > viewMenu.add(inFrontItem); > inFrontItem.addActionListener( > new ActionListener() { > public void actionPerformed(ActionEvent e) { > JMenuItem inFrontItem = (JMenuItem)e.getSource(); > alwaysOnTop = !alwaysOnTop; > if (alwaysOnTop) { > inFrontItem.setText("not alwaysOnTop"); > ra.setDepthBufferEnable(false); > ra.setDepthBufferWriteEnable(false); > } else { > inFrontItem.setText("alwaysOnTop"); > ra.setDepthBufferEnable(true); > ra.setDepthBufferWriteEnable(true); > } > } > } > ); > > > // 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(0.2); > scaleTg.setTransform(scale); > posTg.addChild(scaleTg); > > // Set appearance of node > 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(); > > RasterTextLabel rtl = new RasterTextLabel( > "RasterTextLabel", Color.WHITE, alwaysOnTop, false, 0f, 0f, 0f); > > Raster labelText = (Raster)rtl.getGeometry(); > labelText.setClipMode(Raster.CLIP_IMAGE); > > Appearance ap = rtl.getAppearance(); > ra = ap.getRenderingAttributes(); > ra.setCapability(RenderingAttributes.ALLOW_DEPTH_ENABLE_WRITE); > > Dimension dim = new Dimension(); > labelText.getSize(dim); > labelText.setDstOffset(dim.width / 2, dim.height / 2); > posTg.addChild(rtl); > > root.compile(); > > objRoot.addChild(root); > } // End of addNode > > > public static void main(String[] args) { > new JMainFrame(new RasterBugs(args), 500, 500); > } > > public RasterBugs(String[] args) > { > } > > public RasterBugs() > { > } > } // End of file RenderEngine.java > =========================================================================== 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".
