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