/* * Simbad - Robot Simulator * Copyright (C) 2004 Louis Hugues * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ----------------------------------------------------------------------------- * $Author: sioulseuguh $ * $Date: 2005/08/07 12:25:03 $ * $Revision: 1.16 $ * $Source: /cvsroot/simbad/src/simbad/sim/World.java,v $ */ package org.myrobotlab.mapper.sim; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.util.Map; 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.GeometryArray; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.Light; import javax.media.j3d.LineArray; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PointLight; import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.View; import javax.media.j3d.ViewPlatform; import javax.media.j3d.VirtualUniverse; 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.geometry.Primitive; import com.sun.j3d.utils.geometry.Sphere; /** * Represents a 3d world - this class use intensively JAVA3D. It creates the * scenegraph and the view platform. The building process uses a * EnvironmentDescription object containing colors , objects and attributes * given by the user. This class is thighly coupled with Simulator Class. * * Remember to call System.setProperty("j3d.implicitAntialiasing", "true") at * the very beginning of your program in order to enable antialiasing. * */ public class World { /** J3D universe */ VirtualUniverse universe; /** The content branch. */ private BranchGroup sceneBranch; /** The base translation of the sceneBranch. */ private TransformGroup sceneTrans; /** The base rotation of the sceneBranch. */ private TransformGroup sceneRot; /** * All the pickable/collidable objects should be attached under this * sub-branch */ private BranchGroup pickableSceneBranch; /** The view branch */ private BranchGroup viewBranch; private TransformGroup viewTransformGroup; private ViewPlatform viewPlatform; private View view; /** The main canvas for viewing the world. */ private Canvas3D canvas3d; /** For managing the mouse mouvement in the Canvas3D */ MouseOrbiter mouseOrbiter; // lights private Light light1; private Light light2; // constants used to specify the viewpoint public static final int VIEW_FROM_TOP = 1; public static final int VIEW_FROM_EAST = 2; public static final int VIEW_BEHIND_AGENT = 3; public static final int VIEW_ABOVE_AGENT = 4; public static final int VIEW_ABOVE_AGENT_NEAR = 5; public static final int VIEW_AGENT_SIDE = 6; /** The size of the square containing the world */ protected float worldSize; /** Prepared colors. */ Color3f white = new Color3f(1, 1, 1); Color3f black = new Color3f(0, 0, 0); /** Construct a World from a given EnvironmentDescription. */ public World(EnvironmentDescription ed) { create(ed); } /** * Add a light to the 3d world. Used only in the creation phase. */ Light addLight(Vector3d pos, Color3f color) { BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), worldSize * 2); TransformGroup tg = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.set(pos); tg.setTransform(t3d); PointLight light = new PointLight(); light.setAttenuation(0.5f, 0, 0); // light.setAttenuation(0f,.08f,0); // light.setAttenuation(1.2f,0,0); // note : light pos not affected by transform (but bound is). light.setPosition((float) pos.x, (float) pos.y, (float) pos.z); light.setInfluencingBounds(bounds); sceneTrans.addChild(light); // light geometry ColoringAttributes ca = new ColoringAttributes(); ca.setColor(color); Appearance appL1 = new Appearance(); appL1.setColoringAttributes(ca); Primitive s = new Sphere(0.4f, appL1); s.setCollidable(true); tg.addChild(s); sceneTrans.addChild(tg); return light; } /** * Adds a 3D object to the world. Used only in the creation phase. */ public void addObjectToPickableSceneBranch(BaseObject obj3d) { obj3d.compile(); pickableSceneBranch.addChild(obj3d.getNode()); } /** attach a 3d object to the scenegraph. */ public void attach(BaseObject obj3d) { pickableSceneBranch.addChild(obj3d.getNode()); } /** * Change the user view Point . Note that we modify the ViewBranch transform * not the scene transform. * * @param type * can be VIEW_FROM_TOP,VIEW_FROM_EAST,VIEW_BEHIND_AGENT * @param agent * : specify the agent if VIEW_BEHIND_AGENT * * The VIEW_BEHIND_AGENT case has to be called regularly because of * the agent displacement. */ public void changeViewPoint(int type, SimpleAgent agent) { Point3d p1 = new Point3d(); Point3d p2 = new Point3d(); Transform3D t1 = new Transform3D(); Transform3D t2 = new Transform3D(); t1.setIdentity(); t2.setIdentity(); mouseOrbiter.resetView(); switch (type) { case VIEW_FROM_TOP: t1.lookAt(new Point3d(0, worldSize * 1.2, 0), new Point3d(0, 0, 0), new Vector3d(0, 0, -1)); t1.invert(); viewTransformGroup.setTransform(t1); break; case VIEW_FROM_EAST: t1.lookAt(new Point3d(worldSize, worldSize, 0), new Point3d(0, 0, 0), new Vector3d(-1, 0, 0)); t1.invert(); viewTransformGroup.setTransform(t1); break; case VIEW_BEHIND_AGENT: t1.setTranslation(new Vector3d(-agent.getRadius() * 2, 0, 0)); agent.getGroup().getLocalToVworld(t2); t1.mul(t2); viewTransformGroup.setTransform(t1); break; case VIEW_ABOVE_AGENT: agent.getRotationTransformGroup().getLocalToVworld(t1); t1.transform(p1); t1.transform(p2); p2.y = worldSize * .8; t1.lookAt(p2, p1, new Vector3d(0, 0, -1)); t1.invert(); viewTransformGroup.setTransform(t1); break; case VIEW_ABOVE_AGENT_NEAR: agent.getRotationTransformGroup().getLocalToVworld(t1); t1.transform(p1); t1.transform(p2); p2.y = agent.getHeight() * worldSize * 0.5; // avoid front clipping if (p2.y < 0.2) p2.y = 0.2; t1.lookAt(p2, p1, new Vector3d(0, 0, -1)); t1.invert(); viewTransformGroup.setTransform(t1); break; case VIEW_AGENT_SIDE: agent.getRotationTransformGroup().getLocalToVworld(t1); t1.transform(p1); t1.transform(p2); agent.rotation.transform(p2); t2.setTranslation(new Vector3d(0, agent.getHeight() * 2, agent.getRadius() * 10)); t2.transform(p2); t1.lookAt(p2, p1, new Vector3d(0, 1, 0)); t1.invert(); viewTransformGroup.setTransform(t1); break; } } boolean checkCollisionAgainstBlockWorldObjects(BoundingSphere bs) { return false; } /** * Creates the world from the given environement Description. Used only in the * creation phase. * * @param ed * the environment description. */ private void create(EnvironmentDescription ed) { worldSize = ed.worldSize; createUniverse(ed); } /** * Creates a representation of the 3 axis of the 3d world. Used only in the * creation phase. */ private void createAxis() { Point3f[] axisCoords = { // X axis arrow new Point3f(0.0f, 0.001f, 0.0f), new Point3f(1, 0.001f, 0.0f), new Point3f(1, 0.001f, 0.0f), new Point3f(0.95f, 0.001f, 0.05f), new Point3f(1, 0.001f, 0.0f), new Point3f(0.95f, 0.001f, -0.05f), // a small X new Point3f(1.0f, 0.001f, 0.1f), new Point3f(0.9f, 0.001f, 0.2f), new Point3f(1.0f, 0.001f, 0.2f), new Point3f(0.9f, 0.001f, 0.1f), // Z axis arrow new Point3f(0.0f, 0.001f, 0.0f), new Point3f(0, 0.001f, 1.0f), new Point3f(0, 0.001f, 1.0f), new Point3f(0.05f, 0.001f, 0.95f), new Point3f(0, 0.001f, 1.0f), new Point3f(-0.05f, 0.001f, 0.95f), // a small Z new Point3f(0.1f, 0.001f, 1.0f), new Point3f(0.2f, 0.001f, 1.0f), new Point3f(0.1f, 0.001f, 0.9f), new Point3f(0.2f, 0.001f, 0.9f), new Point3f(0.1f, 0.001f, 1.0f), new Point3f(0.2f, 0.001f, 0.9f), // Y axis arrow new Point3f(0.0f, 0.001f, 0.0f), new Point3f(0, 1.0f, 0.0f), new Point3f(0, 1.0f, 0.0f), new Point3f(0.05f, 0.95f, 0f), new Point3f(0, 1f, 0f), new Point3f(0.00f, 0.95f, 0.05f), // a small Y new Point3f(0.2f, 1f, 0.0f), new Point3f(0.1f, 0.9f, 0f), new Point3f(0.1f, 1.0f, 0.0f), new Point3f(0.15f, 0.95f, 0.0f) }; // scale axis drawing to 5% of word size for (int i = 0; i < axisCoords.length; i++) { axisCoords[i].scale(worldSize * 0.05f); } LineArray axisLines = new LineArray(axisCoords.length, GeometryArray.COORDINATES); axisLines.setCoordinates(0, axisCoords); Appearance axisAppear = new Appearance(); ColoringAttributes ca = new ColoringAttributes(); ca.setColor(white); axisAppear.setColoringAttributes(ca); Material mat = new Material(); mat.setDiffuseColor(white); axisAppear.setMaterial(mat); Shape3D axis = new Shape3D(axisLines, axisAppear); axis.setCollidable(false); axis.setPickable(false); sceneTrans.addChild(axis); } /** * Creates the Canvas3D to visualize the 3D World. Used only in the creation * phase. */ private void createCanvas3D() { GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); template.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED); GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getBestConfiguration(template); // create canvas canvas3d = new Canvas3D(config); canvas3d.setDoubleBufferEnable(true); // display j3d info Map map = canvas3d.queryProperties(); System.out.println("doubleBufferAvailable = " + map.get("doubleBufferAvailable")); System.out.println("sceneAntialiasingNumPasses = " + map.get("sceneAntialiasingNumPasses")); System.out.println("sceneAntialiasingAvailable = " + map.get("sceneAntialiasingAvailable")); System.out.println("texture3DAvailable = " + map.get("texture3DAvailable")); } /** * Creates the floor of the 3d world. Used only in the creation phase. * * @param ed * the environment description. */ private void createFloor(EnvironmentDescription wd) { float minx = -worldSize / 2, maxx = worldSize / 2; float minz = -worldSize / 2, maxz = worldSize / 2; Point3f[] floorCoords = { new Point3f(minx, 0.0f, minz), new Point3f(minx, 0.0f, maxz), new Point3f(maxx, 0.0f, maxz), new Point3f(maxx, 0.0f, minz) }; Vector3f[] floorNormals = { new Vector3f(-0.6f, 0.6f, -0.6f), new Vector3f(-0.6f, 0.6f, 0.6f), new Vector3f(0.6f, 0.6f, 0.6f), new Vector3f(0.6f, 0.6f, -0.6f) }; Vector3f[] floorNormalsSimple = { new Vector3f(0, 1, 0), new Vector3f(0, 1, 0), new Vector3f(0, 1, 0), new Vector3f(0, 1, 0) }; QuadArray floorQuads = null; switch (wd.normalsStyle) { case EnvironmentDescription.NORMALS_REALISTIC: floorQuads = new QuadArray(floorCoords.length, GeometryArray.COORDINATES | GeometryArray.NORMALS); floorQuads.setNormals(0, floorNormals); break; case EnvironmentDescription.NORMALS_SIMPLE: floorQuads = new QuadArray(floorCoords.length, GeometryArray.COORDINATES | GeometryArray.NORMALS); floorQuads.setNormals(0, floorNormalsSimple); break; } floorQuads.setCoordinates(0, floorCoords); Appearance floorAppear = new Appearance(); Material mat = new Material(); mat.setDiffuseColor(wd.floorColor); Color3f specular = new Color3f(wd.floorColor); specular.scale(1.1f); specular.clampMax(0.8f); mat.setSpecularColor(specular); floorAppear.setMaterial(mat); Shape3D floor = new Shape3D(floorQuads, floorAppear); floor.setPickable(false); floor.setCollidable(false); sceneTrans.addChild(floor); } /** * Creates the branch for the visible content of the scenegraph. Used only in * the creation phase. */ private void createSceneBranch(EnvironmentDescription wd) { sceneBranch = new BranchGroup(); sceneRot = new TransformGroup(); sceneRot.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); sceneRot.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); sceneRot.setCapability(Group.ALLOW_CHILDREN_EXTEND); // add transform sceneTrans = new TransformGroup(); // allow transform access sceneTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); sceneTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); sceneTrans.setCapability(Group.ALLOW_CHILDREN_EXTEND); sceneBranch.addChild(sceneRot); sceneRot.addChild(sceneTrans); // bounds (lights,background, behaviors) BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), worldSize * 3); // background Color3f bgColor = wd.backgroundColor; Background bgNode = new Background(bgColor); bgNode.setApplicationBounds(bounds); sceneTrans.addChild(bgNode); // ambient light TransformGroup tga = new TransformGroup(); AmbientLight ambientLight = new AmbientLight(wd.ambientLightColor); ambientLight.setInfluencingBounds(bounds); tga.addChild(ambientLight); sceneBranch.addChild(tga); // directional lights light1 = addLight(wd.light1Position, wd.light1Color); light2 = addLight(wd.light2Position, wd.light2Color); light1.setEnable(wd.light1IsOn); light2.setEnable(wd.light2IsOn); createFloor(wd); if (wd.hasAxis) createAxis(); pickableSceneBranch = new BranchGroup(); sceneTrans.addChild(pickableSceneBranch); pickableSceneBranch.setCapability(Group.ALLOW_CHILDREN_EXTEND); pickableSceneBranch.setCapability(BranchGroup.ALLOW_DETACH); pickableSceneBranch.setCapability(Group.ALLOW_CHILDREN_WRITE); } /** * Creates the universe to attach the scenegraph. Used only in the creation * phase. * * @param ed * the environment description. */ private void createUniverse(EnvironmentDescription ed) { System.out.println("create Universe"); // show infos Map map = VirtualUniverse.getProperties(); System.out.println("----------------------------------------"); System.out.println("j3d.version = " + map.get("j3d.version")); System.out.println("j3d.vendor = " + map.get("j3d.vendor")); System.out.println("j3d.specification.version = " + map.get("j3d.specification.version")); System.out.println("j3d.specification.vendor = " + map.get("j3d.specification.vendor")); System.out.println("j3d.renderer = " + map.get("j3d.renderer")); System.out.println("J3DThreadPriority = " + VirtualUniverse.getJ3DThreadPriority()); System.out.println("----------------------------------------"); createCanvas3D(); createSceneBranch(ed); universe = new VirtualUniverse(); Locale locale = new Locale(universe); // Create and add VIEW branch // locale->viewBranch->viewTransformGroup->viewPlatform viewBranch = new BranchGroup(); viewTransformGroup = new TransformGroup(); viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Transform3D t3d = new Transform3D(); t3d.setIdentity(); viewTransformGroup.setTransform(t3d); viewBranch.addChild(viewTransformGroup); // Creates View and viewplatform viewPlatform = new ViewPlatform(); viewPlatform.setViewAttachPolicy(View.NOMINAL_HEAD); viewPlatform.setActivationRadius(100); view = new View(); view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION); view.setViewPolicy(View.SCREEN_VIEW); view.setVisibilityPolicy(View.VISIBILITY_DRAW_ALL); view.setFrontClipDistance(0.02); GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); template.setSceneAntialiasing(GraphicsConfigTemplate.REQUIRED); template.setDoubleBuffer(GraphicsConfigTemplate.PREFERRED); /* * GraphicsConfiguration config = GraphicsEnvironment * .getLocalGraphicsEnvironment().getDefaultScreenDevice() * .getBestConfiguration(template); */ // request antialiasing view.setSceneAntialiasingEnable(true); view.addCanvas3D(canvas3d); PhysicalBody phyBody = new PhysicalBody(); PhysicalEnvironment phyEnv = new PhysicalEnvironment(); view.setPhysicalBody(phyBody); view.setPhysicalEnvironment(phyEnv); view.attachViewPlatform(viewPlatform); viewTransformGroup.addChild(viewPlatform); // Add both branch to the unique locale locale.addBranchGraph(viewBranch); locale.addBranchGraph(sceneBranch); // Add mouse control in the canvas3d mouseOrbiter = new MouseOrbiter(canvas3d, viewTransformGroup); // sets initial viewpoint changeViewPoint(ed.worldViewPoint, null); } /** Detach a previously attached object from the scenegraph. */ public void detach(BaseObject obj3d) { pickableSceneBranch.removeChild(obj3d.getNode()); } /** Destroy the java3d graph */ public void dispose() { universe.removeAllLocales(); view.removeAllCanvas3Ds(); } /** * @return the canvas3D associated to the world view platform */ public Canvas3D getCanvas3D() { return canvas3d; } /** * @return the scene branchgroup containing the world's object which can be * picked */ BranchGroup getPickableSceneBranch() { return pickableSceneBranch; } /** Do one rendering on main canvas 3D . Used for background mode. */ public void renderOnce() { canvas3d.startRenderer(); try { Thread.sleep((100)); } catch (InterruptedException e) { e.printStackTrace(); } canvas3d.stopRenderer(); } /** Restart rendering on main canvas 3D . Used for background mode. */ public void startRendering() { canvas3d.startRenderer(); } /** Stop rendering on main canvas 3D . Used for background mode. */ public void stopRendering() { canvas3d.stopRenderer(); } }