Introduction:
This application displays a real – time model of a virtual universe capable of user interaction. The program is written in Java 3D.
Java 3D is a high performance 3D graphics library built on OpenGL and Direct3D using Java from Sun Microsystems. This simplifies 3D graphics application development by providing a high level programming interface which is compatible with standard monitors, head – mounted displays and stereo viewing devices. This allows developers to focus on what to draw and not how to draw.
3D computer graphics is the displayed representation of a scene or an object that appears to have three axes of reference: Width, Height and Depth which is x, y and z in Cartesian Space.
Graphics are used for a wide range of applications including architecture, computer aided chemistry, medical imaging, computer aided engineering, movies and games.
Background:
After completing 9 different experiments in Java covering Scene Graphs, Conditional Rendering, Geometry, Appearance, Lighting , Backgrounds and Motion I was ready to produce this galaxy. I have understood the underlying concepts of 3D computer graphics and am able to create 3D content using specialized programming libraries.
This is the actual data for the planets size, orbit and position in our galaxy. For presentation purposes, it was not possible to implement these values in my galaxy.
Sun:
Our Sun is a normal main-sequence G2 star, one of more than 100 billion stars in our galaxy.
diameter: 1,390,000 km.
mass: 1.989e30 kg
temperature: 5800 K (surface)
15,600,000 K (core)
Mercury:
Mercury is the closest planet to the Sun and the eighth largest. Mercury is slightly smaller in diameter than the moons Ganymede and Titan but more than twice as massive.
orbit: 57,910,000 km (0.38 AU) from Sun
diameter: 4,880 km
mass: 3.30e23 kg
Venus:
Venus is the second planet from the Sun and the sixth largest. Venus’ orbit is the most nearly circular of that of any planet, with an eccentricity of less than 1%.
orbit: 108,200,000 km (0.72 AU) from Sun
diameter: 12,103.6 km
mass: 4.869e24 kg
Earth:
Earth is the third planet from the Sun and the fifth largest:
orbit: 149,600,000 km (1.00 AU) from Sun
diameter: 12,756.3 km
mass: 5.972e24 kg
Mars:
Mars is the fourth planet from the Sun and the seventh largest:
orbit: 227,940,000 km (1.52 AU) from Sun
diameter: 6,794 km
mass: 6.4219e23 kg
Jupiter:
Jupiter is the fifth planet from the Sun and by far the largest. Jupiter is more than twice as massive as all the other planets combined (the mass of Jupiter is 318 times that of Earth).
orbit: 778,330,000 km (5.20 AU) from Sun
diameter: 142,984 km (equatorial)
mass: 1.900e27 kg
Saturn:
Saturn is the sixth planet from the Sun and the second largest:
orbit: 1,429,400,000 km (9.54 AU) from Sun
diameter: 120,536 km (equatorial)
mass: 5.68e26 kg
Uranus:
Uranus is the seventh planet from the Sun and the third largest (by diameter). Uranus is larger in diameter but smaller in mass than Neptune.
orbit: 2,870,990,000 km (19.218 AU) from Sun
diameter: 51,118 km (equatorial)
mass: 8.683e25 kg
Neptune:
Neptune is the eighth planet from the Sun and the fourth largest (by diameter). Neptune is smaller in diameter but larger in mass than Uranus.
orbit: 4,504,000,000 km (30.06 AU) from Sun
diameter: 49,532 km (equatorial)
mass: 1.0247e26 kg
Pluto:
Pluto is the farthest planet from the Sun (usually) and by far the smallest. Pluto is smaller than seven of the solar system’s moons (the Moon, Io, Europa, Ganymede, Callisto, Titan and Triton).
orbit: 5,913,520,000 km (39.5 AU) from the Sun (average)
diameter: 2274 km
mass: 1.27e22 kg
With the exception of the sun, I made all the planets roughly the same size.
Design and Implementation:
The program was implemented as follows:
All libraries were imported:
import javax.swing.JFrame; import java.awt.BorderLayout; import java.awt.event.*; import java.awt.GraphicsConfiguration; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; import com.sun.j3d.utils.behaviors.mouse.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.utils.image.TextureLoader; import java.awt.*; import java.awt.image.*;
The canvas was set – up. A scene graph was created. To add music, I had to create the audio device which was to be declared here.
public class universe extends JFrame { public static void main(String[] args) { new universe(); } public universe() { getContentPane().setLayout(new BorderLayout()); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas = new Canvas3D(config); getContentPane().add(canvas, BorderLayout.CENTER); SimpleUniverse u = new SimpleUniverse(canvas); ViewingPlatform viewingPlatform = u.getViewingPlatform(); u.getViewingPlatform().setNominalViewingTransform(); u.getViewer().createAudioDevice(); BranchGroup scene = createSceneGraph(); u.addBranchGraph(scene); setSize(400, 400); setVisible(true); } public BranchGroup createSceneGraph() {
For light, I had to create a Transform Group, which had 3 children, Ambient Light, Directional Light and Point Light.
TransformGroup lightGroup = new TransformGroup(); lightGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); lightGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); objRoot.addChild(lightGroup); AmbientLight ambLight = new AmbientLight(new Color3f(0.8f,0.8f,0.8f)); ambLight.setInfluencingBounds( new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000.0)); lightGroup.addChild(ambLight); DirectionalLight dirLight = new DirectionalLight(new Color3f(0.4f,0.4f,0.4f), new Vector3f(-1.0f,-1.0f,-1.0f )); dirLight.setInfluencingBounds( new BoundingSphere( new Point3d( 0.0,0.0,0.0 ),1000.0)); lightGroup.addChild(dirLight); PointLight pLight = new PointLight(new Color3f( 0.9f, 0.9f, 0.9f ), new Point3f( 4.0f, 3.0f, 0.0f ),new Point3f( 1.0f, 0.0f, 2.0f ) ); pLight.setInfluencingBounds( new BoundingSphere( new Point3d( 0.0, 0.0, 0.0 ), 1000.0 ) ); lightGroup.addChild( pLight );
For the planets, I had to create 3 Transform Groups which were children of each other.
TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); objRoot.addChild(objTrans); TransformGroup planet = new TransformGroup(); planet.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); planet.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); objTrans.addChild(planet); TransformGroup shape = new TransformGroup(); shape.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); shape.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); planet.addChild(shape);
For the background, I created a sphere with an image of stars attached which then would move with the scene.
Background bg = new Background(); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); bg.setApplicationBounds(bounds); BranchGroup background = new BranchGroup(); Sphere sphere = new Sphere(1.0f, Sphere.GENERATE_NORMALS | Sphere.GENERATE_NORMALS_INWARD | Sphere.GENERATE_TEXTURE_COORDS, 45);
Appearance backgroundApp = sphere.getAppearance(); background.addChild(sphere); bg.setGeometry(background); objTrans.addChild(bg); Texture tex = new TextureLoader(”background.jpg”, this).getTexture(); backgroundApp.setTexture(tex); TextureAttributes texAttr = new TextureAttributes(); texAttr.setTextureMode(TextureAttributes.MODULATE); backgroundApp.setTextureAttributes(texAttr);
To render the polygon’s in each sphere, I used the POLYGON_FILL command.
PolygonAttributes polygon = new PolygonAttributes( ); polygon.setPolygonMode( polygon.POLYGON_FILL );
The sun was placed at the origin. I created 1 Transform Group.
TransformGroup sun = new TransformGroup(); sun.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); sun.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); shape.addChild(sun);
For the texture of the sun, I set the following values:
Material sunmat = new Material( ); sunmat.setAmbientColor(1.00f, 1.00f, 1.00f); sunmat.setEmissiveColor(0.00f, 0.00f, 0.00f ); sunmat.setDiffuseColor(1.00f, 1.00f, 1.00f); sunmat.setSpecularColor(1.00f, 1.00f, 1.00f ); sunmat.setShininess(75.0f); sunmat.setLightingEnable(true); Appearance sunapp = new Appearance( ); sunapp.setMaterial( sunmat ); sunapp.setPolygonAttributes( polygon );
Texture suntex = new TextureLoader(”sun.jpg”, this).getTexture(); sunapp.setTexture(suntex); TextureAttributes suntexAttr = new TextureAttributes(); suntexAttr.setTextureMode(TextureAttributes.MODULATE); sunapp.setTextureAttributes(suntexAttr);
This set the size of the sun. SunSphere is a child of sun.
Sphere sunsphere = new Sphere(0.22f, Sphere.GENERATE_TEXTURE_COORDS,50, sunapp); sun.addChild(sunsphere);
The sun needed to spin on its own. The rotation interpolator was used for this.
Alpha sunAlpha = new Alpha (-1,18000); Transform3D sunRotate = new Transform3D();
sunRotate.setTranslation(new Vector3f(0f,0f,0f)); sun.setTransform(sunRotate); RotationInterpolator suninterpolator = new RotationInterpolator( sunAlpha, sunTrans, sunRotate,(float)Math.PI*2.0f, 0.0f);
BoundingSphere sunbounds = new BoundingSphere(new Point3d(), 100.0); suninterpolator.setSchedulingBounds(sunbounds); sun.addChild(suninterpolator);
The rest of the planets were similar except for the earth and the moon. For the earth, I included sound. This simulated the motion and direction by modifying the volume and the left/right balance of the sound.
I had to create 4 Transform Groups, for the earth itself, the effects, the orbit and it spinning on its own axis. The rotation and spin were children of earth while earth and earthTrans were children of shape and planet respectively.
//earth TransformGroup earth = new TransformGroup(); earth.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); earth.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); shape.addChild(earth);
TransformGroup earthTrans = new TransformGroup(); earthTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); earthTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); planet.addChild(earthTrans);
TransformGroup earthOrbit = new TransformGroup(); earthOrbit.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); earthOrbit.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); earth.addChild(earthOrbit);
TransformGroup earthRotate = new TransformGroup(); earthRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); earthRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); earth.addChild(earthRotate);
This sets the position of the earth.
Transform3D posearth= new Transform3D(); posearth.setTranslation(new Vector3f(0.38f,0.0f,-0.38f)); earthTrans.setTransform(posearth);
This sets the texture of the earth.
Material earthmat = new Material( ); earthmat.setDiffuseColor(1.0f, 1.0f, 1.00f); earthmat.setSpecularColor(1.0f, 1.0f, 1.00f ); earthmat.setShininess(70.0f); earthmat.setLightingEnable(true);
Appearance earthapp = new Appearance( ); earthapp.setMaterial( earthmat ); earthapp.setPolygonAttributes( polygon ); Texture earthtex = new TextureLoader(”earth.jpg”, this).getTexture(); earthapp.setTexture(earthtex);
TextureAttributes earthtexAttr = new TextureAttributes(); earthtexAttr.setTextureMode(TextureAttributes.MODULATE); earthapp.setTextureAttributes(earthtexAttr);
This sets the size of the earth.
Sphere earthsphere = new Sphere(0.009f, Sphere.GENERATE_TEXTURE_COORDS,50, earthapp); earth.addChild(earthsphere);
Transform3D moveearth= new Transform3D(); moveearth.setTranslation (new Vector3f (0.38f, 0.0f, -0.38f)); earth.setTransform(moveearth); Transform3D rotateearth= new Transform3D(); rotateearth.setTranslation (new Vector3f (-0.38f, 0.0f, 0.38f)); earthRotate.setTransform(rotateearth); earthTrans.addChild(earthsphere);
I had to include 2 rotation interpolators, 1 for the orbit around the sun and the other for spinning on its own axis.
Alpha earthRotationAlpha = new Alpha(-1, 30000); Alpha earthRotationAlpha1 = new Alpha(-1, 365); RotationInterpolator earthRotator =new RotationInterpolator( earthRotationAlpha, earthRotate, rotateearth, 0.0f, (float) Math.PI*2.0f); earthRotator.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0)); earthOrbit.addChild(earthRotator); RotationInterpolator earthRotator1 =new RotationInterpolator(earthRotationAlpha1, earthTrans); earthRotator1.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0)); earthTrans.addChild(earthRotator1);
This is the only difference from the other planets. This creates a point sound for earth.
MediaContainer earthcontainer = new MediaContainer(”file:///c:/temp/graphics/spaceman.wav”); PointSound earthpointSound = new PointSound(); BoundingSphere earthbounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); earthpointSound.setSchedulingBounds(earthbounds); earthpointSound.setSoundData(earthcontainer); earthpointSound.setLoop(Sound.INFINITE_LOOPS); earthpointSound.setPosition(0.38f, 0.0f, 0.0f); earthpointSound.setEnable( true );
This controls the volume and the balance for the sound.
Point2f[] earthdistGain = new Point2f[2]; earthdistGain[0] = new Point2f(0.0f, 3.0f); earthdistGain[1] = new Point2f(3.0f, 0.0f); earthpointSound.setDistanceGain(earthdistGain); earthTrans.addChild(earthpointSound);
For the moon, I had to make it rotate around the earth. I did this by making the moon a child of earthRotate.
TransformGroup moon = new TransformGroup(); moon.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); moon.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); earthRotate.addChild(moon);
Excluding the sun, with these 2 exceptions the planets were similar to each other.
Finally, I created interaction with the mouse. This was done as follows:
This creates user interaction behavior.
MouseRotate rotate = new MouseRotate(); rotate.setTransformGroup(objTrans); objTrans.addChild(rotate); rotate.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0));
This creates the zoom behavior node.
MouseZoom zoom = new MouseZoom(); zoom.setTransformGroup(objTrans); objTrans.addChild(zoom); zoom.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0));
This creates the translate behavior node.
MouseTranslate translate = new MouseTranslate(); translate.setTransformGroup(objTrans); objTrans.addChild(translate); translate.setSchedulingBounds(new BoundingSphere(new Point3d(), 1000.0));
To perform optimizations on the scene graph:
objRoot.compile(); return objRoot; } }
References:
http://www.exploratorium.edu/ronh/solar_system/
http://www.lucid-cake.net/solsys/SolarSystem.html
http://www.nationalgeographic.com/solarsystem/ax/high.html
This is a very simple drawing applet in Java. The left hand side of the applet has a Canvas and the right hand side of the applet has buttons to allow you to choose to draw lines, squares or circles. The source code is detailed beneath.
import java.awt.*; import java.awt.event.*; import java.applet.*; public class PaintApplet extends Applet { //declaring the buttons private Button line; private Button square; private Button circle; private Panel panel; private Canvas canvas; //initialise the applet public void init() { setLayout(new BorderLayout()); //name of buttons line = new Button("LINE"); square = new Button("SQUARE"); circle = new Button("CIRCLE"); //activating the buttons line.addActionListener(new PaintButtonListener()); square.addActionListener(new PaintButtonListener()); circle.addActionListener(new PaintButtonListener()); //setting colour of canvas canvas = new Canvas(); canvas.setBackground(new Color(255, 255, 255)); canvas.setForeground(new Color(0, 0, 0)); //setting panel panel = new Panel(new GridLayout(3, 1)); panel.add(line); panel.add(square); panel.add(circle); add(panel, "East"); add(canvas, "Center"); } //display the applet public void paint(Graphics g) { } private class PaintButtonListener implements ActionListener { private LineMouseListener ll = new LineMouseListener(); private SquareMouseListener sl = new SquareListener(); private CircleMouseListener cl = new CircleListener(); public void actionPerformed(ActionEvent event) { //line condition if(event.getSource() == line) { if(setCircle ==true) { setCircle = false; } if(setSquare == true) { setSquare = false; } setLine = true; canvas.addMouseListener(ll); } //square condition else if(event.getSource() == square) { if(setCircle ==true) { setCircle = false; } if(setline == true) { setLine = false; } setSquare = true; canvas.addMouseListener(sl); canvas.addMouseListener(new SquareMouseListener()); //circle condition if(event.getSource() == circle) { if(setSquare ==true) { setSquare = false; } if(setLine == true) { setLine = false; } } } //line drawing private class LineMouseListener implements MouseListener { //initialise line private int startX = 0; private int startY = 0; private int endX = 0; private int endY = 0; public void mousePressed(MouseEvent e) { //start point if(setLine == true) { startX = e.getX(); startY = e.getY(); } } public void mouseReleased(MouseEvent e) { //end point if(setline == true) { endX = e.getX(); endY = e.getY(); } //Setting the colour Graphics g = canvas.getGraphics(); g.setColor(new Color(125, 0, 0)); g.drawLine(startX, startY, endX, endY); repaint(); } //these must be included public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } } //square drawing private class SquareMouseListener implements MouseListener { //initialise square private int startX = 0; private int startY = 0; private int endx = 0; private int endy = 0; private int width = 0; private int height = 0; public void mousePressed(MouseEvent e) { //start point if(setSquare == true) { startX = e.getX(); starty = e.gety(); } } public void mouseReleased(MouseEvent e) { //end point endx = e.getx(); endY = e.getY(); //get absolute value width = Math.abs(startX - e.getX()); height = Math.abs(startY - e.getY()); //setting the colour Graphics g = canvas.getGraphics(); g.setColor(new Color(0, 50, 100)); g.drawRect(startX, startY, width, height); repaint(); } //these must be included public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } } //circle drawing private class CircleMouseListener implements MouseListener { //initialise circle private int startx = 0; private int starty = 0; private int endx = 0; private int endy = 0; private int width = 0; private int height = 0; public void mousePressed(MouseEvent e) { //start point if(setCircle == true) { StartX = e.getX(); StartY = e.getY(); } } public void mouseReleased(MouseEvent e) { //end point endx = e.getx(); endy = e.gety(); width = Math.abs(startx - e.getx()); height = Math.abs(starty - e.gety()); //setting the colour Graphics g = canvas.getGraphics(); g.setColor(new Color(0, 50, 0)); g.drawOval(startx, starty, width, height); repaint(); } //these must be included public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } } }
Develop a two NeatVision programs capable of automatically counting the number of lines in the grey scale image lines.gif in a robust manner. What are the advantages and disadvantages of each approach?
A.
Using a threshold of 100, the image is converted to binary.
The image is passed through an erode loop twice to thin the lines making it easier for the limb end detector.
The limb end detector marks the ends of each line. Each line has 2 points.
The white blob counter counts the limb ends. The mathsdivide operator divides the number of points by 2, giving the final result of 5, which is the correct number of lines.
B.
Using a threshold of 100, the image is converted to binary. Hough transform will only work with a binary image.
The Hough Transform is used to segment and detect the number of lines.
Using a threshold of 100, the image is converted to binary again.
The image is eroded 5 times, to remove the excess data and dilated once. Whiteblobcount is used to count the lines.
Chapter 2 – Testing
A.
Salt and Pepper Noise :
The maximum threshold of Salt and Pepper Noise is 0.0001.
B.
Salt and Pepper Noise :
The system is not robust to any Salt and Pepper Noise. Testing ceased at 0.000001.
A.
Gaussian Noise :
The maximum threshold of Gaussian Noise is 0.8.
B.
Gaussian Noise :
The maximum threshold of Gaussian Noise is 1.3.
A.
Raleigh Noise :
The maximum threshold of Raleigh Noise is 26.
B.
Raleigh Noise :
The maximum threshold of Raleigh Noise is 17.7.
A.
Poisson Noise :
The maximum threshold of Poisson Noise is 27.
B.
Poisson Noise :
The maximum threshold of Poisson Noise is 16.0.
A.
Additive White Noise :
This system is not robust to additive noise.
B.
Additive White Noise :
This system is not robust to additive noise.
Robustness to Scaled Images :
The original image is 256 x 256. The height and width were increased or decreased depending on the purpose.
A.
Minumum Scaled Threshold :
The image was scaled down but would not function. The minimum threshold is the same size as the original.
B.
Minumum Scaled Threshold :
The image was scaled down but would not function. The minimum threshold is the same size as the original.
A.
Maximum Scaled Threshold :
The maximum threshold is 260 x 260
B.
Maximum Scaled Threshold :
The image was scaled up but would not function. The maximum threshold is the same size as the original.
Distorting Width
A.
Minimum Width Threshold :
The minimum threshold of the width is 254.
B.
Minimum Width Threshold :
The width of the image was decreased but would not function. The minimum threshold is the same size as the original.
A.
Maximum Width Threshold :
The maximum width is 263.
B.
Maximum Width Threshold
The maximum threshold of the width is 274.
Distorting Height
A.
Maximum Height Threshold :
The maximum height was 263.
B.
Maximum Height Threshold :
The height of the image was increased but would not function. The maximum threshold is the same size as the original.
A.
Minimum height Threshold :
The height of the image was decreased but would not function. The minimum threshold is the same size as the original.
B.
Minimum height Threshold :
The height of the image was decreased but would not function. The minimum threshold is the same size as the original.
A.
Robustness to Image Rotation:
This system was not robust to any rotational changes.
B.
Robustness to Image Rotation
The system would only function at 0 and 180 degrees.
A.
Robustness to another image
Bcode2 was tried but the system failed.
B.
Robustness to another image
Bcode2 was tried but the system failed.
Bibliography
A. Machine Vision Algorithms in Java, Paul F. Whelan and Derek Molloy.
References
1. http://www.eeng.dcu.ie/%7Ewhelanp/EE425/protected_material/, EE425 Course Notes, Colour Image Analysis
2. www.neatvision.com, NeatVision Developers Guide
The .pdf version of this report is available below.