Java/3D/Scene
Allows the various Java 3D Appearance components to
<source lang="java">
/**********************************************************
Copyright (C) 2001 Daniel Selman First distributed with the book "Java 3D Programming" by Daniel Selman and published by Manning Publications. http://manning.ru/selman 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, version 2. 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. The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Authors can be contacted at: Daniel Selman: daniel@selman.org If you make changes you think others would like, please contact one of the authors or someone at the www.j3d.org web site. **************************************************************/
import java.applet.Applet; import java.awt.BorderLayout; import java.awt.ruponent; import java.awt.Frame; import java.awt.GraphicsConfigTemplate; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.AudioDevice; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; 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.GraphicsConfigTemplate3D; import javax.media.j3d.Group; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.LineAttributes; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.NodeComponent; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PointAttributes; import javax.media.j3d.PolygonAttributes; import javax.media.j3d.QuadArray; import javax.media.j3d.RenderingAttributes; import javax.media.j3d.Shape3D; import javax.media.j3d.TexCoordGeneration; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TransparencyAttributes; 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.Vector3d; import javax.vecmath.Vector3f; import javax.vecmath.Vector4f; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.image.TextureLoader; /**
* Allows the various Java 3D Appearance components to be specified * interactively and applies the Appearance to an object in a scene.*
* This example can only be run as an application as it uses a MenuBar which can * only be associated with a Frame (in AWT) */ public class AppearanceTest extends Java3dApplet { private static int m_kWidth = 400; private static int m_kHeight = 400; private Frame m_Frame = null; private Appearance m_Appearance = null; private AppearanceComponent[] m_ComponentArray = null; public AppearanceTest() { m_Appearance = new Appearance(); TextureComponent.setComponent(this); m_ComponentArray = new AppearanceComponent[] { new PolygonComponent(m_Appearance), new ColoringComponent(m_Appearance), new LineComponent(m_Appearance), new MaterialComponent(m_Appearance), new PointComponent(m_Appearance), new RenderingComponent(m_Appearance), new TransparencyComponent(m_Appearance), new TextureComponent(m_Appearance), new TextureAttributesComponent(m_Appearance), new TexGenComponent(m_Appearance) }; } protected void addCanvas3D(Canvas3D c3d) { if (m_Frame != null) { MenuBar menuBar = new MenuBar(); for (int n = 0; n < m_ComponentArray.length; n++) menuBar.add(m_ComponentArray[n].createMenu()); m_Frame.setMenuBar(menuBar); } setLayout(new BorderLayout()); add(c3d, BorderLayout.CENTER); doLayout(); } protected double getScale() { return 0.1; } protected BranchGroup createSceneBranchGroup() { BranchGroup objRoot = super.createSceneBranchGroup(); TransformGroup zoomTg = new TransformGroup(); zoomTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); zoomTg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); // attach a navigation behavior to the position of the viewer KeyNavigatorBehavior key = new KeyNavigatorBehavior(zoomTg); key.setSchedulingBounds(createApplicationBounds()); key.setEnable(true); objRoot.addChild(key); // create a TransformGroup to flip the hand onto its end and enlarge it. TransformGroup objTrans1 = new TransformGroup(); Transform3D tr = new Transform3D(); objTrans1.getTransform(tr); tr.setEuler(new Vector3d(0.5 * Math.PI, 0.6, 0)); objTrans1.setTransform(tr); // Set up the global lights Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f); Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f); Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f); AmbientLight aLgt = new AmbientLight(alColor); aLgt.setInfluencingBounds(getApplicationBounds()); DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1); lgt1.setInfluencingBounds(getApplicationBounds()); objRoot.addChild(aLgt); objRoot.addChild(lgt1); int nScale = 50; Box box = new Box(nScale, nScale, nScale, Primitive.GENERATE_NORMALS | Primitive.GENERATE_TEXTURE_COORDS, m_Appearance); Shape3D frontFace = box.getShape(Box.LEFT); // create a new left face so we can // assign per-vertex colors GeometryArray geometry = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR_4 | GeometryArray.TEXTURE_COORDINATE_2); nScale = 40; final float[] verts = { // left face -1.0f * nScale, -1.0f * nScale, 1.0f * nScale, -1.0f * nScale, 1.0f * nScale, 1.0f * nScale, -1.0f * nScale, 1.0f * nScale, -1.0f * nScale, -1.0f * nScale, -1.0f * nScale, -1.0f * nScale }; final float[] colors = { // left face 1, 0, 0, 0, 0, 1, 0, 0.2f, 0, 0, 1, 0.8f, 0, 0, 0, 1, }; float[] tcoords = { // left 1, 0, 1, 1, 0, 1, 0, 0 }; Vector3f normalVector = new Vector3f(-1.0f, 0.0f, 0.0f); geometry.setColors(0, colors, 0, 4); for (int n = 0; n < 4; n++) geometry.setNormal(n, normalVector); geometry.setTextureCoordinates(0, tcoords, 0, 4); geometry.setCoordinates(0, verts); frontFace.setGeometry(geometry); // connect the scenegraph objTrans1.addChild(box); zoomTg.addChild(objTrans1); objRoot.addChild(zoomTg); return objRoot; } public static void main(String[] args) { AppearanceTest appearanceTest = new AppearanceTest(); appearanceTest.saveCommandLineArguments(args); Frame frame = (Frame) new MainFrame(appearanceTest, m_kWidth, m_kHeight); appearanceTest.m_Frame = frame; appearanceTest.initJava3d(); } } /******************************************************************************* * Copyright (C) 2001 Daniel Selman * * First distributed with the book "Java 3D Programming" by Daniel Selman and * published by Manning Publications. http://manning.ru/selman * * 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, version 2. * * 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. * * The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html * * Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite * 330, Boston, MA 02111-1307, USA. * * Authors can be contacted at: Daniel Selman: daniel@selman.org * * If you make changes you think others would like, please contact one of the * authors or someone at the www.j3d.org web site. ******************************************************************************/ //***************************************************************************** /** * Java3dApplet * * Base class for defining a Java 3D applet. Contains some useful methods for * defining views and scenegraphs etc. * * @author Daniel Selman * @version 1.0 */ //***************************************************************************** abstract class Java3dApplet extends Applet { public static int m_kWidth = 300; public static int m_kHeight = 300; protected String[] m_szCommandLineArray = null; protected VirtualUniverse m_Universe = null; protected BranchGroup m_SceneBranchGroup = null; protected Bounds m_ApplicationBounds = null; // protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null; public Java3dApplet() { } public boolean isApplet() { try { System.getProperty("user.dir"); System.out.println("Running as Application."); return false; } catch (Exception e) { } System.out.println("Running as Applet."); return true; } public URL getWorkingDirectory() throws java.net.MalformedURLException { URL url = null; try { File file = new File(System.getProperty("user.dir")); System.out.println("Running as Application:"); System.out.println(" " + file.toURL()); return file.toURL(); } catch (Exception e) { } System.out.println("Running as Applet:"); System.out.println(" " + getCodeBase()); return getCodeBase(); } public VirtualUniverse getVirtualUniverse() { return m_Universe; } //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() { //return m_Java3dTree; // } public Locale getFirstLocale() { java.util.Enumeration e = m_Universe.getAllLocales(); if (e.hasMoreElements() != false) return (Locale) e.nextElement(); return null; } protected Bounds getApplicationBounds() { if (m_ApplicationBounds == null) m_ApplicationBounds = createApplicationBounds(); return m_ApplicationBounds; } protected Bounds createApplicationBounds() { m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); return m_ApplicationBounds; } protected Background createBackground() { Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f)); back.setApplicationBounds(createApplicationBounds()); return back; } public void initJava3d() { // m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree(); m_Universe = createVirtualUniverse(); Locale locale = createLocale(m_Universe); BranchGroup sceneBranchGroup = createSceneBranchGroup(); ViewPlatform vp = createViewPlatform(); BranchGroup viewBranchGroup = createViewBranchGroup( getViewTransformGroupArray(), vp); createView(vp); Background background = createBackground(); if (background != null) sceneBranchGroup.addChild(background); // m_Java3dTree.recursiveApplyCapability(sceneBranchGroup); // m_Java3dTree.recursiveApplyCapability(viewBranchGroup); locale.addBranchGraph(sceneBranchGroup); addViewBranchGroup(locale, viewBranchGroup); onDoneInit(); } protected void onDoneInit() { // m_Java3dTree.updateNodes(m_Universe); } protected double getScale() { return 1.0; } public TransformGroup[] getViewTransformGroupArray() { TransformGroup[] tgArray = new TransformGroup[1]; tgArray[0] = new TransformGroup(); // move the camera BACK a little... // note that we have to invert the matrix as // we are moving the viewer Transform3D t3d = new Transform3D(); t3d.setScale(getScale()); t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0)); t3d.invert(); tgArray[0].setTransform(t3d); return tgArray; } protected void addViewBranchGroup(Locale locale, BranchGroup bg) { locale.addBranchGraph(bg); } protected Locale createLocale(VirtualUniverse u) { return new Locale(u); } protected BranchGroup createSceneBranchGroup() { m_SceneBranchGroup = new BranchGroup(); return m_SceneBranchGroup; } protected View createView(ViewPlatform vp) { View view = new View(); PhysicalBody pb = createPhysicalBody(); PhysicalEnvironment pe = createPhysicalEnvironment(); AudioDevice audioDevice = createAudioDevice(pe); if (audioDevice != null) { pe.setAudioDevice(audioDevice); audioDevice.initialize(); } view.setPhysicalEnvironment(pe); view.setPhysicalBody(pb); if (vp != null) view.attachViewPlatform(vp); view.setBackClipDistance(getBackClipDistance()); view.setFrontClipDistance(getFrontClipDistance()); Canvas3D c3d = createCanvas3D(); view.addCanvas3D(c3d); addCanvas3D(c3d); return view; } protected PhysicalBody createPhysicalBody() { return new PhysicalBody(); } protected AudioDevice createAudioDevice(PhysicalEnvironment pe) { JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe); if (javaSoundMixer == null) System.out.println("create of audiodevice failed"); return javaSoundMixer; } protected PhysicalEnvironment createPhysicalEnvironment() { return new PhysicalEnvironment(); } protected float getViewPlatformActivationRadius() { return 100; } protected ViewPlatform createViewPlatform() { ViewPlatform vp = new ViewPlatform(); vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW); vp.setActivationRadius(getViewPlatformActivationRadius()); return vp; } protected Canvas3D createCanvas3D() { GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D(); gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED); GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment() .getScreenDevices(); Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D)); c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d)); return c3d; } protected int getCanvas3dWidth(Canvas3D c3d) { return m_kWidth; } protected int getCanvas3dHeight(Canvas3D c3d) { return m_kHeight; } protected double getBackClipDistance() { return 100.0; } protected double getFrontClipDistance() { return 1.0; } protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray, ViewPlatform vp) { BranchGroup vpBranchGroup = new BranchGroup(); if (tgArray != null && tgArray.length > 0) { Group parentGroup = vpBranchGroup; TransformGroup curTg = null; for (int n = 0; n < tgArray.length; n++) { curTg = tgArray[n]; parentGroup.addChild(curTg); parentGroup = curTg; } tgArray[tgArray.length - 1].addChild(vp); } else vpBranchGroup.addChild(vp); return vpBranchGroup; } protected void addCanvas3D(Canvas3D c3d) { setLayout(new BorderLayout()); add(c3d, BorderLayout.CENTER); doLayout(); } protected VirtualUniverse createVirtualUniverse() { return new VirtualUniverse(); } protected void saveCommandLineArguments(String[] szArgs) { m_szCommandLineArray = szArgs; } protected String[] getCommandLineArguments() { return m_szCommandLineArray; } } class LineComponent extends AppearanceComponent { public LineComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { LineAttributes.ALLOW_ANTIALIASING_WRITE, LineAttributes.ALLOW_PATTERN_WRITE, LineAttributes.ALLOW_WIDTH_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new LineAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance.setLineAttributes((LineAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setLineAttributes(null); } protected String getName() { return "Line"; } protected String[] getMenuItemNames() { return new String[] { "-", "Antialiasing", "-", "On", "Off", "-", "Pattern", "-", "Dash", "DashDot", "Dot", "Solid", "-", "Width", "-", "1", "2", "5", "10" }; } private LineAttributes getLineAttributes() { return (LineAttributes) m_NodeComponent; } public void onOn() { getLineAttributes().setLineAntialiasingEnable(true); } public void onOff() { getLineAttributes().setLineAntialiasingEnable(false); } public void onDash() { getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH); } public void onDashDot() { getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH_DOT); } public void onDot() { getLineAttributes().setLinePattern(LineAttributes.PATTERN_DOT); } public void onSolid() { getLineAttributes().setLinePattern(LineAttributes.PATTERN_SOLID); } public void on1() { getLineAttributes().setLineWidth(1); } public void on2() { getLineAttributes().setLineWidth(2); } public void on5() { getLineAttributes().setLineWidth(5); } public void on10() { getLineAttributes().setLineWidth(10); } } class MaterialComponent extends AppearanceComponent { public MaterialComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { Material.ALLOW_COMPONENT_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new Material(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_MATERIAL_WRITE); } protected void assignToAppearance() { m_Appearance.setMaterial((Material) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setMaterial(null); } protected String getName() { return "Material"; } protected String[] getMenuItemNames() { return new String[] { "-", "Ambient", "-", "A_White", "A_Black", "A_Blue", "-", "Diffuse", "-", "D_White", "D_Black", "D_Blue", "-", "Emissive", "-", "E_White", "E_Black", "E_Blue", "-", "Specular", "-", "S_White", "S_Black", "S_Blue", "-", "Lighting", "-", "On", "Off", "-", "Shininess", "-", "1", "70", }; } private Material getMaterial() { return (Material) m_NodeComponent; } public void onA_White() { getMaterial().setAmbientColor(1, 1, 1); } public void onA_Black() { getMaterial().setAmbientColor(0, 0, 0); } public void onA_Blue() { getMaterial().setAmbientColor(0, 0, 1); } public void onE_White() { getMaterial().setEmissiveColor(1, 1, 1); } public void onE_Black() { getMaterial().setEmissiveColor(0, 0, 0); } public void onE_Blue() { getMaterial().setEmissiveColor(0, 0, 1); } public void onD_White() { getMaterial().setDiffuseColor(1, 1, 1); } public void onD_Black() { getMaterial().setDiffuseColor(0, 0, 0); } public void onD_Blue() { getMaterial().setDiffuseColor(0, 0, 1); } public void onS_White() { getMaterial().setSpecularColor(1, 1, 1); } public void onS_Black() { getMaterial().setSpecularColor(0, 0, 0); } public void onS_Blue() { getMaterial().setSpecularColor(0, 0, 1); } public void onOn() { getMaterial().setLightingEnable(true); } public void onOff() { getMaterial().setLightingEnable(false); } public void on1() { getMaterial().setShininess(1); } public void on70() { getMaterial().setShininess(70); } } class PointComponent extends AppearanceComponent { public PointComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { PointAttributes.ALLOW_ANTIALIASING_WRITE, PointAttributes.ALLOW_SIZE_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new PointAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_POINT_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance.setPointAttributes((PointAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setPointAttributes(null); } protected String getName() { return "Point"; } protected String[] getMenuItemNames() { return new String[] { "-", "Antialiasing", "-", "On", "Off", "-", "Size", "-", "1", "5", "10" }; } private PointAttributes getPointAttributes() { return (PointAttributes) m_NodeComponent; } public void onOn() { getPointAttributes().setPointAntialiasingEnable(true); } public void onOff() { getPointAttributes().setPointAntialiasingEnable(false); } public void on1() { getPointAttributes().setPointSize(1); } public void on5() { getPointAttributes().setPointSize(5); } public void on10() { getPointAttributes().setPointSize(10); } } class PolygonComponent extends AppearanceComponent { public PolygonComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { PolygonAttributes.ALLOW_CULL_FACE_WRITE, PolygonAttributes.ALLOW_MODE_WRITE, PolygonAttributes.ALLOW_NORMAL_FLIP_WRITE, PolygonAttributes.ALLOW_OFFSET_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new PolygonAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance.setPolygonAttributes((PolygonAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setPolygonAttributes(null); } protected String getName() { return "Polygon"; } protected String[] getMenuItemNames() { return new String[] { "-", "Cull", "-", "Back", "Front", "None", "-", "Mode", "-", "Fill", "Line", "Point", "-", "Normal", "-", "Flip_ON", "Flip_OFF", "-", "Offset", "-", "0", "10", "50", "200" }; } private PolygonAttributes getPolygonAttributes() { return (PolygonAttributes) m_NodeComponent; } public void onBack() { getPolygonAttributes().setCullFace(PolygonAttributes.CULL_BACK); } public void onFront() { getPolygonAttributes().setCullFace(PolygonAttributes.CULL_FRONT); } public void onNone() { getPolygonAttributes().setCullFace(PolygonAttributes.CULL_NONE); } public void onFill() { getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_FILL); } public void onLine() { getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_LINE); } public void onPoint() { getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_POINT); } public void onFlip_ON() { getPolygonAttributes().setBackFaceNormalFlip(true); } public void onFlip_OFF() { getPolygonAttributes().setBackFaceNormalFlip(false); } public void on0() { getPolygonAttributes().setPolygonOffset(0); } public void on10() { getPolygonAttributes().setPolygonOffset(10); } public void on50() { getPolygonAttributes().setPolygonOffset(50); } public void on200() { getPolygonAttributes().setPolygonOffset(200); } } class RenderingComponent extends AppearanceComponent { public RenderingComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE, RenderingAttributes.ALLOW_ALPHA_TEST_VALUE_WRITE, RenderingAttributes.ALLOW_DEPTH_ENABLE_READ }; } protected NodeComponent createComponent() { return (NodeComponent) new RenderingAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance .setRenderingAttributes((RenderingAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setRenderingAttributes(null); } protected String getName() { return "Rendering"; } protected String[] getMenuItemNames() { return new String[] { "-", "AlphaTest", "-", "ALWAYS", "NEVER", "EQUAL", "NOT_EQUAL", "LESS", "LESS_OR_EQUAL", "GREATER", "GREATER_OR_EQUAL", "-", "AlphaTest Value", "-", "0", "0point5", "1", "-", "Depth Buffer", "-", "On", "Off", "-", "Depth Buffer Write", "-", "Enable", "Disable", }; } private RenderingAttributes getRenderingAttributes() { return (RenderingAttributes) m_NodeComponent; } public void onALWAYS() { getRenderingAttributes().setAlphaTestFunction( RenderingAttributes.ALWAYS); } public void onNEVER() { getRenderingAttributes() .setAlphaTestFunction(RenderingAttributes.NEVER); } public void onEQUAL() { getRenderingAttributes() .setAlphaTestFunction(RenderingAttributes.EQUAL); } public void onNOT_EQUAL() { getRenderingAttributes().setAlphaTestFunction( RenderingAttributes.NOT_EQUAL); } public void onLESS() { getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.LESS); } public void onLESS_OR_EQUAL() { getRenderingAttributes().setAlphaTestFunction( RenderingAttributes.LESS_OR_EQUAL); } public void onGREATER() { getRenderingAttributes().setAlphaTestFunction( RenderingAttributes.GREATER); } public void onGREATER_OR_EQUAL() { getRenderingAttributes().setAlphaTestFunction( RenderingAttributes.GREATER_OR_EQUAL); } public void on0() { getRenderingAttributes().setAlphaTestValue(0); } public void on0point5() { getRenderingAttributes().setAlphaTestValue(0.5f); } public void on1() { getRenderingAttributes().setAlphaTestValue(1); } public void onOn() { getRenderingAttributes().setDepthBufferEnable(true); } public void onOff() { getRenderingAttributes().setDepthBufferEnable(false); } public void onEnable() { getRenderingAttributes().setDepthBufferWriteEnable(true); } public void onDisable() { getRenderingAttributes().setDepthBufferWriteEnable(false); } } class TexGenComponent extends AppearanceComponent { TexCoordGeneration m_TexCoordGeneration = null; final float m_PlaneFactor = 0.02f; public TexGenComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { TexCoordGeneration.ALLOW_ENABLE_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new TexCoordGeneration( TexCoordGeneration.OBJECT_LINEAR, TexCoordGeneration.TEXTURE_COORDINATE_3); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_TEXGEN_WRITE); } protected void assignToAppearance() { m_TexCoordGeneration = new TexCoordGeneration(); m_TexCoordGeneration.duplicateNodeComponent(m_NodeComponent); m_Appearance.setTexCoordGeneration(m_TexCoordGeneration); } protected void assignNullToAppearance() { m_Appearance.setTexCoordGeneration(null); } protected String getName() { return "TexCoordGen"; } protected String[] getMenuItemNames() { return new String[] { "-", "Enable", "-", "On", "Off", "-", "GenMode", "-", "EYE_LINEAR", "OBJECT_LINEAR", "SPHERE_MAP", "-", "Format", "-", "TEXTURE_COORDINATE_2", "TEXTURE_COORDINATE_3", "-", "Plane R", "-", "R_1_0_0_0", "R_0_1_0_5", "R_0_0_1_0", "R_0_0_0_1", "-", "Plane S", "-", "S_1_0_0_0", "S_0_1_0_5", "S_0_0_1_0", "S_0_0_0_1", "-", "Plane T", "-", "T_1_0_0_0", "T_0_1_0_5", "T_0_0_1_0", "T_0_0_0_1", }; } private TexCoordGeneration getTexCoordGeneration() { return (TexCoordGeneration) m_NodeComponent; } public void onOn() { getTexCoordGeneration().setEnable(true); assignToAppearance(); } public void onOff() { getTexCoordGeneration().setEnable(false); assignToAppearance(); } public void onEYE_LINEAR() { getTexCoordGeneration().setGenMode(TexCoordGeneration.EYE_LINEAR); assignToAppearance(); } public void onOBJECT_LINEAR() { getTexCoordGeneration().setGenMode(TexCoordGeneration.OBJECT_LINEAR); assignToAppearance(); } public void onSPHERE_MAP() { getTexCoordGeneration().setGenMode(TexCoordGeneration.SPHERE_MAP); assignToAppearance(); } public void onTEXTURE_COORDINATE_2() { getTexCoordGeneration().setFormat( TexCoordGeneration.TEXTURE_COORDINATE_2); assignToAppearance(); } public void onTEXTURE_COORDINATE_3() { getTexCoordGeneration().setFormat( TexCoordGeneration.TEXTURE_COORDINATE_3); assignToAppearance(); } public void onR_1_0_0_0() { getTexCoordGeneration().setPlaneR(new Vector4f(m_PlaneFactor, 0, 0, 0)); assignToAppearance(); } public void onR_0_1_0_5() { getTexCoordGeneration().setPlaneR( new Vector4f(0, m_PlaneFactor, 0, 0.5f)); assignToAppearance(); } public void onR_0_0_1_0() { getTexCoordGeneration().setPlaneR(new Vector4f(0, 0, m_PlaneFactor, 0)); assignToAppearance(); } public void onR_0_0_0_1() { getTexCoordGeneration().setPlaneR(new Vector4f(0, 0, 0, m_PlaneFactor)); assignToAppearance(); } public void onS_1_0_0_0() { getTexCoordGeneration().setPlaneS(new Vector4f(m_PlaneFactor, 0, 0, 0)); assignToAppearance(); } public void onS_0_1_0_5() { getTexCoordGeneration().setPlaneS( new Vector4f(0, m_PlaneFactor, 0, 0.5f)); assignToAppearance(); } public void onS_0_0_1_0() { getTexCoordGeneration().setPlaneS(new Vector4f(0, 0, m_PlaneFactor, 0)); assignToAppearance(); } public void onS_0_0_0_1() { getTexCoordGeneration().setPlaneS(new Vector4f(0, 0, 0, m_PlaneFactor)); assignToAppearance(); } public void onT_1_0_0_0() { getTexCoordGeneration().setPlaneT(new Vector4f(m_PlaneFactor, 0, 0, 0)); assignToAppearance(); } public void onT_0_1_0_5() { getTexCoordGeneration().setPlaneT( new Vector4f(0, m_PlaneFactor, 0, 0.5f)); assignToAppearance(); } public void onT_0_0_1_0() { getTexCoordGeneration().setPlaneT(new Vector4f(0, 0, m_PlaneFactor, 0)); assignToAppearance(); } public void onT_0_0_0_1() { getTexCoordGeneration().setPlaneT(new Vector4f(0, 0, 0, m_PlaneFactor)); assignToAppearance(); } } class TextureAttributesComponent extends AppearanceComponent { public TextureAttributesComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { TextureAttributes.ALLOW_BLEND_COLOR_WRITE, TextureAttributes.ALLOW_MODE_WRITE, TextureAttributes.ALLOW_TRANSFORM_WRITE, }; } protected NodeComponent createComponent() { return (NodeComponent) new TextureAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance.setTextureAttributes((TextureAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setTextureAttributes(null); } protected String getName() { return "TextureAttributes"; } protected String[] getMenuItemNames() { return new String[] { "-", "Mode", "-", "MODULATE", "DECAL", "BLEND", "REPLACE", "-", "Blend Color", "-", "T_White_Alpha_0point3", "T_Black_Alpha_0point7", "T_Blue_Alpha_1", "-", "Transform", "-", "0_degrees", "X_30_degrees", "Y_30_degrees", "Z_30_degrees", "-", "Perspective Correction", "-", "NICEST", "FASTEST" }; } private TextureAttributes getTextureAttributes() { return (TextureAttributes) m_NodeComponent; } public void onMODULATE() { getTextureAttributes().setTextureMode(TextureAttributes.MODULATE); } public void onDECAL() { getTextureAttributes().setTextureMode(TextureAttributes.DECAL); } public void onBLEND() { getTextureAttributes().setTextureMode(TextureAttributes.BLEND); } public void onREPLACE() { getTextureAttributes().setTextureMode(TextureAttributes.REPLACE); } public void onT_White_Alpha_0point3() { getTextureAttributes().setTextureBlendColor(1, 1, 1, 0.3f); } public void onT_Black_Alpha_0point7() { getTextureAttributes().setTextureBlendColor(0, 0, 0, 0.7f); } public void onT_Blue_Alpha_1() { getTextureAttributes().setTextureBlendColor(0, 0, 1, 1); } public void on0_degrees() { Transform3D t3d = new Transform3D(); getTextureAttributes().setTextureTransform(t3d); } public void onX_30_degrees() { Transform3D t3d = new Transform3D(); t3d.rotX(Math.toRadians(30)); getTextureAttributes().setTextureTransform(t3d); } public void onY_30_degrees() { Transform3D t3d = new Transform3D(); t3d.rotY(Math.toRadians(30)); getTextureAttributes().setTextureTransform(t3d); } public void onZ_30_degrees() { Transform3D t3d = new Transform3D(); t3d.rotZ(Math.toRadians(30)); getTextureAttributes().setTextureTransform(t3d); } public void onNICEST() { getTextureAttributes().setPerspectiveCorrectionMode( TextureAttributes.NICEST); } public void onFASTEST() { getTextureAttributes().setPerspectiveCorrectionMode( TextureAttributes.FASTEST); } } class TextureComponent extends AppearanceComponent { // hack, so we have an image observer when we load Textures public static Component m_Component = null; private Texture m_Texture = null; public TextureComponent(Appearance app) { super(app); } public static void setComponent(Component comp) { m_Component = comp; } protected int[] getCapabilities() { return new int[] { Texture.ALLOW_ENABLE_WRITE, }; } protected NodeComponent createComponent() { TextureLoader texLoader = new TextureLoader("texture00.jpg", m_Component); ImageComponent2D image = texLoader.getImage(); Texture2D tex2D = new Texture2D(Texture.MULTI_LEVEL_MIPMAP, Texture.RGBA, image.getWidth(), image.getHeight()); for (int n = 0; n <= 6; n++) { texLoader = new TextureLoader("texture0" + n + ".jpg", m_Component); tex2D.setImage(n, texLoader.getImage()); } return (NodeComponent) tex2D; } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE); } protected void assignToAppearance() { m_Texture = (Texture) new Texture2D(); m_Texture = (Texture) m_NodeComponent.cloneNodeComponent(true); m_Appearance.setTexture(m_Texture); } protected void assignNullToAppearance() { m_Appearance.setTexture(null); } protected String getName() { return "Texture"; } protected String[] getMenuItemNames() { return new String[] { "-", "Boundary Color", "-", "White", "Black", "BlueTransparent", "-", "Boundary Mode S", "-", "S_CLAMP", "S_WRAP", "-", "Boundary Mode T", "-", "T_CLAMP", "T_WRAP", "-", "Enable", "-", "On", "Off", "-", "Image", "-", "Texture0", "Texture1", "Texture2", "-", "MagFilter", "-", "Mag_FASTEST", "Mag_NICEST", "Mag_BASE_LEVEL_POINT", "Mag_BASE_LEVEL_LINEAR", "-", "MinFilter", "-", "Min_FASTEST", "Min_NICEST", "Min_BASE_LEVEL_POINT", "Min_BASE_LEVEL_LINEAR", "Min_MULTI_LEVEL_POINT", "Min_MULTI_LEVEL_LINEAR", "-", "MipMap Mode", "-", "BASE_LEVEL", "MULTI_LEVEL_MIPMAP", }; } private Texture getTexture() { return (Texture) m_NodeComponent; } public void onWhite() { getTexture().setBoundaryColor(1, 1, 1, 0); assignToAppearance(); } public void onBlack() { getTexture().setBoundaryColor(0, 0, 0, 0); assignToAppearance(); } public void onBlueTransparent() { getTexture().setBoundaryColor(0, 0, 1, 0.5f); assignToAppearance(); } public void onS_CLAMP() { getTexture().setBoundaryModeS(Texture.CLAMP); assignToAppearance(); } public void onS_WRAP() { getTexture().setBoundaryModeS(Texture.WRAP); assignToAppearance(); } public void onT_CLAMP() { getTexture().setBoundaryModeT(Texture.CLAMP); assignToAppearance(); } public void onT_WRAP() { getTexture().setBoundaryModeT(Texture.WRAP); assignToAppearance(); } public void onOn() { getTexture().setEnable(true); assignToAppearance(); } public void onOff() { getTexture().setEnable(false); assignToAppearance(); } public void onTexture0() { TextureLoader texLoader = null; for (int n = 0; n <= 6; n++) { texLoader = new TextureLoader("texture0" + n + ".jpg", m_Component); getTexture().setImage(n, texLoader.getImage()); } assignToAppearance(); } public void onTexture1() { TextureLoader texLoader = null; for (int n = 0; n <= 6; n++) { texLoader = new TextureLoader("texture1" + n + ".jpg", m_Component); getTexture().setImage(n, texLoader.getImage()); } assignToAppearance(); } public void onTexture2() { TextureLoader texLoader = null; for (int n = 0; n <= 6; n++) { texLoader = new TextureLoader("texture2" + n + ".gif", m_Component); getTexture().setImage(n, texLoader.getImage()); } assignToAppearance(); } public void onMag_FASTEST() { getTexture().setMagFilter(Texture.FASTEST); assignToAppearance(); } public void onMag_NICEST() { getTexture().setMagFilter(Texture.NICEST); assignToAppearance(); } public void onMag_BASE_LEVEL_POINT() { getTexture().setMagFilter(Texture.BASE_LEVEL_POINT); assignToAppearance(); } public void onMag_BASE_LEVEL_LINEAR() { getTexture().setMagFilter(Texture.BASE_LEVEL_LINEAR); assignToAppearance(); } public void onMin_FASTEST() { getTexture().setMinFilter(Texture.FASTEST); assignToAppearance(); } public void onMin_NICEST() { getTexture().setMinFilter(Texture.NICEST); assignToAppearance(); } public void onMin_BASE_LEVEL_POINT() { getTexture().setMinFilter(Texture.BASE_LEVEL_POINT); assignToAppearance(); } public void onMin_BASE_LEVEL_LINEAR() { getTexture().setMinFilter(Texture.BASE_LEVEL_LINEAR); assignToAppearance(); } public void onMin_MULTI_LEVEL_POINT() { getTexture().setMinFilter(Texture.MULTI_LEVEL_POINT); assignToAppearance(); } public void onMin_MULTI_LEVEL_LINEAR() { getTexture().setMinFilter(Texture.MULTI_LEVEL_LINEAR); assignToAppearance(); } public void onBASE_LEVEL() { getTexture().setMipMapMode(Texture.BASE_LEVEL); assignToAppearance(); } public void onMULTI_LEVEL_MIPMAP() { getTexture().setMipMapMode(Texture.MULTI_LEVEL_MIPMAP); assignToAppearance(); } } class TransparencyComponent extends AppearanceComponent { public TransparencyComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { TransparencyAttributes.ALLOW_MODE_WRITE, TransparencyAttributes.ALLOW_VALUE_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new TransparencyAttributes(); } protected void setAppearanceCapability() { m_Appearance .setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance .setTransparencyAttributes((TransparencyAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setTransparencyAttributes(null); } protected String getName() { return "Transparency"; } protected String[] getMenuItemNames() { return new String[] { "-", "Transparency", "-", "0", "0point2", "0point5", "0point8", "1", "-", "Mode", "-", "NONE", "FASTEST", "NICEST", "SCREEN_DOOR", "BLENDED" }; } private TransparencyAttributes getTransparencyAttributes() { return (TransparencyAttributes) m_NodeComponent; } public void on0() { getTransparencyAttributes().setTransparency(0); } public void on0point2() { getTransparencyAttributes().setTransparency(0.2f); } public void on0point5() { getTransparencyAttributes().setTransparency(0.5f); } public void on0point8() { getTransparencyAttributes().setTransparency(0.8f); } public void on1() { getTransparencyAttributes().setTransparency(1); } public void onNONE() { getTransparencyAttributes().setTransparencyMode( TransparencyAttributes.NONE); } public void onFASTEST() { getTransparencyAttributes().setTransparencyMode( TransparencyAttributes.FASTEST); } public void onNICEST() { getTransparencyAttributes().setTransparencyMode( TransparencyAttributes.NICEST); } public void onSCREEN_DOOR() { getTransparencyAttributes().setTransparencyMode( TransparencyAttributes.SCREEN_DOOR); } public void onBLENDED() { getTransparencyAttributes().setTransparencyMode( TransparencyAttributes.BLENDED); } } abstract class AppearanceComponent implements ActionListener { protected NodeComponent m_NodeComponent = null; protected Appearance m_Appearance = null; public AppearanceComponent(Appearance app) { m_Appearance = app; m_NodeComponent = createComponent(); int[] capsArray = getCapabilities(); if (capsArray != null) { for (int n = 0; n < capsArray.length; n++) m_NodeComponent.setCapability(capsArray[n]); } setAppearanceCapability(); assignToAppearance(); } abstract protected int[] getCapabilities(); abstract protected void setAppearanceCapability(); abstract protected NodeComponent createComponent(); abstract protected void assignToAppearance(); abstract protected void assignNullToAppearance(); abstract protected String getName(); abstract protected String[] getMenuItemNames(); public Menu createMenu() { String szName = getName(); String[] itemArray = getMenuItemNames(); ActionListener listener = this; Menu menu = new Menu(szName); MenuItem menuItem = new MenuItem("Null"); menuItem.addActionListener(listener); menu.add(menuItem); menuItem = new MenuItem("Non_Null"); menuItem.addActionListener(listener); menu.add(menuItem); for (int n = 0; n < itemArray.length; n++) { menuItem = new MenuItem(itemArray[n]); menuItem.addActionListener(listener); menu.add(menuItem); } return menu; } public void onNull() { assignNullToAppearance(); } public void onNon_Null() { assignToAppearance(); } public void actionPerformed(ActionEvent event) { // (primitive) menu command dispatch Class classObject = getClass(); Method[] methodArray = classObject.getMethods(); for (int n = methodArray.length - 1; n >= 0; n--) { if (("on" + event.getActionCommand()).equals(methodArray[n] .getName())) { try { methodArray[n].invoke(this, null); } catch (InvocationTargetException ie) { System.err .println("Warning. Menu handler threw exception: " + ie.getTargetException()); } catch (Exception e) { System.err .println("Warning. Menu dispatch exception: " + e); } return; } } } } class ColoringComponent extends AppearanceComponent { public ColoringComponent(Appearance app) { super(app); } protected int[] getCapabilities() { return new int[] { ColoringAttributes.ALLOW_COLOR_WRITE, ColoringAttributes.ALLOW_SHADE_MODEL_WRITE }; } protected NodeComponent createComponent() { return (NodeComponent) new ColoringAttributes(); } protected void setAppearanceCapability() { m_Appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); } protected void assignToAppearance() { m_Appearance .setColoringAttributes((ColoringAttributes) m_NodeComponent); } protected void assignNullToAppearance() { m_Appearance.setColoringAttributes(null); } protected String getName() { return "Coloring"; } protected String[] getMenuItemNames() { return new String[] { "-", "Color", "-", "Red", "Green", "Blue", "-", "Shade Model", "-", "Fastest", "Nicest", "Flat", "Gouraud" }; } private ColoringAttributes getColoringAttributes() { return (ColoringAttributes) m_NodeComponent; } public void onRed() { getColoringAttributes().setColor(1, 0, 0); } public void onGreen() { getColoringAttributes().setColor(0, 1, 0); } public void onBlue() { getColoringAttributes().setColor(0, 0, 1); } public void onFastest() { getColoringAttributes().setShadeModel(ColoringAttributes.FASTEST); } public void onNicest() { getColoringAttributes().setShadeModel(ColoringAttributes.NICEST); } public void onFlat() { getColoringAttributes().setShadeModel(ColoringAttributes.SHADE_FLAT); } public void onGouraud() { getColoringAttributes().setShadeModel(ColoringAttributes.SHADE_GOURAUD); } } //File: hand1.obj /*
- Mon Jun 02 17:09:33 1997
- 281 vertices
- 0 texture vertices
- 0 normals
- 552 elements
- /
Displays a simple driving type game scene, using texture mapped cubes
<source lang="java">
/**********************************************************
Copyright (C) 2001 Daniel Selman First distributed with the book "Java 3D Programming" by Daniel Selman and published by Manning Publications. http://manning.ru/selman 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, version 2. 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. The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Authors can be contacted at: Daniel Selman: daniel@selman.org If you make changes you think others would like, please contact one of the authors or someone at the www.j3d.org web site. **************************************************************/
import java.applet.Applet; import java.awt.AWTEvent; import java.awt.ruponent; import java.awt.event.KeyEvent; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.Vector; import javax.media.j3d.Alpha; import javax.media.j3d.Appearance; import javax.media.j3d.Background; import javax.media.j3d.BackgroundSound; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.Bounds; import javax.media.j3d.BranchGroup; import javax.media.j3d.GeometryArray; import javax.media.j3d.Group; import javax.media.j3d.MediaContainer; import javax.media.j3d.Node; import javax.media.j3d.PhysicalEnvironment; import javax.media.j3d.PointSound; import javax.media.j3d.PositionInterpolator; import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Sound; import javax.media.j3d.Texture; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.WakeupCondition; import javax.media.j3d.WakeupCriterion; import javax.media.j3d.WakeupOnAWTEvent; import javax.media.j3d.WakeupOnCollisionEntry; import javax.media.j3d.WakeupOnCollisionExit; import javax.media.j3d.WakeupOr; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Quat4f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import javax.vecmath.Vector4f; import com.sun.j3d.audioengines.javasound.JavaSoundMixer; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; import com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator; import com.sun.j3d.utils.behaviors.interpolators.TCBKeyFrame; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewerAvatar; /**
* Displays a simple driving type game scene, using texture mapped cubes. It * assigns an Avatar to the viewer and incorporates simple sounds and collision * detection/notification/ * <p> * This example does not use the Java3dApplet base class but is based on a * SimpleUniverse construction instead. that way we can illustrate the * setPlatformGeometry call. */
public class AvatarTest extends Applet {
public BranchGroup createSceneGraph() { BranchGroup bg = new BranchGroup(); TransformGroup tgRoot = addBehaviors(bg); createBuildings(tgRoot); createRoad(tgRoot); createLand(tgRoot); createCars(tgRoot); createBackground(bg); return bg; } public void createBackground(Group bg) { // add the sky backdrop Background back = new Background(); back.setApplicationBounds(getBoundingSphere()); bg.addChild(back); BranchGroup bgGeometry = new BranchGroup(); // create an appearance and assign the texture image Appearance app = new Appearance(); Texture tex = new TextureLoader("back.jpg", this).getTexture(); app.setTexture(tex); Sphere sphere = new Sphere(1.0f, Primitive.GENERATE_TEXTURE_COORDS | Primitive.GENERATE_NORMALS_INWARD, app); bgGeometry.addChild(sphere); back.setGeometry(bgGeometry); } public Group createLand(Group g) { Land land = new Land(this, g, ComplexObject.GEOMETRY | ComplexObject.TEXTURE); return land.createObject(new Appearance(), new Vector3d(0, 0, 0), new Vector3d(1, 1, 1), "land.jpg", null, null); } public Group createRoad(Group g) { Road road = new Road(this, g, ComplexObject.GEOMETRY | ComplexObject.TEXTURE); return road.createObject(new Appearance(), new Vector3d(0, 0, 0), new Vector3d(1, 1, 1), "road.jpg", null, null); } private float getRandomNumber(float basis, float random) { return basis + ((float) Math.random() * random * 2) - (random); } public Group createBuildings(Group g) { BranchGroup bg = new BranchGroup(); for (int n = (int) Road.ROAD_LENGTH; n < 0; n = n + 10) { Building building = new Building(this, bg, ComplexObject.GEOMETRY | ComplexObject.TEXTURE | ComplexObject.COLLISION); building.createObject(new Appearance(), new Vector3d( getRandomNumber(-4.0f, 0.25f), getRandomNumber(1.0f, 0.5f), getRandomNumber(n, 0.5f)), new Vector3d(1, 1, 1), "house.jpg", null, null); building = new Building(this, bg, ComplexObject.GEOMETRY | ComplexObject.TEXTURE | ComplexObject.COLLISION); building.createObject(new Appearance(), new Vector3d( getRandomNumber(4.0f, 0.25f), getRandomNumber(1.0f, 0.5f), getRandomNumber(n, 0.5f)), new Vector3d(1, 1, 1), "house.jpg", null, null); } g.addChild(bg); return bg; } public Group createCars(Group g) { BranchGroup bg = new BranchGroup(); for (int n = (int) Road.ROAD_LENGTH; n < 0; n = n + 10) { Car car = new Car(this, bg, ComplexObject.GEOMETRY | ComplexObject.TEXTURE | ComplexObject.SOUND); car.createObject(new Appearance(), new Vector3d(getRandomNumber( 0.0f, 2.0f), Car.CAR_HEIGHT / 2.0f, getRandomNumber(n, 5.0f)), new Vector3d(1, 1, 1), "car0.jpg", "car.wav", "collide.wav"); } g.addChild(bg); return bg; } public TransformGroup addBehaviors(Group bgRoot) { // Create the transform group node and initialize it to the // identity. Enable the TRANSFORM_WRITE capability so that // our behavior code can modify it at runtime. Add it to the // root of the subgraph. TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Transform3D zAxis = new Transform3D(); zAxis.rotY(Math.toRadians(90.0)); Alpha zoomAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 20000, 0, 0, 0, 0, 0); PositionInterpolator posInt = new PositionInterpolator(zoomAlpha, objTrans, zAxis, 0, -160); posInt.setSchedulingBounds(getBoundingSphere()); objTrans.addChild(posInt); bgRoot.addChild(objTrans); return objTrans; } BoundingSphere getBoundingSphere() { return new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 400.0); } ViewerAvatar createAvatar() { ViewerAvatar va = new ViewerAvatar(); TransformGroup tg = new TransformGroup(); Car car = new Car(this, tg, ComplexObject.GEOMETRY | ComplexObject.TEXTURE | ComplexObject.COLLISION | ComplexObject.COLLISION_SOUND); car.createObject(new Appearance(), new Vector3d(0, -0.3, -0.3), new Vector3d(0.3, 0.3, 1), "platform.jpg", null, "collide.wav"); tg.addChild(car); va.addChild(tg); return va; } public static void main(String[] args) { AvatarTest avatarTest = new AvatarTest(); // Create a simple scene and attach it to the virtual universe SimpleUniverse u = new SimpleUniverse(); PhysicalEnvironment physicalEnv = u.getViewer() .getPhysicalEnvironment(); TransformGroup tg = u.getViewer().getViewingPlatform() .getViewPlatformTransform(); Transform3D t3d = new Transform3D(); t3d.set(new Vector3f(0, 0.5f, 0)); tg.setTransform(t3d); CarSteering keys = new CarSteering(tg); keys.setSchedulingBounds(avatarTest.getBoundingSphere()); u.getViewer().setAvatar(avatarTest.createAvatar()); if (physicalEnv != null) { JavaSoundMixer javaSoundMixer = new JavaSoundMixer(physicalEnv); if (javaSoundMixer == null) System.out.println("Unable to create AudioDevice."); javaSoundMixer.initialize(); } // Add everthing to the scene graph - it will now be displayed. BranchGroup scene = avatarTest.createSceneGraph(); scene.addChild(keys);
// Java3dTree j3dTree = new Java3dTree();
// j3dTree.recursiveApplyCapability(scene); u.addBranchGraph(scene); //j3dTree.updateNodes(u); u.getViewingPlatform().getViewPlatform().setActivationRadius(2); }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class Building extends ComplexObject {
private final float BUILDING_WIDTH = 1.0f; private final float BUILDING_LENGTH = 1.0f; public Building(Component comp, Group g, int nFlags) { super(comp, g, nFlags); } private float getRandomNumber(float basis, float random) { return basis + ((float) Math.random() * random * 2) - (random); } protected Group createGeometryGroup(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile) { int nPrimFlags = 0; if ((m_nFlags & ComplexObject.TEXTURE) == ComplexObject.TEXTURE) { nPrimFlags |= Primitive.GENERATE_TEXTURE_COORDS; setTexture(app, szTextureFile); } return new Box(getRandomNumber(BUILDING_WIDTH, 0.25f), (float) position.y, getRandomNumber(BUILDING_LENGTH, 0.15f), nPrimFlags, app); }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class Land extends ComplexObject {
private final float LAND_WIDTH = 100.0f; private final float LAND_HEIGHT = 0.0f; private final float LAND_LENGTH = -200.0f; public Land(Component comp, Group g, int nFlags) { super(comp, g, nFlags); } protected Group createGeometryGroup(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile) { QuadArray quadArray = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2); float[] coordArray = { -LAND_WIDTH, LAND_HEIGHT, 0, LAND_WIDTH, LAND_HEIGHT, 0, LAND_WIDTH, LAND_HEIGHT, LAND_LENGTH, -LAND_WIDTH, LAND_HEIGHT, LAND_LENGTH }; float[] texArray = { 0, 0, 1, 0, 1, 1, 0, 1 }; quadArray.setCoordinates(0, coordArray, 0, 4); if ((m_nFlags & TEXTURE) == TEXTURE) { quadArray.setTextureCoordinates(0, 0, texArray, 0, 4); setTexture(app, szTextureFile); } Shape3D sh = new Shape3D(quadArray, app); BranchGroup bg = new BranchGroup(); bg.addChild(sh); return bg; }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class CollisionBehavior extends Behavior {
private WakeupOnCollisionEntry wakeupOne = null; private WakeupOnCollisionExit wakeupTwo = null; private WakeupCriterion[] wakeupArray = new WakeupCriterion[2]; private WakeupCondition wakeupCondition = null; private ComplexObject m_Owner = null; public CollisionBehavior(Node node, ComplexObject owner) { wakeupOne = new WakeupOnCollisionEntry(node, WakeupOnCollisionEntry.USE_BOUNDS); wakeupTwo = new WakeupOnCollisionExit(node, WakeupOnCollisionExit.USE_BOUNDS); wakeupArray[0] = wakeupOne; wakeupArray[1] = wakeupTwo; wakeupCondition = new WakeupOr(wakeupArray); m_Owner = owner; } /** * Override Behavior"s initialize method to setup wakeup criteria. */ public void initialize() { // Establish initial wakeup criteria wakeupOn(wakeupCondition); } /** * Override Behavior"s stimulus method to handle the event. */ public void processStimulus(Enumeration criteria) { WakeupCriterion genericEvt; while (criteria.hasMoreElements()) { genericEvt = (WakeupCriterion) criteria.nextElement(); if (genericEvt instanceof WakeupOnCollisionEntry) { m_Owner.onCollide(true); } else if (genericEvt instanceof WakeupOnCollisionExit) { m_Owner.onCollide(false); } } // Set wakeup criteria for next time wakeupOn(wakeupCondition); }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class CarSteering extends Behavior {
private WakeupOnAWTEvent wakeupOne = null; private WakeupCriterion[] wakeupArray = new WakeupCriterion[1]; private WakeupCondition wakeupCondition = null; private final float TRANSLATE_LEFT = -0.05f; private final float TRANSLATE_RIGHT = 0.05f; TransformGroup m_TransformGroup = null; public CarSteering(TransformGroup tg) { m_TransformGroup = tg; try { m_TransformGroup .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); m_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); } catch (Exception e) { } wakeupOne = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED); wakeupArray[0] = wakeupOne; wakeupCondition = new WakeupOr(wakeupArray); } /** * Override Behavior"s initialize method to setup wakeup criteria. */ public void initialize() { // Establish initial wakeup criteria wakeupOn(wakeupCondition); } /** * Override Behavior"s stimulus method to handle the event. */ public void processStimulus(Enumeration criteria) { WakeupOnAWTEvent ev; WakeupCriterion genericEvt; AWTEvent[] events; while (criteria.hasMoreElements()) { genericEvt = (WakeupCriterion) criteria.nextElement(); if (genericEvt instanceof WakeupOnAWTEvent) { ev = (WakeupOnAWTEvent) genericEvt; events = ev.getAWTEvent(); processAWTEvent(events); } } // Set wakeup criteria for next time wakeupOn(wakeupCondition); } /** * Process a keyboard event */ private void processAWTEvent(AWTEvent[] events) { for (int n = 0; n < events.length; n++) { if (events[n] instanceof KeyEvent) { KeyEvent eventKey = (KeyEvent) events[n]; if (eventKey.getID() == KeyEvent.KEY_PRESSED) { int keyCode = eventKey.getKeyCode(); int keyChar = eventKey.getKeyChar(); Vector3f translate = new Vector3f(); Transform3D t3d = new Transform3D(); m_TransformGroup.getTransform(t3d); t3d.get(translate); switch (keyCode) { case KeyEvent.VK_LEFT: translate.x += TRANSLATE_LEFT; break; case KeyEvent.VK_RIGHT: translate.x += TRANSLATE_RIGHT; break; } // System.out.println( "Steering: " + translate.x ); translate.y = 0.5f; t3d.setTranslation(translate); m_TransformGroup.setTransform(t3d); } } } }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class Car extends ComplexObject {
public static final float CAR_WIDTH = 0.2f; public static final float CAR_HEIGHT = 0.2f; public static final float CAR_LENGTH = 0.6f; public Car(Component comp, Group g, int nFlags) { super(comp, g, nFlags); } private float getRandomNumber(float basis, float random) { return basis + ((float) Math.random() * random * 2) - (random); } public Bounds getGeometryBounds() { return new BoundingSphere(new Point3d(0, 0, 0), 0.2); } protected Group createGeometryGroup(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile) { int nPrimFlags = 0; if ((m_nFlags & ComplexObject.TEXTURE) == ComplexObject.TEXTURE) { nPrimFlags |= Primitive.GENERATE_TEXTURE_COORDS; setTexture(app, szTextureFile); } return new Box(CAR_WIDTH, (float) position.y, getRandomNumber( CAR_LENGTH, 0.01f), nPrimFlags, app); }
} /**
* This class is a simple behavior that invokes the KeyNavigator to modify the * view platform transform. */
class Road extends ComplexObject {
public static final float ROAD_WIDTH = 3.0f; public static final float ROAD_HEIGHT = 0.01f; public static final float ROAD_LENGTH = -200.0f; public Road(Component comp, Group g, int nFlags) { super(comp, g, nFlags); } protected Group createGeometryGroup(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile) { // creates a segment of road 200 x 2 QuadArray quadArray = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2); float[] coordArray = { -ROAD_WIDTH, ROAD_HEIGHT, 0, ROAD_WIDTH, ROAD_HEIGHT, 0, ROAD_WIDTH, ROAD_HEIGHT, ROAD_LENGTH, -ROAD_WIDTH, ROAD_HEIGHT, ROAD_LENGTH }; float[] texArray = { 0, 0, 1, 0, 1, 1, 0, 1 }; quadArray.setCoordinates(0, coordArray, 0, 4); if ((m_nFlags & TEXTURE) == TEXTURE) { quadArray.setTextureCoordinates(0, 0, texArray, 0, 4); setTexture(app, szTextureFile); } Shape3D sh = new Shape3D(quadArray, app); BranchGroup bg = new BranchGroup(); bg.addChild(sh); return bg; }
} abstract class ComplexObject extends BranchGroup {
protected Group m_ParentGroup = null; protected int m_nFlags = 0; protected BackgroundSound m_CollideSound = null; protected Component m_Component = null; protected TransformGroup m_TransformGroup = null; protected TransformGroup m_BehaviorTransformGroup = null; public static final int SOUND = 0x001; public static final int GEOMETRY = 0x002; public static final int TEXTURE = 0x004; public static final int COLLISION = 0x008; public static final int COLLISION_SOUND = 0x010; public ComplexObject(Component comp, Group group, int nFlags) { m_ParentGroup = group; m_nFlags = nFlags; m_Component = comp; } public Bounds getGeometryBounds() { return new BoundingSphere(new Point3d(0, 0, 0), 100); } private MediaContainer loadSoundFile(String szFile) { try { File file = new File(System.getProperty("user.dir")); URL url = file.toURL(); URL soundUrl = new URL(url, szFile); return new MediaContainer(soundUrl); } catch (Exception e) { System.err.println("Error could not load sound file: " + e); System.exit(-1); } return null; } protected void setTexture(Appearance app, String szFile) { Texture tex = new TextureLoader(szFile, m_Component).getTexture(); app.setTexture(tex); } abstract protected Group createGeometryGroup(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile); protected Group loadGeometryGroup(String szModel, Appearance app) throws java.io.FileNotFoundException { // load the object file Scene scene = null; Shape3D shape = null; // read in the geometry information from the data file ObjectFile objFileloader = new ObjectFile(ObjectFile.RESIZE); scene = objFileloader.load(szModel); // retrieve the Shape3D object from the scene BranchGroup branchGroup = scene.getSceneGroup(); shape = (Shape3D) branchGroup.getChild(0); shape.setAppearance(app); return branchGroup; } protected int getSoundLoop(boolean bCollide) { return 1; } protected float getSoundPriority(boolean bCollide) { return 1.0f; } protected float getSoundInitialGain(boolean bCollide) { return 1.0f; } protected boolean getSoundInitialEnable(boolean bCollide) { return true; } protected boolean getSoundContinuousEnable(boolean bCollide) { return false; } protected Bounds getSoundSchedulingBounds(boolean bCollide) { return new BoundingSphere(new Point3d(0, 0, 0), 1.0); } protected boolean getSoundReleaseEnable(boolean bCollide) { return true; } protected Point2f[] getSoundDistanceGain(boolean bCollide) { return null; } protected void setSoundAttributes(Sound sound, boolean bCollide) { sound.setCapability(Sound.ALLOW_ENABLE_WRITE); sound.setCapability(Sound.ALLOW_ENABLE_READ); sound.setSchedulingBounds(getSoundSchedulingBounds(bCollide)); sound.setEnable(getSoundInitialEnable(bCollide)); sound.setLoop(getSoundLoop(bCollide)); sound.setPriority(getSoundPriority(bCollide)); sound.setInitialGain(getSoundInitialGain(bCollide)); sound.setContinuousEnable(getSoundContinuousEnable(bCollide)); sound.setReleaseEnable(bCollide); if (sound instanceof PointSound) { PointSound pointSound = (PointSound) sound; pointSound.setInitialGain(getSoundInitialGain(bCollide)); Point2f[] gainArray = getSoundDistanceGain(bCollide); if (gainArray != null) pointSound.setDistanceGain(gainArray); } } public Group createObject(Appearance app, Vector3d position, Vector3d scale, String szTextureFile, String szSoundFile, String szCollisionSound) { m_TransformGroup = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(scale); t3d.setTranslation(position); m_TransformGroup.setTransform(t3d); m_BehaviorTransformGroup = new TransformGroup(); if ((m_nFlags & GEOMETRY) == GEOMETRY) m_BehaviorTransformGroup.addChild(createGeometryGroup(app, position, scale, szTextureFile, szSoundFile)); if ((m_nFlags & SOUND) == SOUND) { MediaContainer media = loadSoundFile(szSoundFile); PointSound pointSound = new PointSound(media, getSoundInitialGain(false), 0, 0, 0); setSoundAttributes(pointSound, false); m_BehaviorTransformGroup.addChild(pointSound); } if ((m_nFlags & COLLISION) == COLLISION) { m_BehaviorTransformGroup .setCapability(Node.ENABLE_COLLISION_REPORTING); m_BehaviorTransformGroup.setCollidable(true); m_BehaviorTransformGroup.setCollisionBounds(getGeometryBounds()); if ((m_nFlags & COLLISION_SOUND) == COLLISION_SOUND) { MediaContainer collideMedia = loadSoundFile(szCollisionSound); m_CollideSound = new BackgroundSound(collideMedia, 1); setSoundAttributes(m_CollideSound, true); m_TransformGroup.addChild(m_CollideSound); } CollisionBehavior collision = new CollisionBehavior( m_BehaviorTransformGroup, this); collision.setSchedulingBounds(getGeometryBounds()); m_BehaviorTransformGroup.addChild(collision); } m_TransformGroup.addChild(m_BehaviorTransformGroup); m_ParentGroup.addChild(m_TransformGroup); return m_BehaviorTransformGroup; } public void onCollide(boolean bCollide) { System.out.println("Collide: " + bCollide); if (m_CollideSound != null && bCollide == true) m_CollideSound.setEnable(true); } public void attachBehavior(Behavior beh) { m_BehaviorTransformGroup .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); beh.setSchedulingBounds(getGeometryBounds()); m_BehaviorTransformGroup.addChild(beh); } public TransformGroup getBehaviorTransformGroup() { return m_BehaviorTransformGroup; } public void attachSplinePathInterpolator(Alpha alpha, Transform3D axis, URL urlKeyframes) { // read a spline path definition file and // add a Spline Path Interpolator to the TransformGroup for the object. m_BehaviorTransformGroup .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); RotPosScaleTCBSplinePathInterpolator splineInterpolator = Utils .createSplinePathInterpolator(alpha, m_BehaviorTransformGroup, axis, urlKeyframes); if (splineInterpolator != null) { splineInterpolator.setSchedulingBounds(getGeometryBounds()); m_BehaviorTransformGroup.addChild(splineInterpolator); } else { System.out.println("attachSplinePathInterpolator failed for: " + urlKeyframes); } }
} //***************************************************************************** /**
* Utils * * @author Daniel Selman * @version 1.0 */
//***************************************************************************** class Utils {
// convert an angular rotation about an axis to a Quaternion static Quat4f createQuaternionFromAxisAndAngle(Vector3d axis, double angle) { double sin_a = Math.sin(angle / 2); double cos_a = Math.cos(angle / 2); // use a vector so we can call normalize Vector4f q = new Vector4f(); q.x = (float) (axis.x * sin_a); q.y = (float) (axis.y * sin_a); q.z = (float) (axis.z * sin_a); q.w = (float) cos_a; // It is necessary to normalise the quaternion // in case any values are very close to zero. q.normalize(); // convert to a Quat4f and return return new Quat4f(q); } // convert three rotations about the Euler axes to a Quaternion static Quat4f createQuaternionFromEuler(double angleX, double angleY, double angleZ) { // simply call createQuaternionFromAxisAndAngle // for each axis and multiply the results Quat4f qx = createQuaternionFromAxisAndAngle(new Vector3d(1, 0, 0), angleX); Quat4f qy = createQuaternionFromAxisAndAngle(new Vector3d(0, 1, 0), angleY); Quat4f qz = createQuaternionFromAxisAndAngle(new Vector3d(0, 0, 1), angleZ); // qx = qx * qy qx.mul(qy); // qx = qx * qz qx.mul(qz); return qx; } static public double getRandomNumber(double basis, double random) { return basis + ((float) Math.random() * random * 2f) - (random); } static public double getRandomNumber(double basis, double random, double scale) { double value = basis + ((float) Math.random() * random * 2f) - (random); return value * scale; } static public StringBuffer readFile(URL urlFile) { // allocate a temporary buffer to store the input file StringBuffer szBufferData = new StringBuffer(); Vector keyFramesVector = new Vector(); try { InputStream inputStream = urlFile.openStream(); int nChar = 0; // read the entire file into the StringBuffer while (true) { nChar = inputStream.read(); // if we have not hit the end of file // add the character to the StringBuffer if (nChar != -1) szBufferData.append((char) nChar); else // EOF break; } inputStream.close(); } catch (Exception e) { System.err.println(e.toString()); return null; } return szBufferData; } static public RotPosScaleTCBSplinePathInterpolator createSplinePathInterpolator( Alpha alpha, TransformGroup tg, Transform3D axis, URL urlKeyframes) { TCBKeyFrame[] keyFrames = readKeyFrames(urlKeyframes); if (keyFrames != null) return new RotPosScaleTCBSplinePathInterpolator(alpha, tg, axis, keyFrames); return null; } static public TCBKeyFrame[] readKeyFrames(URL urlKeyframes) { StringBuffer szBufferData = readFile(urlKeyframes); if (szBufferData == null) return null; Vector keyFramesVector = new Vector(); // create a tokenizer to tokenize the input file at whitespace java.util.StringTokenizer tokenizer = new java.util.StringTokenizer( szBufferData.toString()); // each keyframe is defined as follows // - knot (0 >= k <= 1) // - position (x,y,z) // - rotation (rx,ry,rz) // - scale (x,y,z) // - tension (-1 >= t <= 1) // - continuity (-1 >= c <= 1) // - bias (-1 >= b <= 1) // - linear (int - 0 or 1) while (true) { try { float knot = Float.parseFloat(tokenizer.nextToken()); float posX = Float.parseFloat(tokenizer.nextToken()); float posY = Float.parseFloat(tokenizer.nextToken()); float posZ = Float.parseFloat(tokenizer.nextToken()); float rotX = Float.parseFloat(tokenizer.nextToken()); float rotY = Float.parseFloat(tokenizer.nextToken()); float rotZ = Float.parseFloat(tokenizer.nextToken()); float scaleX = Float.parseFloat(tokenizer.nextToken()); float scaleY = Float.parseFloat(tokenizer.nextToken()); float scaleZ = Float.parseFloat(tokenizer.nextToken()); float tension = Float.parseFloat(tokenizer.nextToken()); float continuity = Float.parseFloat(tokenizer.nextToken()); float bias = Float.parseFloat(tokenizer.nextToken()); int linear = Integer.parseInt(tokenizer.nextToken()); TCBKeyFrame keyframe = new TCBKeyFrame(knot, linear, new Point3f(posX, posY, posZ), createQuaternionFromEuler(rotX, rotY, rotZ), new Point3f(scaleX, scaleY, scaleZ), tension, continuity, bias); keyFramesVector.add(keyframe); } catch (Exception e) { break; } } // create the return structure and populate TCBKeyFrame[] keysReturn = new TCBKeyFrame[keyFramesVector.size()]; for (int n = 0; n < keysReturn.length; n++) keysReturn[n] = (TCBKeyFrame) keyFramesVector.get(n); // return the array return keysReturn; }
}
</source>
This builds up a simple scene from primitives
<source lang="java">
/* Essential Java 3D Fast Ian Palmer Publisher: Springer-Verlag ISBN: 1-85233-394-4
- /
import java.awt.BorderLayout; import java.awt.Button; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.Locale; import javax.media.j3d.Material; import javax.media.j3d.Node; import javax.media.j3d.PhysicalBody; import javax.media.j3d.PhysicalEnvironment; 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.AxisAngle4d; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Vector3f; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.geometry.Cylinder; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.geometry.Sphere; /**
* This builds up a simple scene from primitives. It builds a circular "house" * with a conical "roof", and then creates three "trees" made up of cylinders * and spheres. All this is place on a ground made up of a cube. * * @author I.J.Palmer * @version 1.0 */
public class SimpleCombine extends Frame implements ActionListener {
protected Canvas3D myCanvas3D = new Canvas3D(null); protected Button myButton = new Button("Exit"); /** * This function builds the view branch of the scene graph. It creates a * branch group and then creates the necessary view elements to give a * useful view of our content. * * @param c * Canvas3D that will display the view * @return BranchGroup that is the root of the view elements */ protected BranchGroup buildViewBranch(Canvas3D c) { BranchGroup viewBranch = new BranchGroup(); Transform3D viewXfm = new Transform3D(); viewXfm.set(new Vector3f(0.0f, 0.0f, 7.0f)); TransformGroup viewXfmGroup = new TransformGroup(viewXfm); ViewPlatform myViewPlatform = new ViewPlatform(); PhysicalBody myBody = new PhysicalBody(); PhysicalEnvironment myEnvironment = new PhysicalEnvironment(); viewXfmGroup.addChild(myViewPlatform); viewBranch.addChild(viewXfmGroup); View myView = new View(); myView.addCanvas3D(c); myView.attachViewPlatform(myViewPlatform); myView.setPhysicalBody(myBody); myView.setPhysicalEnvironment(myEnvironment); return viewBranch; } /** * Add some lights so that we can illuminate the scene. This adds one * ambient light to bring up the overall lighting level and one directional * shape to show the shape of the objects in the scene. * * @param b * BranchGroup that the lights are to be added to. */ protected void addLights(BranchGroup b) { BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); Color3f lightColour1 = new Color3f(1.0f, 1.0f, 1.0f); Vector3f lightDir1 = new Vector3f(-1.0f, -1.0f, -1.0f); Color3f lightColour2 = new Color3f(1.0f, 1.0f, 1.0f); Vector3f lightDir2 = new Vector3f(1.0f, -1.0f, -1.0f); DirectionalLight light1 = new DirectionalLight(lightColour1, lightDir1); light1.setInfluencingBounds(bounds); DirectionalLight light2 = new DirectionalLight(lightColour2, lightDir2); light2.setInfluencingBounds(bounds); b.addChild(light1); b.addChild(light2); } /** * This builds the content branch of our scene graph. The root of the shapes * supplied as a parameter is slightly tilted to reveal its 3D shape. It * also uses the addLights function to add some lights to the scene. * * @param shape * Node that represents the geometry for the content * @return BranchGroup that is the root of the content branch */ protected BranchGroup buildContentBranch(Node shape) { BranchGroup contentBranch = new BranchGroup(); Transform3D rotateCube = new Transform3D(); rotateCube.set(new AxisAngle4d(1.0, 1.0, 0.0, Math.PI / 4.0)); TransformGroup rotationGroup = new TransformGroup(rotateCube); contentBranch.addChild(rotationGroup); rotationGroup.addChild(shape); addLights(contentBranch); return contentBranch; } /** * This defines the shapes used in the scene. The function uses the utility * geometries sphere, box, cone and cylinder to build a simple scene. This * demonstrates the use of transformations to group and position items. * * @return Node that is the root of the shape hierarchy. */ protected Node buildShape() { //Create a root for the shapes in the scene BranchGroup theScene = new BranchGroup(); //Create an appearance for the ground Appearance groundApp = new Appearance(); Color3f groundColour = new Color3f(0.0f, 0.5f, 0.0f); Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f); Color3f specularColour = new Color3f(0.5f, 0.5f, 0.5f); float shininess = 10.0f; groundApp.setMaterial(new Material(groundColour, emissiveColour, groundColour, specularColour, shininess)); //Create a box that will be the ground Box ground = new Box(100.0f, 0.1f, 100.0f, groundApp); //Create a transform and a transform group that //will position the ground Transform3D grndXfm = new Transform3D(); grndXfm.set(new Vector3f(0.0f, -1.0f, 0.0f)); TransformGroup grndXfmGrp = new TransformGroup(grndXfm); //Add the ground shape to the group grndXfmGrp.addChild(ground); //Add the ground group to the scene group theScene.addChild(grndXfmGrp); //Create an appearance for the wall of the house Appearance wallApp = new Appearance(); Color3f wallColour = new Color3f(0.5f, 0.5f, 0.5f); wallApp.setMaterial(new Material(wallColour, emissiveColour, wallColour, specularColour, shininess)); //Create a cylinder that is the wall of the house Cylinder walls = new Cylinder(1.0f, 1.0f, Primitive.GENERATE_NORMALS, wallApp); //Create a group that will be the root of the house TransformGroup house = new TransformGroup(); //Add the walls to the house group house.addChild(walls); //Create an appearance for the roof Appearance roofApp = new Appearance(); Color3f roofColour = new Color3f(0.5f, 0.0f, 0.0f); roofApp.setMaterial(new Material(roofColour, emissiveColour, roofColour, specularColour, shininess)); //Create a cone that will be the roof Cone myRoof = new Cone(1.0f, 1.0f, Primitive.GENERATE_NORMALS, roofApp); //Create the transform and transform group that will position the //roof on the house Transform3D roofXfm = new Transform3D(); roofXfm.set(new Vector3f(0.0f, 1.0f, 0.0f)); TransformGroup roofXfmGrp = new TransformGroup(roofXfm); //Add the roof to the roof transform group roofXfmGrp.addChild(myRoof); //Add the roof group to the house house.addChild(roofXfmGrp); //Create an appearance for the tree trunks Appearance trunkApp = new Appearance(); Color3f trunkColour = new Color3f(0.2f, 0.2f, 0.0f); trunkApp.setMaterial(new Material(trunkColour, emissiveColour, trunkColour, specularColour, shininess)); //Create an appearance for the tree leaves Appearance leafApp = new Appearance(); Color3f leafColour = new Color3f(0.0f, 0.2f, 0.0f); leafApp.setMaterial(new Material(leafColour, emissiveColour, leafColour, specularColour, shininess)); //Create a transform and transform group for the tree Transform3D treeXfm = new Transform3D(); treeXfm.set(new Vector3f(-2.0f, 0.0f, 0.5f)); TransformGroup treeXfmGrp = new TransformGroup(treeXfm); //Create a cylinder for the tree trunk Cylinder myTrunk = new Cylinder(0.1f, 1.0f, trunkApp); //Add the trunk to the tree group treeXfmGrp.addChild(myTrunk); //Create a transform and transform group for the tree leaves Transform3D leafXfm = new Transform3D(); leafXfm.set(new Vector3f(0.0f, 1.0f, 0.0f)); TransformGroup leafXfmGrp = new TransformGroup(leafXfm); //Create the leaves Sphere myLeaf = new Sphere(0.5f, leafApp); //Add the leaves to the leaf group leafXfmGrp.addChild(myLeaf); //Add the leaf group to the tree group treeXfmGrp.addChild(leafXfmGrp); //Create another tree Transform3D tree1Xfm = new Transform3D(); tree1Xfm.set(new Vector3f(1.4f, 0.0f, -0.5f)); TransformGroup tree1XfmGrp = new TransformGroup(tree1Xfm); Cylinder myTrunk1 = new Cylinder(0.1f, 1.0f, trunkApp); tree1XfmGrp.addChild(myTrunk1); Transform3D leaf1Xfm = new Transform3D(); leaf1Xfm.set(new Vector3f(0.0f, 1.0f, 0.0f)); TransformGroup leaf1XfmGrp = new TransformGroup(leaf1Xfm); Sphere myLeaf1 = new Sphere(0.5f, leafApp); leaf1XfmGrp.addChild(myLeaf1); tree1XfmGrp.addChild(leaf1XfmGrp); //Create the final tree Transform3D tree2Xfm = new Transform3D(); tree2Xfm.set(new Vector3f(1.2f, 0.0f, 1.0f)); TransformGroup tree2XfmGrp = new TransformGroup(tree2Xfm); Cylinder myTrunk2 = new Cylinder(0.1f, 1.0f, trunkApp); tree2XfmGrp.addChild(myTrunk2); Transform3D leaf2Xfm = new Transform3D(); leaf2Xfm.set(new Vector3f(0.0f, 1.0f, 0.0f)); TransformGroup leaf2XfmGrp = new TransformGroup(leaf2Xfm); Sphere myLeaf2 = new Sphere(0.5f, leafApp); leaf2XfmGrp.addChild(myLeaf2); tree2XfmGrp.addChild(leaf2XfmGrp); //Put the scene together by adding all the groups //to the scene group theScene.addChild(house); theScene.addChild(treeXfmGrp); theScene.addChild(tree1XfmGrp); theScene.addChild(tree2XfmGrp); return theScene; } /** * Handles the exit button action to quit the program. */ public void actionPerformed(ActionEvent e) { dispose(); System.exit(0); } public SimpleCombine() { VirtualUniverse myUniverse = new VirtualUniverse(); Locale myLocale = new Locale(myUniverse); myLocale.addBranchGraph(buildViewBranch(myCanvas3D)); myLocale.addBranchGraph(buildContentBranch(buildShape())); setTitle("SimpleWorld"); setSize(400, 400); setLayout(new BorderLayout()); add("Center", myCanvas3D); add("South", myButton); myButton.addActionListener(this); setVisible(true); } public static void main(String[] args) { SimpleCombine sw = new SimpleCombine(); }
}
</source>