0 Replies Latest reply: Aug 23, 2011 10:00 AM by 884081 RSS

    facing problem while creating a Road/Pathway using Java3D

    884081
      Hello guys,

      I am newbie in Java3D and I am facing some problems while designing a 3d shape. Actually I have to design a 3d shape of a 'Carpet' placed on the ground in such a way, it looks like a Road or Pathway from "First-Person-View". That is, like a Trapezoid. The Carpet itself is made up of several segments or pieces, each of different color, width and height. Finally, exporting the final Carpet-shape as Buffered Image. Though I am able to do the later part very easily, that is, creating an image using BufferdImage from JFrame, On & Off Screen Canvas but the designing part is where I am facing some difficulties.

      I am creating a Group (carpetShapeGroup) of Polygons (with QuadArray: 4) for each segment/piece and place them one over another. so it looks like Rectangular Boxes placed one over another. Then with the Transformation3D (rot), I rotate this carpetShapeGroup with rot.rotX(-Math.PI/4) to make it like a Trapezoid shape. However, I am able to draw the image but there are several problems which I am not able to solve anymore and I need some help. I had uploaded the code on Pastie and attached it here as well with inline comments to illustrate the details. Following are the problems I am facing;

      I can create a Carpet with 3 segments/pieces successfully but as soon as I add fourth segment, the image gets distorted and the segments overlaps each other. I don't know why is it happening and how to resolve this issue. (Uncomment line:227)

      In order to display the Carpet from the bottom of the Screen i am setting a constant factor (*Transformation_Vector_Y*) but I am not able to derive it as Constant for different screen resolutions. I mean I had to make slight changes in Transformation_Vector_Y each time the Screen width and height is modified. (line:132)

      Please let me know if something is unclear here, I will try to explain my problem again. Looking forward to see your replies.

      thanks and regards
      package me.mmw.test.java3d;
      import java.awt.BorderLayout;
      import java.awt.Color;
      import java.awt.GraphicsConfiguration;
      import java.awt.GraphicsEnvironment;
      import java.awt.image.BufferedImage;
      import java.io.File;
      import java.io.IOException;
      import javax.imageio.ImageIO;
      import javax.media.j3d.AmbientLight;
      import javax.media.j3d.Appearance;
      import javax.media.j3d.BoundingSphere;
      import javax.media.j3d.BranchGroup;
      import javax.media.j3d.Canvas3D;
      import javax.media.j3d.ColoringAttributes;
      import javax.media.j3d.DirectionalLight;
      import javax.media.j3d.Group;
      import javax.media.j3d.ImageComponent;
      import javax.media.j3d.ImageComponent2D;
      import javax.media.j3d.QuadArray;
      import javax.media.j3d.Screen3D;
      import javax.media.j3d.Shape3D;
      import javax.media.j3d.Transform3D;
      import javax.media.j3d.TransformGroup;
      import javax.swing.JFrame;
      import javax.vecmath.Color3f;
      import javax.vecmath.Point3d;
      import javax.vecmath.Vector3f;
      
      import com.sun.j3d.utils.universe.SimpleUniverse;
      import com.sun.j3d.utils.universe.ViewingPlatform;
      
      public class CarpetImageRenderer {
      
      private double screenWidth;
      private double screenHeight;
      private SimpleUniverse universe;
      
      public double getScreenWidth() {
      return screenWidth;
      }
      
      public void setScreenWidth(double screenWidth) {
      this.screenWidth = screenWidth;
      }
      
      public double getScreenHeight() {
      return screenHeight;
      }
      
      public void setScreenHeight(int screenHeight) {
      this.screenHeight = screenHeight;
      }
      
      public BufferedImage render(int width, int height, PolygonDetails[] polygonDetails) {
      setScreenWidth(width);
      setScreenHeight(height);
      
      BranchGroup scene = createSceneGraph(polygonDetails);
      Canvas3D onScreenCanvas = new Canvas3D(
      SimpleUniverse.getPreferredConfiguration());
      
      universe = new SimpleUniverse(onScreenCanvas);
      ViewingPlatform viewingPlatform = universe.getViewingPlatform();
      viewingPlatform.setNominalViewingTransform();
      scene.compile();
      universe.addBranchGraph(scene);
      
      OffScreenCanvas3D offScreenCanvas = createOffScreenCanvas();
      
      JFrame frame = new JFrame();
      frame.setLayout(new BorderLayout());
      frame.setLocation(GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
      frame.setTitle("3D Carpet Renderer");
      frame.add(onScreenCanvas);
      
      BufferedImage output = offScreenCanvas.doRender((int)getScreenWidth(), (int)getScreenHeight());
      frame.setSize(output.getWidth(), output.getHeight());
      setScreenWidth(output.getWidth());
      setScreenHeight(output.getHeight());
      
      return output;
      }
      
      private OffScreenCanvas3D createOffScreenCanvas() {
      /**
      * Setup graphics
      */
      GraphicsConfiguration configuration = SimpleUniverse
      .getPreferredConfiguration();
      
      /**
      * Create the capturing canvas
      */
      OffScreenCanvas3D canvas = new OffScreenCanvas3D(configuration);
      
      /**
      * Set the size, width and height so that off-screen renderer knows at
      * what dimensions it needs to render.
      */
      Screen3D screen3D = canvas.getScreen3D();
      screen3D.setSize((int)screenWidth, (int)screenHeight);
      
      /**
      * Physical dimension of the Screen3D is supposed to be size of the physical screen in meters.
      * The values are from the top of the Screen3D physical screen in meters.
      * The values are from the top of the Screen3D.
      * Setting the wrong physical dimension may also change the aspect ratio of the rendered image
      * and you are end up with a Blackboard
      */
      screen3D.setPhysicalScreenWidth(0.0254 / 90.0 * screenWidth);
      screen3D.setPhysicalScreenHeight(0.0254 / 90.0 * screenHeight);
      
      universe.getViewer().getView().addCanvas3D(canvas);
      
      return canvas;
      }
      
      public BranchGroup createSceneGraph(PolygonDetails[] polygonDetails) {
      
      BranchGroup objRoot = new BranchGroup();
      Group carpetShapeGroup = new Group();
      /**
      * Setting Transformation/Postion Vector to display the Carpet from the Bottom of the screen
      * Problem-2: Not able to derive a constant factor for positioning the Carpet with
      * different Width and Height of Screen
      */
      
      final float TRANSFORMATION_VECTOR_Y = -0.0014f;
      
      Vector3f vector = new Vector3f(0.0f, (float)(TRANSFORMATION_VECTOR_Y * getScreenHeight()), 0.0f);
      
      double previousElementHeight = 0.0d;
      double baseCoordinateY = 0.0d;
      
      double elementHeight = 0.0d;
      double elementWidth = 1.0d;
      
      for (PolygonDetails element : polygonDetails) {
      elementHeight = (double) getScreenHeight()/100 * element.getPercentage() /100 /2;
      previousElementHeight += elementHeight;
      
      //System.out.println("baseCoordinateY:"+baseCoordinateY+" previousElementHeight"+previousElementHeight);
      
      QuadArray polygon = new QuadArray(4, QuadArray.COORDINATES);
      // X:WIDTH, Y:HEIGHT, Z:LENGTH
      polygon.setCoordinate(0, new Point3d(-elementWidth, baseCoordinateY, 0d));
      polygon.setCoordinate(1, new Point3d(elementWidth, baseCoordinateY, 0d));
      polygon.setCoordinate(2, new Point3d(elementWidth, previousElementHeight, 0d));
      polygon.setCoordinate(3, new Point3d(-elementWidth, previousElementHeight, 0d));
      
      Shape3D polygonShape = new Shape3D(polygon, createAppearance(element.getColor()));
      polygonShape.setGeometry(polygon);
      //System.out.println(polygonShape.getBounds());
      polygonShape.setCollidable(false);
      /**
      * Adding each polygon-shape in a group and finally add this group in the BranchGroup
      * Problem-3: Is there any way I can create set of polygons as One Shape?
      */
      carpetShapeGroup.addChild(polygonShape);
      baseCoordinateY = elementHeight;
      }
      TransformGroup tg = new TransformGroup();
      Transform3D transform = new Transform3D();
      Transform3D rot = new Transform3D();
      /**
      * transforming the final shape as Trapezoid
      */
      rot.rotX(-Math.PI / 7);
      transform.mul(rot);
      //transform.setScale(0.7);
      
      transform.setTranslation(vector);
      tg.setTransform(transform);
      tg.addChild(carpetShapeGroup);
      
      objRoot.addChild(tg);
      
      createLights(objRoot);
      return objRoot;
      }
      private Appearance createAppearance(Color color){
      
      Appearance polygon2Appearance = new Appearance();
      Color3f c = new Color3f ();
      c.set(color);
      ColoringAttributes yellowCA = new ColoringAttributes (c, 1);
      polygon2Appearance.setColoringAttributes(yellowCA);
      return polygon2Appearance;
      
      }
      private void createLights(BranchGroup branchGroup) {
      
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
      100.0);
      
      Color3f ambientLightColour = new Color3f(0.9f, 0.9f, 0.9f);
      AmbientLight ambientLight = new AmbientLight(ambientLightColour);
      ambientLight.setInfluencingBounds(bounds);
      
      Color3f directionLightColour = new Color3f(1.0f, 1.0f, 1.0f);
      Vector3f directionLightDir = new Vector3f(4.0f, -7.0f, -12.0f);// (-1.0f,
      // -100.0f,
      // -1.0f);
      DirectionalLight directionLight = new DirectionalLight(
      directionLightColour, directionLightDir);
      directionLight.setInfluencingBounds(bounds);
      
      branchGroup.addChild(ambientLight);
      branchGroup.addChild(directionLight);
      }
      
      public static void main(String... args) {
      /**
      * Segments/Pieces of Carpet
      * 1st arg: size of segment as %tage value
      * 2nd arg: Color of segment
      * Problem-1: when I add Fourth segment, the Image gets weird
      */
      PolygonDetails[] polygonDetails = new PolygonDetails[] {
      new PolygonDetails(10, Color.YELLOW),
      new PolygonDetails(60, Color.GREEN),
      new PolygonDetails(5, Color.RED),
      new PolygonDetails(5, Color.YELLOW),
      //new PolygonDetails(10, Color.GREEN),
      };
      /**
      * Create a Scene, render the Carpet and finally return a buffered image.
      * Takes screen width, height and set of carpet-segments as args
      */
      BufferedImage bi = new CarpetImageRenderer().render(400, 400, polygonDetails);
      
      try {
      ImageIO.write(bi, "PNG", new File("carpet3d.png"));
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      
      @SuppressWarnings("serial")
      class OffScreenCanvas3D extends Canvas3D {
      public OffScreenCanvas3D(GraphicsConfiguration graphicsConfiguration) {
      super(graphicsConfiguration, true);
      }
      
      public BufferedImage doRender(int width, int height) {
      
      BufferedImage bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
      
      ImageComponent2D buffer = new ImageComponent2D(
      ImageComponent.FORMAT_RGB, bImage);
      buffer.setCapability(ImageComponent.ALLOW_FORMAT_READ);
      
      setOffScreenBuffer(buffer);
      renderOffScreenBuffer();
      waitForOffScreenRendering();
      bImage = getOffScreenBuffer().getImage();
      
      // Release the buffer
      setOffScreenBuffer(null);
      
      return bImage;
      }
      }
      
      class PolygonDetails {
      
      private Color color;
      private double percentage;
      
      public PolygonDetails(double percentage, Color color) {
      super();
      this.color = color;
      this.percentage = percentage;
      }
      
      public PolygonDetails() {
      }
      
      public double getPercentage() {
      return percentage;
      }
      
      public Color getColor() {
      return color;
      }
      }