package org.myrobotlab.openni; // Points3DPanel.java // Andrew Davison, September 2011, ad@fivedots.coe.psu.ac.th /* This class builds a Java 3D scene consisting of a dark green and blue tiled surface with labels along the X and Z axes, a blue background, lit from two different directions. The user (viewer) can move through the scene by moving the mouse. A points cloud of the Kinect's depth map is displayed spread out along the -z axis, with different colors assigned to different depths. The points cloud is implemented as an instance of the PointsShape class, a subclass of Shape3D. All of the scene graph, apart from the PointsShape object, comes from the Checkers3D example in Chapter 15, "Killer Game Programming in Java" (http://fivedots.coe.psu.ac.th/~ad/jg/ch8/), and is explained in detail there. */ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GraphicsConfiguration; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Background; 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.GeometryArray; import javax.media.j3d.IndexedTriangleArray; import javax.media.j3d.LineArray; import javax.media.j3d.LineAttributes; import javax.media.j3d.PolygonAttributes; import javax.media.j3d.Shape3D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.swing.JPanel; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform; public class Points3DPanel extends JPanel // Holds the 3D canvas { private static final long serialVersionUID = 1L; private static final int PWIDTH = 512; // size of panel private static final int PHEIGHT = 512; private static final int BOUNDSIZE = 100; // larger than world private static final Point3d USERPOSN = new Point3d(0, 7, 17); // initial user position private SimpleUniverse su; private BranchGroup sceneBG; private BoundingSphere bounds; // for environment nodes public Points3DPanel(PointsShape ptsShape) { setLayout(new BorderLayout()); setOpaque(false); setPreferredSize(new Dimension(PWIDTH, PHEIGHT)); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas3D = new Canvas3D(config); add("Center", canvas3D); canvas3D.setFocusable(true); canvas3D.requestFocus(); // the canvas now has focus, so receives key // events su = new SimpleUniverse(canvas3D); createSceneGraph(ptsShape); initUserPosition(); // set user's viewpoint orbitControls(canvas3D); // controls for moving the viewpoint su.addBranchGraph(sceneBG); } // end of Points3DPanel() private void addBackground() // A blue sky { Background back = new Background(); back.setApplicationBounds(bounds); // back.setColor(0.17f, 0.65f, 0.92f); // sky colour back.setColor(0.0f, 0.0f, 0.0f); // sky colour sceneBG.addChild(back); } // end of addBackground() public void addKinectShape() { // create an appearance Appearance ap = new Appearance(); // render as a wireframe PolygonAttributes polyAttrbutes = new PolygonAttributes(); polyAttrbutes.setPolygonMode(PolygonAttributes.POLYGON_LINE); polyAttrbutes.setCullFace(PolygonAttributes.CULL_NONE); ap.setPolygonAttributes(polyAttrbutes); Box kinect = new Box(0.6f, 0.1f, 0.2f, ap); // scale and move start position to (-4,0,0) // change later TransformGroup posnTG = new TransformGroup(); Transform3D t3d = new Transform3D(); // t3d.setScale(0.5); t3d.setTranslation(new Vector3d(0f, 2.4f, 6.0f)); posnTG.setTransform(t3d); posnTG.addChild(kinect); Color3f red = new Color3f(1.0f, 0.0f, 0.0f); // line pattern dot-dash ColoringAttributes ca = new ColoringAttributes(red, ColoringAttributes.NICEST); Point3f[] dotDashPts = new Point3f[2]; dotDashPts[0] = new Point3f(0.0f, 0.0f, 0.0f); dotDashPts[1] = new Point3f(4.9f, 4.7f, -5.0f); LineArray dotDash = new LineArray(2, GeometryArray.COORDINATES); dotDash.setCoordinates(0, dotDashPts); LineAttributes dotDashLa = new LineAttributes(); dotDashLa.setLineWidth(4.0f); dotDashLa.setLinePattern(LineAttributes.PATTERN_DASH); Appearance dotDashApp = new Appearance(); dotDashApp.setLineAttributes(dotDashLa); dotDashApp.setColoringAttributes(ca); Shape3D dotDashShape = new Shape3D(dotDash, dotDashApp); posnTG.addChild(dotDashShape); // Shape3D pyramid = createPyramid(); // posnTG.addChild(pyramid); sceneBG.addChild(posnTG); } /** * This is the only method different from the Checkers3D example in Chapter 15 * of "Killer Game Programming in Java" * (http://fivedots.coe.psu.ac.th/~ad/jg/ch8/). * * All the hard work is done inside the PointsShape object. The transform * group is used to position (and perhaps scale) the points cloud. */ private void addPointsShape(PointsShape ptsShape) { // scale and move start position to (-4,0,0) // change later TransformGroup posnTG = new TransformGroup(); Transform3D t3d = new Transform3D(); // t3d.setScale(0.5); // t3d.setTranslation(new Vector3d(-3.2f, 2.4f, 0.0f));// 6.40 / 2 t3d.setTranslation(new Vector3d(0f, 0f, 0.0f));// 6.40 / 2 posnTG.setTransform(t3d); posnTG.addChild(ptsShape); sceneBG.addChild(posnTG); } Shape3D createPyramid() { IndexedTriangleArray pyGeom = new IndexedTriangleArray(5, GeometryArray.COORDINATES | GeometryArray.COLOR_3, 12); pyGeom.setCoordinate(0, new Point3f(0.0f, 0.7f, 0.0f)); pyGeom.setCoordinate(1, new Point3f(-0.4f, 0.0f, -0.4f)); pyGeom.setCoordinate(2, new Point3f(-0.4f, 0.0f, 0.4f)); pyGeom.setCoordinate(3, new Point3f(0.4f, 0.0f, 0.4f)); pyGeom.setCoordinate(4, new Point3f(0.4f, 0.0f, -0.4f)); pyGeom.setCoordinateIndex(0, 0); pyGeom.setCoordinateIndex(1, 1); pyGeom.setCoordinateIndex(2, 2); pyGeom.setCoordinateIndex(3, 0); pyGeom.setCoordinateIndex(4, 2); pyGeom.setCoordinateIndex(5, 3); pyGeom.setCoordinateIndex(6, 0); pyGeom.setCoordinateIndex(7, 3); pyGeom.setCoordinateIndex(8, 4); pyGeom.setCoordinateIndex(9, 0); pyGeom.setCoordinateIndex(10, 4); pyGeom.setCoordinateIndex(11, 1); Color3f c = new Color3f(0.6f, 0.5f, 0.55f); pyGeom.setColor(0, c); pyGeom.setColor(1, c); pyGeom.setColor(2, c); pyGeom.setColor(3, c); pyGeom.setColor(4, c); Shape3D pyramid = new Shape3D(pyGeom); return pyramid; } /** * initialize the scene * * @param ptsShape */ private void createSceneGraph(PointsShape ptsShape) { sceneBG = new BranchGroup(); // global? bounds = new BoundingSphere(new Point3d(0, 0, 0), BOUNDSIZE); lightScene(); // add the lights addBackground(); // add the sky // sceneBG.addChild(new CheckerFloor().getBG()); // add the floor addPointsShape(ptsShape); addKinectShape(); sceneBG.compile(); // fix the scene } private void initUserPosition() // Set the user's initial viewpoint using lookAt() { ViewingPlatform vp = su.getViewingPlatform(); TransformGroup steerTG = vp.getViewPlatformTransform(); Transform3D t3d = new Transform3D(); steerTG.getTransform(t3d); // args are: viewer posn, where looking, up direction t3d.lookAt(USERPOSN, new Point3d(0, 0, 0), new Vector3d(0, 1, 0)); t3d.invert(); steerTG.setTransform(t3d); } // end of initUserPosition() private void lightScene() /* One ambient light, 2 directional lights */ { Color3f white = new Color3f(1.0f, 1.0f, 1.0f); // Set up the ambient light AmbientLight ambientLightNode = new AmbientLight(white); ambientLightNode.setInfluencingBounds(bounds); sceneBG.addChild(ambientLightNode); // Set up the directional lights Vector3f light1Direction = new Vector3f(-1.0f, -1.0f, -1.0f); // left, down, backwards Vector3f light2Direction = new Vector3f(1.0f, -1.0f, 1.0f); // right, down, forwards DirectionalLight light1 = new DirectionalLight(white, light1Direction); light1.setInfluencingBounds(bounds); sceneBG.addChild(light1); DirectionalLight light2 = new DirectionalLight(white, light2Direction); light2.setInfluencingBounds(bounds); sceneBG.addChild(light2); } // end of lightScene() /** * OrbitBehaviour allows the user to rotate around the scene, and to zoom in * and out. */ private void orbitControls(Canvas3D c) { OrbitBehavior orbit = new OrbitBehavior(c, OrbitBehavior.REVERSE_ALL); orbit.setSchedulingBounds(bounds); ViewingPlatform vp = su.getViewingPlatform(); vp.setViewPlatformBehavior(orbit); } // end of orbitControls() } // end of Points3DPanel class