package transp; import java.awt.*; import java.awt.event.*; import java.applet.*; import javax.swing.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.utils.universe.*; public class TestTransp extends JApplet { boolean isStandalone = false; static JFrame frame = null; /**Get a parameter value*/ public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } /**Construct the applet*/ public TestTransp() { } /**Initialize the applet*/ public void init() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } // end init() /**Component initialization*/ private void jbInit() throws Exception { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } // end try part catch(Exception e) { System.out.println("Error setting Windows LAF: " + e); } // end catch part if (frame == null) setupFrame(); // Build the initial scene. Canvas3D the3DCanvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration()); SimpleUniverse theSimpleUniverse = new SimpleUniverse(the3DCanvas); BranchGroup scene = createInitialSceneGraph(theSimpleUniverse); theSimpleUniverse.addBranchGraph(scene); // Put objects into frame window. frame.getContentPane().add("Center", the3DCanvas); frame.setVisible(true); } // end jbInit() void setupFrame() { Toolkit theKit = this.getToolkit(); Dimension windowSize = theKit.getScreenSize(); frame = new JFrame() { protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } } public synchronized void setTitle(String title) { super.setTitle(title); enableEvents(AWTEvent.WINDOW_EVENT_MASK); } }; frame.getContentPane().setBackground(Color.black); frame.setSize(new Dimension(windowSize.width / 2, windowSize.height / 2)); frame.getContentPane().setLayout(new BorderLayout()); } // end setupFrame /**Start the applet*/ public void start() { } /**Stop the applet*/ public void stop() { } /**Destroy the applet*/ public void destroy() { } /**Get Applet information*/ public String getAppletInfo() { return "Applet Information"; } /**Get parameter info*/ public String[][] getParameterInfo() { return null; } /**Main method*/ public static void main(String[] args) { TestTransp applet = new TestTransp(); applet.isStandalone = true; // I like seperate window for 3D stuff. if (frame == null) applet.setupFrame(); applet.init(); applet.start(); } // end main ///////////////////////////////////////// // Methods for creating various objects // for testing transparency. public BranchGroup createInitialSceneGraph(SimpleUniverse SU) { // Create the root of the branch graph BranchGroup objRoot = new BranchGroup(); BoundingSphere worldBounds = new BoundingSphere(new Point3d( 0.0, 0.0, 0.0 ), 10000.0 ); // Create an (ambient) light source TransformGroup lightTG = new TransformGroup(); Transform3D lightT3D = new Transform3D(); lightT3D.set(new Vector3d(20.0, 0.0, 0.0)); DirectionalLight DL = new DirectionalLight(new Color3f(1.0f, 1.0f, 1.0f), new Vector3f(-1.0f, 0.0f, 0.0f)); DL.setInfluencingBounds(worldBounds); lightTG.setTransform(lightT3D); lightTG.addChild(DL); objRoot.addChild(lightTG); AmbientLight lightA = new AmbientLight(); lightA.setInfluencingBounds(worldBounds); objRoot.addChild(lightA); // Set the initial viewing platform location TransformGroup vpTG = null; Transform3D vpT3D = new Transform3D(); vpTG = SU.getViewingPlatform().getViewPlatformTransform(); vpT3D.lookAt(new Point3d(20.0, 0.0, 0.0), new Point3d(0.0, 0.0, 0.0), new Vector3d(0.0, 0.0, 1.0)); vpT3D.invert(); vpTG.setTransform(vpT3D); // For transparency, make sure everything is rendered in correct depth order. // SU.getViewer().getView().setDepthBufferFreezeTransparent(false); SU.getViewer().getView().setDepthBufferFreezeTransparent(true); SU.getViewer().getView().setTransparencySortingPolicy(View.TRANSPARENCY_SORT_GEOMETRY); SU.getViewer().getView().setBackClipDistance(100.0); // Create background. Background BGround = new Background(); BGround.setApplicationBounds(worldBounds); objRoot.addChild(BGround); // Make the objects to be displayed. TransformGroup objTG = new TransformGroup(); Transform3D objT3D = new Transform3D(); objT3D.rotY(d2r(30.0)); objTG.setTransform(objT3D); objTG.addChild(makeObjects()); objRoot.addChild(objTG); return(objRoot); } // end of createSceneGraph method BranchGroup makeObjects() { BranchGroup BG = new BranchGroup(); // Create the torus Shape3D Torus; //////////////////////////////////////////// // Create the torus-like geometry. // Outer Shape3D Torus1 = createTorusGeometry2(10.0f, 85.0f, 5.0f, 0.5f); Torus1.setAppearance(createTorusAppearance(Color.red)); // Middle Shape3D Torus2 = createTorusGeometry2(15.0f, 80.0f, 4.0f, 0.7f); Torus2.setAppearance(createTorusAppearance(Color.blue)); // Inner most torus Shape3D Torus3 = createTorusGeometry2(20.0f, 70.0f, 3.0f, 0.9f); Torus3.setAppearance(createTorusAppearance(Color.green)); // Use an ordered group so *we* control the order in which objects // get rendered. OrderedGroup OBG = new OrderedGroup(); OBG.addChild(Torus3); // render this one 1st OBG.addChild(Torus2); // render this one 2nd OBG.addChild(Torus1); // render this one 3rd BG.addChild(OBG); return BG; } // end makeObjects Shape3D createTorusGeometry2(float startTheta, float endTheta, float radius, float funnelRadius) { // This method creates one QuadArray for the entire object. // The QuadArray will have many quad coordinates and normals defined. Shape3D theShape3D = new Shape3D(); float thetaInc = 5.0f; // 5 degree increaments. float phiInc = 5.0f; // 5 degree increaments. int numThetaDiv = (int)((endTheta - startTheta) / thetaInc) + 1; int numPhiDiv = (int)(360.0f / phiInc); Vector3f[][] thePoints = new Vector3f[numPhiDiv][numThetaDiv+1]; // populate the first longitude circle. float x; float y; float z; int i = 0; int j = 0; for (float phi=0.0f; phi<360.0f; phi=phi+phiInc) { j = 0; for (float theta=startTheta; theta<=endTheta; theta=theta+thetaInc) { // calculate the inside funnel point. if (j == 0) { x = (float)(funnelRadius * Math.cos(d2r(phi))); y = (float)(funnelRadius * Math.sin(d2r(phi))); z = (float)(radius * Math.cos(d2r(endTheta))); thePoints[i][j] = new Vector3f(x, y, z); j = j + 1; } // end if statement x = (float)(radius * Math.sin(d2r(theta)) * Math.cos(d2r(phi))); y = (float)(radius * Math.sin(d2r(theta)) * Math.sin(d2r(phi))); z = (float)(radius * Math.cos(d2r(theta))); thePoints[i][j] = new Vector3f(x, y, z); j = j + 1; } // end for theta statement i = i + 1; } // end for phi statement // We now have all the points to make the geometry. Vector3f hld1 = new Vector3f(0.0f, 0.0f, 0.0f); Vector3f hld2 = new Vector3f(0.0f, 0.0f, 0.0f); System.out.println("i: "+i+" j: "+j); int numPoints = 2 * (4 * i * j ); Point3f[] coord = new Point3f[numPoints]; Vector3f[] norms = new Vector3f[numPoints]; QuadArray qa = new QuadArray(numPoints, QuadArray.COORDINATES | QuadArray.NORMALS); int p = 0; for (int m=0; m<i; m++) { for (int n=0; n<j; n++) { int a = m+1; if (a == i) a = 0; int b = n+1; if (b == j) b = 0; coord[p+0] = new Point3f(thePoints[m][n]); coord[p+1] = new Point3f(thePoints[m][b]); coord[p+2] = new Point3f(thePoints[a][b]); coord[p+3] = new Point3f(thePoints[a][n]); hld1 = new Vector3f((coord[p+0].x - coord[p+1].x), (coord[p+0].y - coord[p+1].y), (coord[p+0].z - coord[p+1].z)); hld2 = new Vector3f((coord[p+2].x - coord[p+1].x), (coord[p+2].y - coord[p+1].y), (coord[p+2].z - coord[p+1].z)); norms[p+0] = new Vector3f(0.0f, 0.0f, 0.0f); norms[p+0].cross(hld2, hld1); norms[p+0].normalize(); norms[p+1] = new Vector3f(norms[p+0]); norms[p+2] = new Vector3f(norms[p+0]); norms[p+3] = new Vector3f(norms[p+0]); p = p + 4; // negative z part coord[p+0] = new Point3f(thePoints[m][n].x, thePoints[m][n].y, -thePoints[m][n].z); coord[p+1] = new Point3f(thePoints[m][b].x, thePoints[m][b].y, -thePoints[m][b].z); coord[p+2] = new Point3f(thePoints[a][b].x, thePoints[a][b].y, -thePoints[a][b].z); coord[p+3] = new Point3f(thePoints[a][n].x, thePoints[a][n].y, -thePoints[a][n].z); hld1 = new Vector3f((coord[p+0].x - coord[p+1].x), (coord[p+0].y - coord[p+1].y), (coord[p+0].z - coord[p+1].z)); hld2 = new Vector3f((coord[p+2].x - coord[p+1].x), (coord[p+2].y - coord[p+1].y), (coord[p+2].z - coord[p+1].z)); norms[p+0] = new Vector3f(0.0f, 0.0f, 0.0f); norms[p+0].cross(hld2, hld1); norms[p+0].normalize(); norms[p+1] = new Vector3f(norms[p+0]); norms[p+2] = new Vector3f(norms[p+0]); norms[p+3] = new Vector3f(norms[p+0]); p = p + 4; } // end for j statement } // end for i statement qa.setCoordinates(0, coord); qa.setNormals(0, norms); theShape3D.addGeometry(qa); return(theShape3D); } // end createTorusGeometry2() Appearance createTorusAppearance(Color theColor) { // This is the Appearance used to color the object (Shape3D). // It assigns the transparency attributes. // Playing with the various transparency settings tofigure // out if there is a transparency problem or a coding problem. float red = theColor.getRed() / 255.0f; float green = theColor.getGreen() / 255.0f; float blue = theColor.getBlue() / 255.0f; Appearance A = new Appearance(); RenderingAttributes RA = new RenderingAttributes(); RA.setDepthBufferEnable(true); A.setRenderingAttributes(RA); // We want the color to be defined by using materials. Material theMaterial = new Material(); theMaterial.setLightingEnable(true); theMaterial.setShininess(5.0f); theMaterial.setDiffuseColor(red, green, blue); theMaterial.setAmbientColor(0.1f, 0.1f, 0.1f); theMaterial.setEmissiveColor(0.0f, 0.0f, 0.0f); theMaterial.setSpecularColor(0.08f, 0.08f, 0.08f); A.setMaterial(theMaterial); // Setup polygon attributes PolygonAttributes PA = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_BACK, 0.01f, true); A.setPolygonAttributes(PA); // Setup Treansparency TransparencyAttributes TA = new TransparencyAttributes(TransparencyAttributes.NICEST, 0.5f); A.setTransparencyAttributes(TA); return(A); } // end createAppearancePlane static public double d2r(double angle) { return (angle * 2.0 * Math.PI / 360.0 ); } // end d2r static public double r2d(double angle) { return (angle * 360.0) / (2.0 * Math.PI); } // end r2d }