Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Chapter 4: Graphics Programming
with Java 2D and Java 3D
Outline
4.1
4.2
4.3
4.4
4.5
Introduction
Coordinates, Graphics Contexts and Graphics Objects
Java 2D API
4.3.1
Java 2D Shapes
4.3.2
Java 2D Image Processing
Java 3D API
4.4.1
Obtaining and Installing the Java 3D API
4.4.2
Java 3D Scenes
4.4.3
A Java 3D Example
A Java 3D Case Study: A 3D Game with Custom Behaviors
2002 Prentice Hall. All rights reserved.
4.1 Introduction
• Java 2D
– APIs for 2D graphics
• Drawing
• Coloring
• Image manipulation
• Java 3D
– APIs for 3D graphics
• 3D object manipulation
• Lighting
• Texture mapping
2002 Prentice Hall. All rights reserved.
4.2 Coordinates, Graphics Contexts and
Graphics Objects
• Java 2D coordinate system
– Scheme for identifying every point on screen
• Upper left corner of GUI component has coordinates (0,0)
• Java graphics context
– Enables drawing on screen
• e.g., font and color manipulation
– Graphics object manages a graphics context
• abstract class for portability
2002 Prentice Hall. All rights reserved.
4.2 Coordinates, Graphics Contexts and
Graphics Objects (cont.)
(0, 0)
+x
x-Axis
(x, y)
+y
y -Axis
Fig. 4.1
Java coordinate system. Units are measured in pixels.
2002 Prentice Hall. All rights reserved.
4.3 Java 2D API
• Java 2D API
–
–
–
–
Provides advanced 2D graphics capabilities
Part of the Java 2 Platform, Standard Edition
Includes features for processing line art, text and images
Class java.awt.Graphics2D
• Enables drawing with Java 2D API
• Offers three graphics primitives: images, text and shapes
• java.awt.Graphics subclass
• Contains seven state attributes
– Clipping, compositing, font, paint, rendering hints, stroke
and transforms
2002 Prentice Hall. All rights reserved.
4.3 Java 2D API (cont.)
Cla ss/ Interfa c e
Classes and interfaces
from package
java.awt
Graphics2D
BasicStroke
GradientPaint
TexturePaint
Paint
Shape
Stroke
Classes and interfaces
from package
java.awt.geom
GeneralPath
Desc rip tio n
Graphics subclass for rendering 2D shapes, text and images.
Defines a basic set of rendering attributes for the outlines of
graphics primitives.
Provides a way to fill and outline 2D shapes with a linear color
gradient.
Provides a way to fill and outline shapes with texture images.
Defines how color patterns can be generated for rendering
operations.
Provides definitions for geometrical objects.
Provides methods for obtaining the outline of a geometrical
shape.
Represents a path constructed from straight lines, quadratic
curves and cubic curves.
Line2D
Represents a line in coordinate space.
RectangularShape Base class for geometrical shapes with rectangular frames.
Subclasses include Arc2D, Ellipse2D, Rectangle2D and
RoundRectangle2D.
BufferedImage
Describes an Image with a buffer of colored pixel data
composed of a ColorModel and a Raster.
ColorModel
Defines methods for translating a numerical pixel value to a
color.
Classes and interfaces
from package
java.awt.image
Raster
Is part of a BufferedImage that describes sample values in a
rectangular array of pixels.
Kernel
Describes a 2D array used for filtering BufferedImages.
BufferedImageOp Defines methods that perform operations on BufferedImages
(e.g. blurring a BufferedImage)
RasterOp
Describes single-input/single-output processes performed on
Rasters.
Fig. 4.2 So m e Ja va 2D c la sses a nd interfa c es.
2002 Prentice Hall. All rights reserved.
4.3 Java 2D API (cont.)
Attrib ute
Clipping
Compositing
Font
Paint
Rendering Hints
Stroke
De sc rip tio n
Defines the area in which rendering operations take effect. Any
geometrical shape, including text, can be used as a clipping region.
Is a Set of blending rules that control how the pixels in a source image
mix with the pixels in a destination image.
Fonts are created from shapes that represent the characters to be
drawn—called glyphs. Text is rendered by drawing and filling the
glyphs.
Determines the colors, patterns and gradients for filling and outlining
a shape.
Specify techniques and methods that help to optimize drawing.
Determines the outline of the shape to be drawn.
Transform
Defines ways to perform linear transformations—an operation that
changes the shape of an image.
Fig. 4.3 The se ve n sta te a ttrib ute s o f a Ja va 2D g ra p hic s c o nte xt.
2002 Prentice Hall. All rights reserved.
4.3.1 Java 2D Shapes
• Java 2D shape classes
– Package java.awt.geom
• Ellipse2D.Double
• Line2D.Double
• Rectangle2D.Double
• RoundRectangle2D.Double
• Arc2D.Double
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Outline
// Shapes.java
// Shapes demonstrates some Java 2D shapes.
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
// Java extension packages
import javax.swing.*;
Fig. 4.4
Demonstrating some
Java 2D shapes
Class Shapes demonstrates
several
(part 1).
Java 2D shapes and rendering attributes
Line 13
public class Shapes extends JFrame {
Line 28
// constructor method
public Shapes()
{
super( "Drawing 2D shapes" );
}
// draw shapes using Java 2D API
public void paint( Graphics g )
{
// call superclass' paint method
super.paint( g );
Lines 31-32
Lines 33
Cast Graphics object to
Graphics2D object to allow
access to Java 2D features
// get Graphics 2D by casting g to Graphics2D
Graphics2D graphics2D = ( Graphics2D ) g;
// draw 2D ellipse filled with blue-yellow gradient
graphics2D.setPaint( new GradientPaint
( 5, 30, Color.blue, 35, 100, Color.yellow, true ) );
graphics2D.fill( new Ellipse2D.Double( 5, 30, 65, 100 ) );
GradientPaint
displays a gradient color
Draw a filled ellipse
2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// draw 2D rectangle in red
graphics2D.setPaint( Color.red );
graphics2D.setStroke( new BasicStroke( 10.0f ) );
graphics2D.draw(
new Rectangle2D.Double( 80, 30, 65, 100 ) );
// draw 2D rounded rectangle with BufferedImage background
BufferedImage bufferedImage = new BufferedImage(
10, 10, BufferedImage.TYPE_INT_RGB );
Graphics2D graphics = bufferedImage.createGraphics();
graphics.setColor( Color.yellow ); // draw in yellow
graphics.fillRect( 0, 0, 10, 10 ); // draw filled rectangle
graphics.setColor( Color.black ); // draw in black
graphics.drawRect( 1, 1, 6, 6 );
// draw rectangle
graphics.setColor( Color.blue );
// draw in blue
graphics.fillRect( 1, 1, 3, 3 );
// draw filled rectangle
graphics.setColor( Color.red );
// draw in red
graphics.fillRect( 4, 4, 3, 3 );
// draw filled rectangle
// paint buffImage into graphics context of JFrame
graphics2D.setPaint( new TexturePaint(
bufferedImage, new Rectangle( 10, 10 ) ) );
graphics2D.fill( new RoundRectangle2D.Double(
155, 30, 75, 100, 50, 50 ) );
// draw 2D pie-shaped arc in white
graphics2D.setPaint( Color.white );
graphics2D.setStroke( new BasicStroke( 6.0f ) );
graphics2D.draw( new Arc2D.Double(
240, 30, 75, 100, 0, 270, Arc2D.PIE ) );
// draw 2D lines in green and yellow
graphics2D.setPaint( Color.green );
graphics2D.draw( new Line2D.Double( 395, 30, 320, 150 ) );
Outline
Draw hollow rectangle
with thick red border
Fig. 4.4
Demonstrating some
Java a2D
shapes
Create
Buffered(part
2). which will
Image,
serve as a pattern for a
Lines
36-39
rounded
rectangle
Lines 42-53
Lines 56-59
Lines 62-65
Use the BufferedImage to create the
pattern-filled rounded
rectangle
Draw hollow arc with
thick white border
2002 Prentice Hall.
All rights reserved.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
float dashes[] = { 10, 2 };
graphics2D.setPaint( Color.yellow );
graphics2D.setStroke( new BasicStroke(
4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
10, dashes, 0 ) );
graphics2D.draw( new Line2D.Double( 320, 30, 395, 150 ) );
Outline
DrawFig.
yellow
4.4dashed line
Demonstrating some
Java 2D shapes
(part 3).
} // end method paint
// start application
public static void main( String args[] )
{
Shapes application = new Shapes();
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
Lines 73-77
application.setSize( 425, 160 );
application.setVisible( true );
}
}
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Outline
// Shapes2.java
// Shapes2 demonstrates a general path.
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
// Java extension packages
import javax.swing.*;
4.5
Class Shapes2Fig.
demonstrates
Demonstrating
using a general path
– a shape Java
2D lines
pathsand
(part 1).
constructed from
complex curves – to draw a start
Line 12
public class Shapes2 extends JFrame {
Lines 29-32
// set window's title bar String and background color
public Shapes2()
{
super( "Drawing 2D Shapes" );
getContentPane().setBackground( Color.gray );
}
// draw general paths
public void paint( Graphics g )
{
// call superclass' paint method
super.paint( g );
int xPoints[] =
{ 55, 67, 109, 73, 83, 55, 27, 37, 1, 43 };
int yPoints[] =
{ 0, 36, 36, 54, 96, 72, 96, 54, 36, 36 };
Graphics2D graphics2D = ( Graphics2D ) g;
Define two int array
representing the x- and
y-coordinates of the
points in the star
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
// create a star from a series of points
GeneralPath star = new GeneralPath();
Method
specifies
Fig.moveTo
4.5
the Demonstrating
first point in the star
Java
// set the initial coordinate of the General Path
star.moveTo( xPoints[ 0 ], yPoints[ 0 ] );
// create the star--this does not draw the star
for ( int count = 1; count < xPoints.length; count++ )
star.lineTo( xPoints[ count ], yPoints[ count ] );
// close the shape
star.closePath();
2D paths (part 2).
Line 40
Method lineTo draws a line
to the next
point43-44
in the star
Lines
// translate the origin to (200, 200)
graphics2D.translate( 200, 200 );
Lines 53-65
// rotate around origin and draw stars in random colors
for ( int count = 1; count <= 20; count++ ) {
// rotate coordinate system
graphics2D.rotate( Math.PI / 10.0 );
// set random drawing color
graphics2D.setColor( new Color(
( int ) ( Math.random() * 256 ),
( int ) ( Math.random() * 256 ),
( int ) ( Math.random() * 256 ) ) );
Draw several stars
// draw filled star
graphics2D.fill( star );
}
}
// end method paint
// execute application
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
public static void main( String args[] )
{
Shapes2 application = new Shapes2();
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.setSize( 400, 400 );
application.setVisible( true );
}
Outline
Fig. 4.5
Demonstrating Java
2D paths (part 3).
}
2002 Prentice Hall.
All rights reserved.
4.3.2 Java 2D Image Processing
• Image processing
– Manipulation of digital images by applying filters
• Filters – mathematical operations that change images
– Compression filters
• Reduce digital image’s memory usage
– Measurement filters
• Collect data from digital images
– Enhancement filters
• Alter certain physical aspects of an image
• Java 2D image processing
– Use java.awt.BufferedImage
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ImagePanel.java
// ImagePanel contains an image for display. The image is
// converted to a BufferedImage for filtering purposes.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
Outline
Fig. 4.6 Class
ImagePanel allows
for displaying and
filtering BufferedImages (part 1).
Line 23
Line 34
public class ImagePanel extends JPanel {
private BufferedImage displayImage; // filtered image
private BufferedImage originalImage; // original image
private Image image; // image to load
// ImagePanel constructor
Constructor takes a URL that specifies
public ImagePanel( URL imageURL )
the file containing the image to filter
{
image =
Toolkit.getDefaultToolkit().createImage( imageURL );
// create MediaTracker for image
MediaTracker mediaTracker = new MediaTracker( this );
mediaTracker.addImage( image, 0 );
// wait for Image to load
try {
mediaTracker.waitForAll();
}
Load image from URL into memory
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
// exit program on error
catch ( InterruptedException interruptedException ) {
interruptedException.printStackTrace();
}
// create BufferedImages from Image
originalImage = new BufferedImage( image.getWidth( null ),
image.getHeight( null ), BufferedImage.TYPE_INT_RGB );
displayImage = originalImage;
// get BufferedImage’s graphics context
Graphics2D graphics = displayImage.createGraphics();
graphics.drawImage( image, null, null );
Create BufferedImage
to store the original
Fig. 4.6 Class
(unaltered) image
ImagePanel allows
for displaying and
filtering BufferedBufferedImage
Images (part 2).
displayImage is
the image that will
Lines
43-44
be modified
Line 46
} // end ImagePanel constructor
// apply Java2DImageFilter to Image
public void applyFilter( Java2DImageFilter filter )
{
// process Image using Java2DImageFilter
displayImage = filter.processImage( displayImage );
repaint();
}
Lines 55-60
Apply filter to
displayImage
Lines 65-66
Replaces displayImage with
original BufferedImage
// set Image to originalImage
public void displayOriginalImage()
{
displayImage = new BufferedImage( image.getWidth( null ),
image.getHeight( null ), BufferedImage.TYPE_INT_RGB );
Graphics2D graphics = displayImage.createGraphics();
graphics.drawImage( originalImage, null, null );
repaint();
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}
// draw ImagePanel
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D graphics = ( Graphics2D ) g;
graphics.drawImage( displayImage, 0, 0, null );
}
// get preferred ImagePanel size
public Dimension getPreferredSize()
{
return new Dimension( displayImage.getWidth(),
displayImage.getHeight() );
}
Outline
Fig. 4.6 Class
ImagePanel allows
for displaying and
Draw displayImage on screen
filtering BufferedImages (part 3).
Line 78
// get minimum ImagePanel size
public Dimension getMinimumSize()
{
return getPreferredSize();
}
}
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Java2DImageFilter.java
// Java2DImageFilter is an interface that defines method
// processImage for applying a filter to an Image.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.*;
import java.awt.image.*;
Outline
Fig. 4.6 Java2DImageFilter
interface for creating
Java 2D image filters.
public interface Java2DImageFilter {
// apply filter to Image
public BufferedImage processImage( BufferedImage image );
Line 13
}
Method processImage accepts a
BufferedImage to filter and returns
the filtered BufferedImage
2002 Prentice Hall.
All rights reserved.
4.3.2 Java 2D Image Processing (cont.)
C la ss
Im p le m e nts
Inte rfa c e s
AffineTransformOp BufferedImageOp
RasterOp
De sc rip tio n
Performs linear mapping from 2D
coordinates in the source image to 2D
coordinates in the destination image.
(Example: Rotate an image about a
point in the image.)
BandCombineOp
RasterOp
Performs a linear combination of the
bands in a Raster. (Example:
Change the color palette in an image.)
ColorConvertOp
BufferedImageOp
Performs color conversion on each
RasterOp
pixel in the source image. (Example:
Convert from RGB color to gray
scale.)
ConvolveOp
BufferedImageOp
Combines source pixel values with
RasterOp
surrounding pixel values to derive
destination pixel values. (Example:
Sharpen edges in an image.)
LookupOp
BufferedImageOp
Performs a lookup operation on the
RasterOp
source image to create the destination
image. (Example: Invert the RGB
colors in an image.)
RescaleOp
BufferedImageOp
Rescale the data in the source image
RescaleOp
by a scalar plus offset. (Example:
Darken the coloring of an image.)
Fig. 4.8 C la sse s tha t im p le m e nt BufferedImageOp a nd RasterOp.
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// InvertFilter.java
// InvertFilter, which implements Java2DImageFilter, inverts a
// BufferedImage's RGB color values.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.image.*;
public class InvertFilter implements Java2DImageFilter {
// apply color inversion filter to BufferedImage
public BufferedImage processImage( BufferedImage image )
{
// create 256 color array and invert colors
byte[] invertArray = new byte[ 256 ];
Outline
Fig. 4.9
InvertFilter
inverts colors in a
BufferedImage.
Lines 21-22
for ( int counter = 0; counter < 256; counter++ )
invertArray[ counter ] = ( byte )( 255 - counter );
// create filter to invert colors
BufferedImageOp invertFilter = new LookupOp(
new ByteLookupTable( 0, invertArray ), null );
Use LookupOp (an array
indexed by source pixel color
values) to invert colors
// apply filter to displayImage
return invertFilter.filter( image, null );
} // end method processImage
}
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// SharpenFilter.java
// SharpenFilter, which implements Java2DImageFilter, sharpens
// the edges in a BufferedImage.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.image.*;
public class SharpenFilter implements Java2DImageFilter {
Outline
Fig. 4.10
SharpenFilter
sharpens edges in a
BufferedImage.
// apply edge-sharpening filter to BufferedImage
Lines 21-22
public BufferedImage processImage( BufferedImage image )
{
// array used to detect edges in image
float[] sharpenMatrix = {
Use ConvolveOp (which
0.0f, -1.0f, 0.0f,
-1.0f, 5.0f, -1.0f,
combines the colors of a source
0.0f, -1.0f, 0.0f };
// create filter to sharpen edges
BufferedImageOp sharpenFilter =
new ConvolveOp( new Kernel( 3, 3, sharpenMatrix ),
ConvolveOp.EDGE_NO_OP, null );
pixel and its surrounding
neighbors) to sharpen edges
// apply sharpenFilter to displayImage
return sharpenFilter.filter( image, null );
} // end method processImage
}
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// BlurFilter.java
// Blurfilter blurs a BufferedImage.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.image.*;
public class BlurFilter implements Java2DImageFilter {
// apply blurring filter to BufferedImage
public BufferedImage processImage( BufferedImage image )
{
// array used to blur BufferedImage
float[] blurMatrix = {
1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f,
1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f,
1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f };
// create ConvolveOp for blurring BufferedImage
BufferedImageOp blurFilter = new ConvolveOp(
new Kernel( 3, 3, blurMatrix ) );
Outline
Fig. 4.11
BlurFilter blurs
the colors in a
BufferedImage.
Lines 20-21
Use ConvolveOp
to blur edges
// apply blurFilter to BufferedImage
return blurFilter.filter( image, null );
} // end method processImage
}
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ColorFilter.java
// ColorFilter is an Java2DImageFilter that alters the RGB
// color bands in a BufferedImage.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.image.*;
public class ColorFilter implements Java2DImageFilter {
Outline
Fig. 4.12
ColorFilter
changes the colors in
a BufferedImage
(part 1).
// apply color-change filter to BufferedImage
public BufferedImage processImage( BufferedImage image )
Lines 21-22
{
// create array used to change RGB color bands
float[][] colorMatrix = {
Line 25 (which
Use BandCombineOp
{ 1.0f, 0.0f, 0.0f },
{ 0.5f, 1.0f, 0.5f },
operates on the color bands of a
{ 0.2f, 0.4f, 0.6f } };
Raster) to alter colors
// create filter to change colors
BandCombineOp changeColors =
new BandCombineOp( colorMatrix, null );
// create source and display Rasters
Raster sourceRaster = image.getRaster();
WritableRaster displayRaster =
sourceRaster.createCompatibleWritableRaster();
Raster organizes and
stores the samples that
determine the pixel colors
in the BufferedImage
// filter Rasters with changeColors filter
changeColors.filter( sourceRaster, displayRaster );
// create new BufferedImage from display Raster
return new BufferedImage( image.getColorModel(),
displayRaster, true, null );
2002 Prentice Hall.
All rights reserved.
36
37
38
} // end method processImage
Outline
}
Fig. 4.12
ColorFilter
changes the colors in
a BufferedImage
(part 2).
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Java2DExample.java
// Java2DExample is an application that applies filters to an
// image using Java 2D.
package com.deitel.advjhtp1.java2d;
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.lang.*;
import java.net.*;
Outline
Fig. 4.13 Java 2D
image-processing
application GUI
(part 1).
Class Java2DExample provides
Line
a user interface
for17
applying
Java2DImageFilters to
Lines 23-26
ImagePanels
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
public class Java2DExample extends JFrame {
private JMenu filterMenu;
private ImagePanel imagePanel;
// image filters
private Java2DImageFilter
private Java2DImageFilter
private Java2DImageFilter
private Java2DImageFilter
invertFilter;
sharpenFilter;
blurFilter;
colorFilter;
Declared a set of
Java2DImageFilters
// initialize JMenuItems
public Java2DExample()
{
super( "Java 2D Image Processing Demo" );
// create Java2DImageFilters
blurFilter = new BlurFilter();
sharpenFilter = new SharpenFilter();
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
invertFilter = new InvertFilter();
colorFilter = new ColorFilter();
// initialize ImagePanel
imagePanel = new ImagePanel(
Java2DExample.class.getResource( "images/ajhtp.png" ) );
// create JMenuBar
JMenuBar menuBar = new JMenuBar();
setJMenuBar( menuBar );
Fig. 4.13 Java 2D
image-processing
application GUI
(part 2).
Lines 60-63
// create JMenu
filterMenu = new JMenu( "Image Filters" );
filterMenu.setMnemonic( 'I' );
// create JMenuItem for displaying original Image
JMenuItem originalMenuItem =
new JMenuItem( "Display Original" );
originalMenuItem.setMnemonic( 'O' );
originalMenuItem.addActionListener(
new ActionListener() {
Provide mechanism for displaying
the original (unaltered) image
// show original Image
public void actionPerformed( ActionEvent action )
{
imagePanel.displayOriginalImage();
}
} // end anonymous inner class
);
// create JMenuItems for Java2DImageFilters
JMenuItem invertMenuItem = createMenuItem(
"Invert", 'I', invertFilter );
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
Outline
JMenuItem sharpenMenuItem = createMenuItem(
"Sharpen", 'S', sharpenFilter );
JMenuItem blurMenuItem = createMenuItem(
"Blur", 'B', blurFilter );
JMenuItem changeColorsMenuItem = createMenuItem(
"Change Colors", 'C', colorFilter );
// add JMenuItems to JMenu
filterMenu.add( originalMenuItem );
filterMenu.add( invertMenuItem );
filterMenu.add( sharpenMenuItem );
filterMenu.add( blurMenuItem );
filterMenu.add( changeColorsMenuItem );
Fig. 4.13 Java 2D
image-processing
application GUI
(part 3).
Create menus for applying
Lines 79-83
filters to ImagePanel
// add JMenu to JMenuBar
menuBar.add( filterMenu );
getContentPane().add( imagePanel, BorderLayout.CENTER );
} // end Java2DExample constructor
// create JMenuItem and ActionListener for given filter
public JMenuItem createMenuItem( String menuItemName,
char mnemonic, final Java2DImageFilter filter )
{
// create JMenuItem
JMenuItem menuItem = new JMenuItem( menuItemName );
// set Mnemonic
menuItem.setMnemonic( mnemonic );
menuItem.addActionListener(
new ActionListener() {
// apply Java2DImageFilter when MenuItem accessed
2002 Prentice Hall.
All rights reserved.
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public void actionPerformed( ActionEvent action )
{
imagePanel.applyFilter( filter );
}
} // end anonymous inner class
);
return menuItem;
Outline
Fig. 4.13 Java 2D
Apply Java2DImageFilter
image-processing
to ImagePanel
application GUI
(part 4).
} // end method createMenuItem
Lines 106-109
// start program
public static void main( String args[] )
{
Java2DExample application = new Java2DExample();
application.setDefaultCloseOperation( EXIT_ON_CLOSE );
application.pack();
application.setVisible( true );
}
}
2002 Prentice Hall.
All rights reserved.
Outline
Fig. 4.13 Java 2D
image-processing
application GUI
(part 5).
Program output
2002 Prentice Hall.
All rights reserved.
4.4 Java 3D API
• Java 3d
– Offers several features for developing 3D applications:
•
•
•
•
•
•
Behavior
Fog
Geometry
Light
Sound
Texture
2002 Prentice Hall. All rights reserved.
4.4.1 Obtaining and Installing the Java 3D
API
• Java 3D API requirements
– J2SDK
– OpenGL or Direct3D
– Java extension and utility packages
• Not integrated in core Java 2 Platform
2002 Prentice Hall. All rights reserved.
4.4.2 Java 3D Scenes
• Scenes
– Pictures rendered with Java 3D
– Also called a virtual universe
• Class VirtualUniverse
– Described by scene graphs
• Hierarchical structures specifying attributes of 3D environment
• Contain branch graphs
2002 Prentice Hall. All rights reserved.
4.4.2 Java 3D Scenes (cont.)
C la ss
Partial list of Java3D
Group classes
BranchGroup
Switch
TransformGroup
De sc rip tio n
A scene-graph’s root Node that attaches to a Locale.
Can render either a single child or a mask of children.
Contains a single transformation (e.g., translation, rotation or
scaling).
Partial list of Java3D
Leaf classes
Behavior
Contains methods for gathering user input (e.g., key presses and
mouse clicks) and describing objects’ behavior upon certain events
(e.g., collisions).
Light
Describes a set of parameters for Java 3D light sources.
Shape3D
Describes 3D-geometric objects.
ViewPlatform
Controls the viewpoint for a 3D scene.
Partial list of Java3D
NodeComponent
classes
Appearance
Specifies Shape3D attributes, such as coloring and texture.
Material
Describes an illuminated object’s properties (e.g., reflective color
and shininess).
Texture
Specifies properties for texture mapping—a technique for drawing
2D images over 3D geometric models.
Fig. 4.14
Ja va 3D Group, Leaf a nd NodeComponent sub c la sse s.
2002 Prentice Hall. All rights reserved.
4.4.3 A Java 3D Example
• Interactive Java 3D scene
– Demonstrate mouse behaviors
• Using mouse to rotate, scale and translate 3D shapes
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Java3DWorld.java
// Java3DWorld is a Java 3D Graphics display environment
// that creates a SimpleUniverse and provides capabilities for
// allowing a user to control lighting, motion, and texture
// of the 3D scene.
package com.deitel.advjhtp1.java3d;
// Java core packages
import java.awt.event.*;
import java.awt.*;
import java.net.*;
// Java extension packages
import javax.swing.event.*;
import javax.media.j3d.*;
import javax.vecmath.*;
// Java 3D utility packages
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.mouse.*;
public class Java3DWorld extends Canvas3D {
private
private
private
private
private
private
private
private
Outline
Fig. 4.15 Creating a
Java 3D
SimpleUniverse
with content (part 1).
Class Java3DWorld creates
Line 1 using
Java 3D environment
geometry, transforms and lighting
Lines 19-22
Line 24
Import Java 3D utility packages
that simplify scene creation
Canvas3D is a java.awt.Canvas
subclass used for 3D rendering
Appearance appearance; // 3D object's appearance
Box shape; // 3D object to manipulate
Color3f lightColor; // Light color
Light ambientLight; // ambient scene lighting
Light directionalLight; //directional light
Material material; // 3D objects color object
SimpleUniverse simpleUniverse; // 3D scene environment
TextureLoader textureLoader; // 3D object's texture
2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Outline
// holds 3D transformation information
private TransformGroup transformGroup;
private String imageName; // texture image file name
// Java3DWorld constructor
public Java3DWorld( String imageFileName )
{
super( SimpleUniverse.getPreferredConfiguration() );
Fig. 4.15 Creating a
Java 3D
SimpleUniverse
with content (part 2).
imageName = imageFileName;
Line 48
// create SimpleUniverse (3D Graphics environment)
simpleUniverse = new SimpleUniverse( this );
Lines 51-54
// set default view point and direction
ViewingPlatform viewPlatform =
simpleUniverse.getViewingPlatform();
SimpleUniverse creates a Java 3D
Line 67
scene and encapsulates all objects in
virtual universe and viewing platform
viewPlatform.setNominalViewingTransform();
// create 3D scene
BranchGroup branchGroup = createScene();
// attach BranchGroup to SimpleUniverse
simpleUniverse.addBranchGraph( branchGroup );
Configure viewing distance
(length between viewer and
canvas) for 3D scene
} // end Java3DWorld constructor
// create 3D scene
public BranchGroup createScene()
{
BranchGroup scene = new BranchGroup();
// initialize TransformGroup
BranchGroup is the root node of
a scene graph in a Java 3D scene
2002 Prentice Hall.
All rights reserved.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
transformGroup = new TransformGroup();
// set TransformGroup's READ and WRITE permission
transformGroup.setCapability(
TransformGroup.ALLOW_TRANSFORM_READ );
transformGroup.setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE );
// add TransformGroup to BranchGroup
scene.addChild( transformGroup );
TransformGroup
specifies
Outline
transformational behavior, such as
rotation, scaling and translation
Fig. 4.15 Creating a
Java 3D
Capability SimpleUniverse
bits are integer flags
that specify whether a given object
with content (part 3).
should allow its properties to be
read or written during execution
Line 70
// create BoundingSphere
BoundingSphere bounds = new BoundingSphere(
new Point3d( 0.0f, 0.0f, 0.0f ), 100.0 );
BoundingSphere creates
Lines 73-77
bounding volume, which
specifies the volume in which
Lines 83-84
appearance = new Appearance(); // create object appearance Lights
and Behaviors
material = new Material(); // create texture matieral
affect geometry in the scene
appearance.setMaterial( material );
Lines 93-94
String rgb = new String( "RGB" );
Load texture for texture mapping
// load texture for scene object
textureLoader = new TextureLoader(
Java3DWorld.class.getResource( imageName ), rgb, this );
// set capability bits for enabling texture
textureLoader.getTexture().setCapability(
Texture.ALLOW_ENABLE_WRITE );
// initial texture will not show
textureLoader.getTexture().setEnable( false );
// set object's texture
appearance.setTexture( textureLoader.getTexture() );
2002 Prentice Hall.
All rights reserved.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// create object geometry
Box shape = new Box( 0.3f, 0.3f, 0.3f,
Box.GENERATE_NORMALS | Box.GENERATE_TEXTURE_COORDS,
appearance );
// add geometry to TransformGroup
transformGroup.addChild( shape );
// initialize Ambient lighting
ambientLight = new AmbientLight();
ambientLight.setInfluencingBounds( bounds );
// initialize directionalLight
directionalLight = new DirectionalLight();
lightColor = new Color3f(); // initialize light color
Outline
Create Box to rotate,
Fig.
scale4.15
and translate
Creating a
Java 3D
SimpleUniverse
AmbientLight
is a
with light
content
(part
uniform
source
that4).
illuminates all objects
Linesits
107-109
within
boundary
Lines 115-116
DirectionalLight is a
light source that travels
Line 119
between two points
// set initial DirectionalLight color
directionalLight.setColor( lightColor );
// set capability bits to allow DirectionalLight's
// Color and Direction to be changed
directionalLight.setCapability(
DirectionalLight.ALLOW_DIRECTION_WRITE );
directionalLight.setCapability(
DirectionalLight.ALLOW_DIRECTION_READ );
directionalLight.setCapability(
DirectionalLight.ALLOW_COLOR_WRITE );
directionalLight.setCapability(
DirectionalLight.ALLOW_COLOR_READ );
2002 Prentice Hall.
All rights reserved.
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
directionalLight.setInfluencingBounds( bounds );
// add light nodes to BranchGroup
scene.addChild( ambientLight );
scene.addChild( directionalLight );
// initialize rotation behavior
MouseRotate rotateBehavior = new MouseRotate();
rotateBehavior.setTransformGroup( transformGroup );
rotateBehavior.setSchedulingBounds( bounds );
// initialize translation behavior
MouseTranslate translateBehavior = new MouseTranslate();
translateBehavior.setTransformGroup( transformGroup );
translateBehavior.setSchedulingBounds(
new BoundingBox( new Point3d( -1.0f, -1.0f, -1.0f ),
new Point3d( 1.0f, 1.0f, 1.0f ) ) );
// initialize scaling behavior
MouseZoom scaleBehavior = new MouseZoom();
scaleBehavior.setTransformGroup( transformGroup );
scaleBehavior.setSchedulingBounds( bounds );
// add behaviors to BranchGroup
scene.addChild( scaleBehavior );
scene.addChild( rotateBehavior );
scene.addChild( translateBehavior );
scene.compile();
return scene;
Outline
Create behavior that
Fig. 4.15
Creating
controls
rotation
of the a
Box
Javavia
3Dthe mouse
SimpleUniverse
with content (part 5).
Lines 147-149
Create behavior that
controls
translation of
Lines 152-156
the Box via the mouse
Lines 159-161
Line 168
Create behavior that
controls scalability of
the Box via the mouse
Compiling a BranchGroup informs
the Java 3D engine to optimize
rendering the scene using the
capability bits set by the developer
} // end method createScene
2002 Prentice Hall.
All rights reserved.
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// change DirectionLight color
public void changeColor( Color color )
{
lightColor.set( color );
directionalLight.setColor( lightColor );
}
// change geometry surface to textured image or material color
public void updateTexture( boolean textureValue )
{
textureLoader.getTexture().setEnable( textureValue );
}
Outline
Fig. 4.15 Creating a
Java 3D
SimpleUniverse
with content (part 6).
// change image used for texture
public void setImageName( String imageFileName )
{
imageName = imageFileName;
}
// get image file name
public String getImageName()
{
return imageName;
}
// return preferred dimensions of Container
public Dimension getPreferredSize()
{
return new Dimension( 500, 500 );
}
// return minimum size of Container
public Dimension getMinimumSize()
{
2002 Prentice Hall.
All rights reserved.
208
209
210
return getPreferredSize();
}
Outline
}
Fig. 4.15 Creating a
Java 3D
SimpleUniverse
with content (part 7).
2002 Prentice Hall.
All rights reserved.
4.4.3 A Java 3D Example (cont.)
Fig. 4.16 Demonstrating MouseRotate behavior.
2002 Prentice Hall. All rights reserved.
4.4.3 A Java 3D Example (cont.)
Fig. 4.17 Demonstrating MouseTranslate behavior.
2002 Prentice Hall. All rights reserved.
4.4.3 A Java 3D Example (cont.)
Fig. 4.18 Demonstrating MouseZoom behavior.
2002 Prentice Hall. All rights reserved.
4.4.3 A Java 3D Example (cont.)
Fig. 4.19 Demonstrating changing color in Java 3D.
2002 Prentice Hall. All rights reserved.
4.4.3 A Java 3D Example (cont.)
Fig. 4.20 Demonstrating texture mapping in Java 3D.
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ControlPanel.java
// ControlPanel is a JPanel that contains Swing controls
// for manipulating a Java3DWorld.
package com.deitel.advjhtp1.java3d;
// Java core packages
import java.awt.*;
import java.awt.event.*;
// Java extension packages
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
public class ControlPanel extends JPanel {
Outline
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 1).
Declare three JSliders to change
the color (red, Line
green18
and blue) of
the light that hits the 3D shape
// JSliders control lighting color
private JSlider redSlider, greenSlider, blueSlider;
// JCheckbox turns on texture mapping
private JCheckBox textureCheckBox;
Line 21
Declare JCheckBox to
enable texture mapping
// graphics display environment
private Java3DWorld java3DWorld;
// ControlPanel constructor
public ControlPanel( Java3DWorld tempJ3DWorld )
{
java3DWorld = tempJ3DWorld;
// assemble instruction panel
JPanel instructionPanel = new JPanel();
TitledBorder titledBorder =
new TitledBorder( "Transformation Instructions" );
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
titledBorder.setTitleJustification( TitledBorder.CENTER );
instructionPanel.setBorder( titledBorder );
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 2).
JLabel rotationInstructions =
new JLabel( "Rotation - Left Mouse Button",
SwingConstants.CENTER );
JLabel translationInstructions =
new JLabel( "Translation - Right Mouse Button",
SwingConstants.CENTER );
JLabel scalingInstructions =
new JLabel( "Scale - Alt + Left Mouse Button",
SwingConstants.CENTER );
// add instruction JLabels to JPanel
instructionPanel.add( rotationInstructions );
instructionPanel.add( translationInstructions );
instructionPanel.add( scalingInstructions );
Outline
Lines 53-55
Declare JLabels that include
program instructions
// assemble texture mapping control panel
JPanel texturePanel = new JPanel();
TitledBorder textureBorder =
new TitledBorder( "Texture Controls" );
textureBorder.setTitleJustification( TitledBorder.CENTER );
texturePanel.setBorder( textureBorder );
textureCheckBox = new JCheckBox(
"Apply Texture Map to Image" );
texturePanel.add( textureCheckBox );
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// create ItemListener for JCheckBox
textureCheckBox.addItemListener(
new ItemListener() {
Outline
When user selects JCheckBox,
enable texture mapping
// invoked when checkbox selected/deselected
public void itemStateChanged( ItemEvent event )
{
if( event.getStateChange() == ItemEvent.SELECTED )
Java3DWorld.updateTexture( true );
else
Java3DWorld.updateTexture( false );
}
} // end anonymous inner class
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 3).
Lines 72-85
);
// create JPanel with instructionPanel and texturePanel
JPanel topPanel = new JPanel(
new GridLayout( 2, 1, 0, 20 ) );
topPanel.add( instructionPanel );
topPanel.add( texturePanel );
// assemble lighting color control panel
JPanel colorPanel = new JPanel(
new FlowLayout( FlowLayout.LEFT, 15, 15 ) );
TitledBorder colorBorder =
new TitledBorder( "Direct Lighting Color Controls" );
colorBorder.setTitleJustification( TitledBorder.CENTER );
colorPanel.setBorder( colorBorder );
JLabel redLabel = new JLabel( "R" );
JLabel greenLabel = new JLabel( "G" );
2002 Prentice Hall.
All rights reserved.
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
Outline
JLabel blueLabel = new JLabel( "B" );
// create JSlider for adjusting red light component
redSlider = new JSlider(
SwingConstants.HORIZONTAL, 0, 255, 25 );
redSlider.setMajorTickSpacing( 25 );
redSlider.setPaintTicks( true );
// create JSlider for adjusting green light component
greenSlider = new JSlider(
SwingConstants.HORIZONTAL, 0, 255, 25 );
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 4).
Lines 130-142
greenSlider.setMajorTickSpacing( 25 );
greenSlider.setPaintTicks( true );
// create JSlider for adjusting blue light component
blueSlider = new JSlider(
SwingConstants.HORIZONTAL, 0, 255, 25 );
blueSlider.setMajorTickSpacing( 25 );
blueSlider.setPaintTicks( true );
When user moves JSlider, change
color of lighting that hits 3D shape
// create ChangeListener for JSliders
ChangeListener slideListener = new ChangeListener() {
// invoked when slider has been accessed
public void stateChanged( ChangeEvent event )
{
Color color = new Color(
redSlider.getValue(), greenSlider.getValue(),
blueSlider.getValue() );
Java3DWorld.changeColor( color );
}
2002 Prentice Hall.
All rights reserved.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
}; // end anonymous inner class
// add listener to sliders
redSlider.addChangeListener( slideListener );
greenSlider.addChangeListener( slideListener );
blueSlider.addChangeListener( slideListener );
// add lighting
colorPanel.add(
colorPanel.add(
colorPanel.add(
colorPanel.add(
colorPanel.add(
colorPanel.add(
color control components to colorPanel
redLabel );
redSlider );
greenLabel );
greenSlider );
blueLabel );
blueSlider );
// set Java3DWorld object default RGB slider values
Java3DWorld.changeColor(
new Color( redSlider.getValue(),
greenSlider.getValue(), blueSlider.getValue() ) );
Outline
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 5).
Lines 149-167
Add controls to GUI
// set GridLayout
setLayout( new GridLayout( 2, 1, 0, 20 ) );
// add JPanels to ControlPanel
add( topPanel );
add( colorPanel );
} // end ControlPanel constructor method
// return preferred dimensions of container
public Dimension getPreferredSize()
{
return new Dimension( 250, 150 );
}
2002 Prentice Hall.
All rights reserved.
176
177
178
179
180
181
182
// return minimum size of container
public Dimension getMinimumSize()
{
return getPreferredSize();
}
}
Outline
Fig. 4.21
ControlPanel
provides Swing
controls for
Java3DWorld
(part 6).
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Java3DExample.java
// Java3DExample is an application that demonstrates Java 3D
// and provides an interface for a user to control the
// transformation, lighting color, and texture of a 3D scene.
package com.deitel.advjhtp1.java3d;
// Java core packages
import java.awt.*;
import java.awt.event.*;
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
public class Java3DExample extends JFrame {
private Java3DWorld java3DWorld; // 3D scene panel
private JPanel controlPanel; // 3D scene control panel
Outline
Fig. 4.22 GUI for
Java3DWorld
and ControlPanel
(part 1).
Lines 15-18
Create JFrame application
that contains references to
Java3DWorld and
ControlPanel objects
// initialize Java3DWorld and ControlPanel
public Java3DExample()
{
super( "Java 3D Graphics Demo" );
java3DWorld = new Java3DWorld( "images/ajhtp.png" );
controlPanel = new ControlPanel( java3DWorld );
// add Components to JFrame
getContentPane().add( java3DWorld, BorderLayout.CENTER );
getContentPane().add( controlPanel, BorderLayout.EAST );
} // end Java3DExample constructor
// start program
public static void main( String args[] )
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
{
Java3DExample application = new Java3DExample();
application.setDefaultCloseOperation( EXIT_ON_CLOSE );
application.pack();
application.setVisible( true );
}
}
Outline
Fig. 4.22 GUI for
Java3DWorld
and ControlPanel
(part 2).
2002 Prentice Hall.
All rights reserved.
4.5 A Java 3D Case Study: A 3D Game with
Custom Behaviors
• Custom behaviors
– Programmer-defined behaviors
– Extensions of utility behavior classes
– Examples:
• Collision detection
• Navigation
• Position checking
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Class Java3DWorld1 is a Java 3D game.
// The goal is to navigate the small red ball in the bottom right
// corner to the screen's top-left corner without colliding with
// any of the flying objects. The user can specify the number of
// flying objects to make the game more difficult.
package com.deitel.advjhtp1.java3dgame;
// Java core packages
import java.awt.*;
import java.net.*;
import java.util.BitSet;
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment (part 1).
Line 22
// Java extension packages
import javax.media.j3d.*;
import javax.vecmath.*;
// Java3D utility packages
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.image.*;
import com.sun.j3d.utils.universe.*;
public class Java3DWorld1 extends Canvas3D {
// container dimensions
private static final int CONTAINER_WIDTH = 600;
private static final int CONTAINER_HEIGHT = 600;
Class Java3DWorld1 is
a Java 3D game and will
require custom behaviors
// constants that specify number of shapes
private static final int NUMBER_OF_SHAPES = 20;
private static final int NUMBER_OF_PRIMITIVES = 4;
// initial scene to display in Switch
private static final int DEFAULT_SCENE = 0;
2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// constants for animating rotation
private static final int MAX_ROTATION_SPEED =
private static final int MIN_ROTATION_SPEED =
private static final float MIN_ROTATION_ANGLE
private static final float MAX_ROTATION_ANGLE
( float ) Math.PI * 8.0f;
25000;
20000;
= 0.0f;
=
// constants for animating translation
private static final int MAX_TRANSLATION_SPEED = 7500;
private static final int MIN_TRANSLATION_SPEED = 2500;
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment (part 2).
// maximum time until animations begins
public static final int MAX_PHASE_DELAY = 20000;
// 3D shape information
private static final float
private static final float
private static final float
private static final float
private static final float
MAX_RADIUS = 0.15f;
MAX_LENGTH = 0.2f;
MAX_SHININESS = 128.0f;
SPHERE_RADIUS = 0.15f;
BOUNDING_RADIUS = 100.0f;
private Switch shapeSwitch; // contains flying shapes
private BoundingSphere bounds; // bounds for nodes and groups
private SimpleUniverse simpleUniverse; // 3D environment
private String imageName; // texture image file name
// Java3DWorld1 constructor
public Java3DWorld1( String imageFileName ) {
super( SimpleUniverse.getPreferredConfiguration() );
imageName = imageFileName;
2002 Prentice Hall.
All rights reserved.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// create SimpleUniverse ( 3D Graphics environment )
simpleUniverse = new SimpleUniverse( this );
// set viewing distance for 3D scene
ViewingPlatform viewPlatform =
simpleUniverse.getViewingPlatform();
Outline
Create Java 3D scene
Fig. 4.23 Class
Java3DWorld1
Create
viewing distance
creates the 3D-game
environment (part 3).
viewPlatform.setNominalViewingTransform();
// create 3D scene
BranchGroup branchGroup = createScene();
Line 71
// attach BranchGroup to SimpleUniverse
simpleUniverse.addBranchGraph( branchGroup );
Lines 74-77
} // end Java3DWorld1 constructor
Line 96
// create 3D scene
public BranchGroup createScene()
{
BranchGroup sceneBranchGroup = new BranchGroup();
Line 100
// create scene Switch group
Switch sceneSwitch = initializeSwitch( DEFAULT_SCENE );
// create Switch group containing shapes
shapeSwitch = initializeSwitch( DEFAULT_SCENE );
Switch object specifies
which 3D objects to
render (in this game, the
objects are the obstacles)
// initialize BranchGroup that contains only elements
// in game scene
BranchGroup gameBranchGroup = new BranchGroup();
// add shapeSwitch to gameBranchGroup
gameBranchGroup.addChild( shapeSwitch );
BranchGroup is the root node of
a scene graph in
a Java
3D scene
2002
Prentice
Hall.
All rights reserved.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// add gameBranchGroup to sceneSwitch
sceneSwitch.addChild( gameBranchGroup );
// add sceneSwitch to sceneBranchGroup
sceneBranchGroup.addChild( sceneSwitch );
// create BoundingSphere for 3D objects and behaviors
bounds = new BoundingSphere(
new Point3d( 0.0f, 0.0f, 0.0f ), BOUNDING_RADIUS );
// create rotation TransformGroup array
TransformGroup[] spinTransform =
createTransformGroupArray( NUMBER_OF_SHAPES );
// create translation TransformGroup array
TransformGroup[] pathTransform =
createTransformGroupArray( NUMBER_OF_SHAPES );
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment (part 4).
Line 116-121
Create TransformGroup
arrays
specify
Linesto132-133
transformational behavior
(rotationLines
and translation)
136-137 for
the obstacles
// create RotationInterpolators
createRotationInterpolators( spinTransform,
NUMBER_OF_SHAPES );
// create PositonInterpolators
createPositionInterpolators( pathTransform,
NUMBER_OF_SHAPES );
// create Appearance objects for Primitives
Appearance[] shapeAppearance =
createAppearance( NUMBER_OF_SHAPES );
// create shapes
Primitive[] shapes =
createShapes( shapeAppearance, NUMBER_OF_SHAPES );
Create Appearances
(i.e., colors and texture)
for obstacles
Primitives represent
the actual 3D shapes
2002 Prentice Hall.
All rights reserved.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// add shapes to scene structure
for ( int x = 0; x < NUMBER_OF_SHAPES; x++ ) {
// add primitive to spinTransform group
spinTransform[ x ].addChild( shapes[ x ] );
// add spinTransform group to pathTransform group
pathTransform[ x ].addChild( spinTransform[ x ] );
// add pathTransform group to shapeSwitch group
shapeSwitch.addChild( pathTransform[ x ] );
}
// create and set scene lighting
setLighting( sceneBranchGroup, bounds );
// create scene to display if user loses
TransformGroup loserTransformGroup =
createEndScene( "You Lose!" );
Outline
Fig. 4.23 Class
Java3DWorld1
creates
the 3D-game
Add
Primitives
environment
(part 5).
(shapes)
to the scene
Lines 140-150
Lines 156-160
Lines 163-167
Create scene for when
user loses the game
// add loser scene to sceneSwitch
sceneSwitch.addChild( loserTransformGroup );
// create scene to display if user winss
TransformGroup winnerTransformGroup =
createEndScene( "You Win!" );
Create scene for when
user wins the game
// add winner scene to sceneSwitch
sceneSwitch.addChild( winnerTransformGroup );
// create shiny red Appearance for navigating shape
Appearance flyingAppearance = createAppearance(
new Color3f( 1.0f, 0.0f, 0.0f ) );
2002 Prentice Hall.
All rights reserved.
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// initialize navigable sphere
Primitive flyingBall = new Sphere(
0.03f, Sphere.GENERATE_NORMALS, flyingAppearance );
Outline
Create user-navigated
shape
(shiny red “flying” ball)
// set capability bits to enable collision detection and
// allow for read/write of bounds
flyingBall.setCollidable( true );
flyingBall.setCapability( Node.ENABLE_COLLISION_REPORTING );
flyingBall.setCapability( Node.ALLOW_BOUNDS_READ );
flyingBall.setCapability( Node.ALLOW_BOUNDS_WRITE );
// create TransformGroup to translate shape position
TransformGroup startTransform = createTransform(
new Vector3f( 0.9f, -0.9f, 0.0f ) );
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment (part 6).
Lines 174-175
Lines 203-205
startTransform.addChild( flyingBall );
gameBranchGroup.addChild( startTransform );
// create Material for Appearance for target sphere
Appearance targetAppearance = createAppearance(
new Color3f( 0.0f, 1.0f, 0.0f ) );
Create 3D shape to which the
// obtain textured image for target sphere
user-navigated shape must travel
String rgb = new String( "RGB" );
TextureLoader textureLoader = new TextureLoader(
Java3DWorld1.class.getResource( imageName ), rgb, this );
textureLoader.getTexture().setEnable( true );
targetAppearance.setTexture( textureLoader.getTexture() );
// initialize target sphere
Primitive targetSphere = new Sphere( SPHERE_RADIUS,
Sphere.GENERATE_TEXTURE_COORDS | Sphere.GENERATE_NORMALS,
targetAppearance );
2002 Prentice Hall.
All rights reserved.
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
Outline
// disable collision detection for sphere
targetSphere.setCollidable( false );
// create vector to target point
Vector3f target = new Vector3f( -1.0f, 1.0f, -1.0f );
// create TransformGroup that translates sphere position
TransformGroup targetTransform = createTransform( target );
targetTransform.addChild( targetSphere );
gameBranchGroup.addChild( targetTransform );
// create Navigator behavior
Navigator navigator = new Navigator( startTransform );
navigator.setSchedulingBounds( bounds );
// create Collide behavior
Collide collider = new Collide(
simpleUniverse, flyingBall, sceneSwitch );
collider.setSchedulingBounds( bounds );
// create GoalDetector behavior
GoalDetector goalDetector = new GoalDetector(
simpleUniverse, startTransform, sceneSwitch,
target, SPHERE_RADIUS );
goalDetector.setSchedulingBounds( bounds );
// add Behaviors to scene
sceneBranchGroup.addChild( goalDetector );
sceneBranchGroup.addChild( collider );
sceneBranchGroup.addChild( navigator );
// create Background for scene
Background background = new Background();
background.setColor( 0.4f, 0.4f, 1.0f );
background.setApplicationBounds( bounds );
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment (part 7).
Lines 219-231
Lines 234-236
Instantiate
custom
behaviors
Lines
239-241
(discussed later) for position
checking, collision detection
and navigation
Integrate custom
behaviors to scene
Create scene
2002 Prentice Hall.
Background
All rights reserved.
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
sceneBranchGroup.addChild( background );
sceneBranchGroup.compile();
return sceneBranchGroup;
} // end method createScene
Outline
Compile the BranchGroup to
inform the Java 3D engine to
4.23 Class
optimize renderingFig.
the scene
Java3DWorld1
creates the 3D-game
environment (part 8).
scene
// create Appearance object for Primitive in
private Appearance createAppearance( Color3f diffuseColor )
{
Line 244
Appearance appearance = new Appearance();
Material material = new Material();
Utility method
for 251-261
creating the
material.setShininess( MAX_SHININESS );
Lines
material.setDiffuseColor( diffuseColor );
Appearance for a 3D shape
material.setAmbientColor( 0.0f, 0.0f, 0.0f );
Lines 265-282
appearance.setMaterial( material );
return appearance;
} // end method createAppearance
// create TransformGroup for placing an object in scene
private TransformGroup createTransform(
Vector3f positionVector )
{
// initialize a TransformGroup and set capability bits
TransformGroup transformGroup = new TransformGroup();
transformGroup.setCapability(
TransformGroup.ALLOW_TRANSFORM_READ );
transformGroup.setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE );
Utility method for creating a
TransformGroup for
placing a shape in the 3D scene
2002 Prentice Hall.
All rights reserved.
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
// translate starting position to bottom right of scene
Transform3D location = new Transform3D();
location.setTranslation( positionVector );
Utility
transformGroup.setTransform( location );
return transformGroup;
} // end method createTransform
Outline
method for creating a
4.23
Class
Switch object to Fig.
specify
the 3D
Java3DWorld1
objects to render (i.e.,
the obstacles)
creates the 3D-game
environment (part 9).
// initialize Switch group and set capability bits
private Switch initializeSwitch( int sceneNumber )
{
Switch switchGroup = new Switch( sceneNumber );
switchGroup.setCollidable( true );
switchGroup.setCapability( Switch.ALLOW_SWITCH_WRITE );
switchGroup.setCapability( Switch.ALLOW_SWITCH_READ );
switchGroup.setCapability( Group.ALLOW_CHILDREN_WRITE );
switchGroup.setCapability( Group.ALLOW_CHILDREN_READ );
switchGroup.setCapability(
Group.ENABLE_COLLISION_REPORTING );
Utility
return switchGroup;
Lines 285-297
Lines 299-327
method for creating an array
of TransformGroup objects
} // end method initializeSwitch
private TransformGroup[] createTransformGroupArray(
int size )
{
TransformGroup[] transformGroup =
new TransformGroup[ size ];
// set TransformGroup's WRITE and READ permissions
// and enable collision reporting
for ( int i = 0; i < size; i++ ) {
2002 Prentice Hall.
All rights reserved.
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
Outline
// create TransformGroups
transformGroup[ i ] = new TransformGroup();
// enable collision reporting
transformGroup[ i ].setCapability(
Group.ENABLE_COLLISION_REPORTING );
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 10).
// enable WRITE permission
transformGroup[ i ].setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE );
// enable READ permission
transformGroup[ i ].setCapability(
TransformGroup.ALLOW_TRANSFORM_READ );
Line 330
}
return transformGroup;
} // end method createTransformGroupArray
Utility method for creating
RotationInterpolator
objects to specify the rotation
speed for the obstacles
// create RotationInterpolators for scene
private void createRotationInterpolators(
TransformGroup[] transformGroup, int size )
{
// declare structures for creating RotationInterpolators
Alpha[] alphaSpin = new Alpha[ size ];
Transform3D[] spinAxis =
new Transform3D[ size ];
RotationInterpolator[] spinner =
new RotationInterpolator[ size ];
// create RotationInterpolator for each shape
for ( int x = 0; x < size; x++ ) {
2002 Prentice Hall.
All rights reserved.
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
// initialize Alpha
alphaSpin[ x ] = new Alpha();
// set increasing time for Alpha to random number
alphaSpin[ x ].setIncreasingAlphaDuration(
MIN_ROTATION_SPEED + ( ( int ) ( Math.random() *
MAX_ROTATION_SPEED ) ) );
// initialize RotationInterpolator using appropriate
// Alpha and TransformGroup
spinner[ x ] = new RotationInterpolator(
alphaSpin[ x ], transformGroup[ x ] );
Outline
Alpha objects specify
either
increasing or decreasing
functions, and thus specify
Fig. 4.23 Class
the rotation direction
Java3DWorld1
creates the 3D-game
environment
(part 11).
spinAxis[ x ] = new Transform3D();
Line 346
Line 378
// set random X-axis rotation
spinAxis[ x ].rotX(
( float ) ( Math.PI * ( Math.random() * 2 ) ) );
spinner[ x ].setAxisOfRotation( spinAxis[ x ] );
// set minimum and maximum rotation angles
spinner[ x ].setMinimumAngle( MIN_ROTATION_ANGLE );
spinner[ x ].setMaximumAngle( MAX_ROTATION_ANGLE );
spinner[ x ].setSchedulingBounds( bounds );
// add RotationInterpolator to appropriate TransformGroup
transformGroup[ x ].addChild( spinner[ x ] );
}
} // end method createRotationInterpolators
// create PositionInterpolators
private void createPositionInterpolators(
Utility method for creating
PositionInterpolator
objects to specify the translation
speed forthe
obstacles
2002 Prentice Hall.
All rights reserved.
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
TransformGroup[] transformGroup, int size )
{
// create structures for PositionInterpolators
Alpha[] alphaPath = new Alpha[ size ];
PositionInterpolator[] mover =
new PositionInterpolator[ size ];
Transform3D[] pathAxis =
new Transform3D[ size ];
// create PositionInterpolator for each shape
for ( int x = 0; x < size; x++ ) {
// initialize Alpha
alphaPath[ x ] = new Alpha();
// set mode to increase and decrease interpolation
alphaPath[ x ].setMode(
Alpha.INCREASING_ENABLE | Alpha.DECREASING_ENABLE );
// set random phase delay
alphaPath[ x ].setPhaseDelayDuration(
( ( int ) ( Math.random() * MAX_PHASE_DELAY ) ) );
// randomize translation speed
int speed = MIN_TRANSLATION_SPEED +
( int ) ( Math.random() * MAX_TRANSLATION_SPEED );
// set increasing and decreasing durations
alphaPath[ x ].setIncreasingAlphaDuration( speed );
alphaPath[ x ].setDecreasingAlphaDuration( speed );
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 12).
Alpha
objects
Line
394 specify
the translation direction
Lines 401-402
SetLines
phase 405-406
delay to delay
the initial movement of
the obstacles (so an
obstacle does not collide
with the user-navigated
shape immediately after
the game has started)
All obstacles move
at different speeds
2002 Prentice Hall.
All rights reserved.
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
Outline
// randomize translation axis
pathAxis[ x ] = new Transform3D();
pathAxis[ x ].rotX(
( float ) ( Math.PI * ( Math.random() * 2 ) ) );
pathAxis[ x ].rotY(
( float ) ( Math.PI * ( Math.random() * 2 ) ) );
pathAxis[ x ].rotZ(
( float ) ( Math.PI * ( Math.random() * 2 ) ) );
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 13).
// initialize PositionInterpolator
mover[ x ] = new PositionInterpolator( alphaPath[ x ],
transformGroup[ x ], pathAxis[ x ], 1.0f, -1.0f );
Line 434
mover[ x ].setSchedulingBounds( bounds );
// add PostionInterpolator to appropriate TransformGroup
transformGroup[ x ].addChild( mover[ x ] );
}
} // end method createPositionInterpolators
// create appearance and material arrays for Primitives
private Appearance[] createAppearance( int size )
{
// create Appearance objects for each shape
Appearance[] appearance =
new Appearance[ size ];
Utility method for creating
an array of Appearance
objects for the 3D obstacles
Material[] material = new Material[ size ];
// set material and appearance properties for each shape
for( int i = 0; i < size; i++ ) {
appearance[ i ] = new Appearance();
material[ i ] = new Material();
2002 Prentice Hall.
All rights reserved.
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
);
474
475
476
477
478
479
480
481
Outline
// set material ambient color
material[ i ].setAmbientColor(
new Color3f( 0.0f, 0.0f, 0.0f ) );
// set material Diffuse color
material[ i ].setDiffuseColor( new Color3f(
( float ) Math.random(), ( float ) Math.random(),
( float ) Math.random() ) );
// set Material for appropriate Appearance object
appearance[ i ].setMaterial( material[ i ] );
}
return appearance;
} // end method createAppearance
// create Primitives shapes
private Primitive[] createShapes( Appearance[] appearance,
int size )
{
Primitive[] shapes = new Primitive[ size ];
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 14).
Utility method for
generating
random an
Line at
464
array of Primitive
objects, which collectively
represent the 3D obstacles
// random loop to get index
for ( int x = 0; x < size; x++ ) {
// generate random shape index
int index = ( int ) ( Math.random() * NUMBER_OF_PRIMITIVES
// create shape based on random index
switch( index ) {
case 0: // create Box
shapes[ x ] = new Box(
( ( float ) Math.random() * MAX_LENGTH ),
( ( float ) Math.random() * MAX_LENGTH ),
2002 Prentice Hall.
All rights reserved.
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
( ( float ) Math.random() * MAX_LENGTH ),
Box.GENERATE_NORMALS, appearance[ x ] );
break;
case 1: // create Cone
shapes[ x ] = new Cone(
( ( float ) Math.random() * MAX_RADIUS ),
( ( float ) Math.random() * MAX_LENGTH ),
Cone.GENERATE_NORMALS, appearance[ x ] );
break;
case 2: // create Cylinder
shapes[ x ] = new Cylinder(
( ( float ) Math.random() * MAX_RADIUS ),
( ( float ) Math.random() * MAX_LENGTH ),
Cylinder.GENERATE_NORMALS, appearance[ x ] );
break;
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
The
(partfour
15).available
Primitives are Box,
Cone,
Cylinder
Lines
478-504 and
Sphere
Lines 510-516
case 3: // create Sphere
shapes[ x ] = new Sphere(
( ( float ) Math.random() * MAX_RADIUS ),
Sphere.GENERATE_NORMALS, appearance[ x ] );
break;
} // end switch statement
// set capability bits to enable collisions and to set
// read/write permissions of bounds
shapes[ x ].setCapability(
Node.ENABLE_COLLISION_REPORTING );
shapes[ x ].setCapability(
Node.ALLOW_BOUNDS_READ );
shapes[ x ].setCapability(
Node.ALLOW_BOUNDS_WRITE );
shapes[ x ].setCollidable( true );
Enable collision detection
among the obstacles
2002 Prentice Hall.
All rights reserved.
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
Outline
}
return shapes;
} // end method createShapes
// initialize ambient and directional lighting
private void setLighting( BranchGroup scene,
BoundingSphere bounds )
{
// initialize ambient lighting
AmbientLight ambientLight = new AmbientLight();
ambientLight.setInfluencingBounds( bounds );
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
Utility method for setting
environment
the ambient and direction
(part 16).
light of the 3D scene
Lines 525-542
// initialize directional lighting
DirectionalLight directionalLight = new DirectionalLight();
directionalLight.setColor(
new Color3f( 1.0f, 1.0f, 1.0f ) );
directionalLight.setInfluencingBounds( bounds );
Lines 545-558
// add lights to scene
scene.addChild( ambientLight );
scene.addChild( directionalLight );
} // end method setLighting
// update scene by rendering different shapes in shapeSwitch
public void switchScene( int numberChildren, int size )
{
// create a new BitSet of size NUMBER_OF_SHAPES
Change
BitSet bitSet = new BitSet( size );
the Scene that the
SimpleUniverse displays
// set BitSet values
for ( int i = 0; i < numberChildren; i++ )
2002 Prentice Hall.
All rights reserved.
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
Outline
bitSet.set( i );
// instruct switchShape to render Mask of objects
shapeSwitch.setWhichChild( Switch.CHILD_MASK );
shapeSwitch.setChildMask( bitSet );
} // end method switchScene
// create end scene when user wins or loses
private TransformGroup createEndScene( String text )
{
TransformGroup transformGroup = new TransformGroup();
transformGroup.setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE );
Utility method
for creating
Fig. 4.23
Class
the sceneJava3DWorld1
displayed when
the user wins
(reaches
the
creates
the 3D-game
destination)
or loses
environment
(collides (part
with an
obstacle)
17).
Line 561
// disable scene collision detection
transformGroup.setCollidable( false );
// create Alpha object
Alpha alpha = new Alpha();
alpha.setIncreasingAlphaDuration( MAX_ROTATION_SPEED );
// create RotationInterpolator for scene
RotationInterpolator rotation =
new RotationInterpolator( alpha, transformGroup );
// set axis of rotation
Transform3D axis = new Transform3D();
axis.rotY( ( float ) ( Math.PI / 2.0 ) );
rotation.setAxisOfRotation( axis );
// set minimum and maximum rotation angles
rotation.setMinimumAngle( 0.0f );
rotation.setMaximumAngle( ( float ) ( Math.PI * 8.0 ) );
2002 Prentice Hall.
All rights reserved.
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
rotation.setSchedulingBounds( bounds );
transformGroup.addChild( rotation );
// create scene geometry
Appearance appearance = new Appearance();
Material material = new Material();
appearance.setMaterial( material );
// set diffuse color of material
material.setDiffuseColor(
new Color3f( 0.0f, 0.8f, 1.0f ) );
// create Font3D object
Font3D font3d = new Font3D(
new Font( "Helvetica", Font.ITALIC, 1 ),
new FontExtrusion() );
// create Text3D object from Font3D object
Text3D text3d = new Text3D( font3d, text,
new Point3f( -2.0f, 0.0f, 0.0f ) );
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 18).
Lines 600-606
Display 3D text that
indicates whether the
user has won or lost
// create Shape3D object from Text3D object
Shape3D textShape = new Shape3D( text3d );
textShape.setAppearance( appearance );
// disable collision detection
textShape.setCollidable( false );
transformGroup.addChild( textShape );
return transformGroup;
} // end method createEndScene
2002 Prentice Hall.
All rights reserved.
622
623
624
625
626
627
628
629
630
631
632
633
634
// return preferred dimensions of Container
public Dimension getPreferredSize()
{
return new Dimension( CONTAINER_WIDTH, CONTAINER_HEIGHT );
}
// return minimum size of Container
public Dimension getMinimumSize()
{
return getPreferredSize();
}
Outline
Fig. 4.23 Class
Java3DWorld1
creates the 3D-game
environment
(part 19).
}
Target
Obstacles
User-navigated shape
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Outline
// Class Collide implements collision-detection behavior
// for a Java 3D application. Collide switches scenes
// when the armed object collides with another object.
package com.deitel.advjhtp1.java3dgame;
Fig. 4.24
Implementing
collision detection in
a Java 3D application
(part 1).
// Core Java packages
import java.lang.*;
import java.util.*;
// Java extension packages
import javax.media.j3d.*;
import javax.vecmath.*;
// Java 3D utility packages
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
Line 18
Class Collide implements
the collision-detection behavior
Line 21
public class Collide extends Behavior {
// armed node generates WakeupOnCollisionEntry upon collision
private Node armingNode;
// specifies to what WakeupEvents to react
private WakeupCondition wakeupCondition;
private Switch switchScene; // Switch group contains 3D
private SimpleUniverse simpleUniverse;
Collision occurs when
armingNode’s bounding
volume intersects triggering
scenes node’s bounding volume
// index of scene to switch to upon collision
private static final int LOSER_SCENE = 1;
// constructor method initializes members
public Collide( SimpleUniverse universe, Node node,
Switch tempSwitch )
{
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
armingNode = node;
switchScene = tempSwitch;
simpleUniverse = universe;
Fig. 4.24
Implementing
collision detection in
a Java 3D application
(part 2).
// create WakeupOnCollisionEntry
WakeupOnCollisionEntry wakeupEvent =
new WakeupOnCollisionEntry( armingNode,
WakeupOnCollisionEntry.USE_GEOMETRY );
// set of WakeupEvents to which Behavior reponds
WakeupCriterion[] wakeupCriteria = { wakeupEvent };
Line 62
// Behavior responds when any WakeupEvent in
// WakeupCriterion occurs
wakeupCondition = new WakeupOr( wakeupCriteria );
} // end constructor
// initialize Behavior's wakeup conditions
public void initialize()
{
// register WakeupCriterion to respond to collision events
wakeupOn( wakeupCondition );
}
// handle WakeupEvents
public void processStimulus( Enumeration detected )
{
// loop to handle events
while( detected.hasMoreElements() ) {
// get next sequential element
WakeupCriterion criterion =
( WakeupCriterion ) detected.nextElement();
Upon collision, the behavior
scheduler calls method
processStimulus
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// process event if WakeupOnCollisionEntry
if ( criterion instanceof WakeupOnCollisionEntry ) {
processCollision();
// re-register WakeupCriterion to respond to new
// WakeonOnCollisionEntry event
wakeupOn( wakeupCondition );
}
}
Outline
Handle only those WakeupCriterions
Fig. 4.24 that are
relatedImplementing
to collision detection
collision detection in
a Java 3D application
(part 3).
} // end method processStimulus
// process collision by moving camera view back and
// switching scenes in Switch group
private void processCollision()
{
Transform3D shiftViewBack = new Transform3D();
Lines 72-73
Lines 85-104
// set Transform3D's Translation
shiftViewBack.setTranslation(
new Vector3f( 0.0f, 0.0f, 8.0f ) );
// set Transform3D that determines View
ViewingPlatform viewPlatform =
simpleUniverse.getViewingPlatform();
TransformGroup platformTransform =
viewPlatform.getViewPlatformTransform();
platformTransform.setTransform( shiftViewBack );
// render scene in Switch group
switchScene.setWhichChild( LOSER_SCENE );
If there is a
collision, display the
“You Lose” scene
2002 Prentice Hall.
All rights reserved.
106
107
} // end method processCollision
}
Outline
Fig. 4.24
Implementing
collision detection in
a Java 3D application
(part 4).
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Class Navigator is a subclass of Behavior that implements a
// keyboard translation navigator. Navigator responds to certain
// key presses by translating an object in a 3D scene.
package com.deitel.advjhtp1.java3dgame;
// Core Java packages
import java.awt.*;
import java.awt.event.*;
import java.util.*;
// Java extension packages
import javax.media.j3d.*;
import javax.vecmath.*;
Outline
Fig. 4.25 Behavior
that enables the user
to navigate a 3D
shape (part 1).
Line 18
// Java 3D utility packages
import com.sun.j3d.utils.universe.*;
public class Navigator extends Behavior {
Class Navigator allows
the user to navigate the
shape via the keyboard
// TransformGroup associated with object controlled
// by keyboard navigator
private TransformGroup objectTransform;
// translation
private static
private static
private static
private static
private static
private static
amounts
final float
final float
final float
final float
final float
final float
LEFT = -0.02f;
RIGHT = 0.02f;
UP = 0.02f;
DOWN = -0.02f;
FORWARD = 0.02f;
BACKWARD = -0.02f;
// waking conditions for Behavior
private WakeupCondition wakeupCondition;
2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// constructor method
public Navigator( TransformGroup transform )
{
objectTransform = transform;
// initialize WakeupOnAWTEvent to repond to
// AWT KeyEvent.KEY_PRESSED events
WakeupOnAWTEvent wakeupEvent =
new WakeupOnAWTEvent( KeyEvent.KEY_PRESSED );
// set of WakeupEvents to which Behavior responds
WakeupCriterion[] wakeupCriteria = { wakeupEvent };
Outline
Fig. 4.25 Behavior
that enables the user
to navigate a 3D
shape (part 2).
Line 63
// Behavior responds when WakeupEvent in the
// WakeupCriterion occurs
wakeupCondition = new WakeupOr( wakeupCriteria );
} // end constructor
// initialize Behavior's wakeup conditions
public void initialize()
{
// register WakeupCriterion to generate WakeupEvents
// when AWT events occur
wakeupOn( wakeupCondition );
}
// handle WakeupEvents
public void processStimulus( Enumeration detected )
{
// loop to handle events
while ( detected.hasMoreElements() ) {
// get next WakeupCriterion
WakeupCriterion wakeupCriterion =
When the user presses keys
on the keyboard, the behavior
scheduler calls method
processStimulus
2002 Prentice Hall.
All rights reserved.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Outline
( WakeupCriterion ) detected.nextElement();
// handle WakeupCriterion if WakeupOnAWTEvent
if ( wakeupCriterion instanceof WakeupOnAWTEvent ) {
Fig. 4.25 Behavior
WakeupOnAWTEvent awtEvent =
Handle only
Wakeup(WakeupOnAWTEvent) wakeupCriterion;
thatthose
enables
the user
AWTEvent[] events = awtEvent.getAWTEvent();
Criterions
that are
to navigate
a 3D
// invoke method moveObject with AWTEvent
moveShape( events );
}
}
related to shape
the user(part
pressing
3). a
key on the keyboard
Lines 73-74
// re-register wakeupCondition to respond to next key press
wakeupOn( wakeupCondition );
Line 89
} // end method processStimulus
// handle AWT KeyEvents by translating an object in 3D scene
private void moveShape( AWTEvent[] awtEvents )
{
// handle all events in AWTEvent array
for ( int x = 0; x < awtEvents.length; x++)
{
// handle if AWTEvent is KeyEvent
if ( awtEvents[ x ] instanceof KeyEvent ) {
Utility method for
translating 3D shape
// get cooresponding KeyEvent
KeyEvent keyEvent = ( KeyEvent ) awtEvents[ x ];
// respond only if KeyEvent is of type KEY_PRESSED
if ( keyEvent.getID() == KeyEvent.KEY_PRESSED ) {
// get KeyCode associated with KeyEvent
int keyCode = keyEvent.getKeyCode();
2002 Prentice Hall.
All rights reserved.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
Outline
Transform3D transform3D = new Transform3D();
// get Transform3D from TransformGroup of
// navigable object
objectTransform.getTransform( transform3D );
Fig. 4.25 Behavior
that enables the user
to navigate a 3D
shape (part 4).
Vector3f translateVector = new Vector3f();
// retrieve translation vector associated with
// Transform3D
transform3D.get( translateVector );
// update x, y, or z component of translation
// vector based on keypress
switch ( keyCode ) {
case KeyEvent.VK_A: // move left
translateVector.x += LEFT;
break;
case KeyEvent.VK_D: // move right
translateVector.x += RIGHT;
break;
case KeyEvent.VK_W: // move up
translateVector.y += UP;
break;
case KeyEvent.VK_S: // move down
translateVector.y += DOWN;
break;
case KeyEvent.VK_UP: // move backwards
translateVector.z += BACKWARD;
Lines 122-124
Lines 126-128
If user presses ‘A’, move
Lines
130-132
navigable
shape
to the left
Lines 134-136
If user presses ‘D’, move
navigable
shape
to the right
Lines
138-140
If user presses ‘W’, move
navigable shape up
If user presses ‘S’, move
navigable shape down
If user presses the Up key, move
2002 Prentice
Hall.
navigableshape
backward
All rights reserved.
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
Outline
break;
case KeyEvent.VK_DOWN: // move forwards
translateVector.z += FORWARD;
break;
} // end switch
If user presses the Down key,
move navigable
Fig. 4.25
shape forward
Behavior
that enables the user
to navigate a 3D
shape (part 5).
Transform3D
// set translational component of
// with updated translation Vector3f
transform3D.setTranslation( translateVector );
Lines 142-144
// set TransformGroup's Transform3D
objectTransform.setTransform( transform3D );
} // end if KeyEvent.KEY_PRESSED
}
} // end for loop that handles key presses
} // end method moveShape
}
2002 Prentice Hall.
All rights reserved.
4.5 A Java 3D Case Study: A 3D Game with
Custom Behaviors (cont.)
Ke y
A
Tra nsla tio n
move left
D
W
move right
move up
S
move down
Up Arrow
move forward
Down Arrow
move backward
Fig. 4.26
Ke ys fo r na vig a ting the 3D sc e ne in Navigator.
2002 Prentice Hall. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Class GoalDetector defines a position-checking behavior that
// checks to see if the position of a Node is equal to the target
// position. If the positions are equal, the game is over and
// a Java 3D Switch displays a different scene.
package com.deitel.advjhtp1.java3dgame;
// Core Java packages
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class GoalDetector extends Behavior {
// index of scene to display if goal detected
private static final int WINNER_SCENE = 2;
Fig. 4.27
Implementing a
position-checking
Behavior (part 1).
Line 19
// Java extension packages
import javax.media.j3d.*;
import javax.vecmath.*;
// Java 3D utility packages
import com.sun.j3d.utils.universe.*;
Outline
Class GoalDetector enables the
program to determine when the
navigable shape has reached its target
// TransformGroup associated with object
private TransformGroup objectTransform;
private Switch switchScene; // Switch group that contains scenes
private SimpleUniverse simpleUniverse;
private float goalX, goalY, goalZ; // goal coordinates
// radius of sphere at goal coordinates
private float sphereRadius;
2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Behavior's waking conditions
private WakeupCondition wakeupCondition;
// constructor method initializes members
// and creates WakeupCriterion
public GoalDetector( SimpleUniverse universe,
TransformGroup transform, Switch switchGroup,
Vector3f goalVector, float radius )
{
objectTransform = transform;
switchScene = switchGroup;
simpleUniverse = universe;
Outline
Fig. 4.27
Implementing a
position-checking
Behavior (part 2).
// set goal coordinates to goalVector coordinates
goalX = goalVector.x;
goalY = goalVector.y;
goalZ = goalVector.z;
// set radius of sphere at goal coordinates
sphereRadius = radius;
// initialize WakeupOnAWTEvent to respond to
// AWT KeyEvent.KEY_PRESSED events
WakeupOnAWTEvent wakeupEvent =
new WakeupOnAWTEvent( KeyEvent.KEY_PRESSED );
// set of WakeupEvents to which Behavior responds
WakeupCriterion[] wakeupArray = { wakeupEvent };
// Behavior responds when WakeupEvent in
// WakeupCriterion occurs
wakeupCondition = new WakeupOr( wakeupArray );
} // end constructor method
2002 Prentice Hall.
All rights reserved.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// register Behavior's wakeup conditions
public void initialize()
{
// register WakeupCriterion to respond to AWTEvents
wakeupOn( wakeupCondition );
}
// handle WakeupEvents
public void processStimulus( Enumeration detected )
{
// loop to handle events
while ( detected.hasMoreElements() ) {
// get next sequential WakeupCriterion
WakeupCriterion wakeupCriterion =
( WakeupCriterion ) detected.nextElement();
Outline
When theFig.
user4.27
presses keys
on the keyboard,
the behavior
Implementing
a
scheduler
calls method
position-checking
processStimulus
Behavior (part 3).
Line 78
Handle only those WakeupCriterions
Line 88 that are
related to the user pressing a
key on the keyboard
// handle if WakeupOnAWTEvent
if ( wakeupCriterion instanceof WakeupOnAWTEvent ) {
// ensure WakeupOnAWTEvent is KeyEvent.KEY_PRESSED
WakeupOnAWTEvent awtEvent =
( WakeupOnAWTEvent ) wakeupCriterion;
AWTEvent[] event = awtEvent.getAWTEvent();
// check object position
checkPosition( event );
// re-register WakeupCriterion to respond to next
// key press
wakeupOn( wakeupCondition );
}
}
} // end method processStimulus
2002 Prentice Hall.
All rights reserved.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// check position of object in objectTransform TransformGroup
private void checkPosition( AWTEvent[] awtEvents )
{
Vector3f translate = new Vector3f();
Transform3D transform3d = new Transform3D();
// get Transform3D associated with objectTransform
objectTransform.getTransform( transform3d );
// get Transform3D's translation vector
transform3d.get( translate );
Outline
Utility
Fig. method
4.27 for
checking
the positionaof
Implementing
the 3Dposition-checking
object in the scene
Behavior (part 4).
Line 107
// handle all key presses in awtEvents
for ( int x = 0; x < awtEvents.length; x++ ) {
// handle if AWTEvent is KeyEvent
if ( awtEvents[ x ] instanceof KeyEvent ) {
KeyEvent keyEvent = (KeyEvent) awtEvents[ x ];
// handle if KeyEvent.KEY_PRESSED
if ( keyEvent.getID() == KeyEvent.KEY_PRESSED ) {
// if object position == goal coordinates
if ( atGoal( translate ) ) {
Transform3D shiftBack = new Transform3D();
// set translation to 8.0 on +z-axis
shiftBack.setTranslation(
new Vector3f( 0.0f, 0.0f, 8.0f ) );
// set Transform3D that determines view
// in SimpleUniverse
ViewingPlatform viewPlatform =
simpleUniverse.getViewingPlatform();
2002 Prentice Hall.
All rights reserved.
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
TransformGroup platformTransform =
viewPlatform.getViewPlatformTransform();
platformTransform.setTransform( shiftBack );
// render winner scene in SimpleUniverse
switchScene.setWhichChild( WINNER_SCENE );
}
Outline
Fig. 4.27
Implementing a
position-checking
Behavior (part 5).
}
} // end if KeyEvent
Lines 159-170
} // end for loop that handles key presses
} // end method checkPosition
// helper method returns true if current position is within
// goal boundry
private boolean atGoal( Vector3f currentPosition )
{
// calculate difference between current location and goal
float x = Math.abs( currentPosition.x - goalX );
float y = Math.abs( currentPosition.y - goalY );
float z = Math.abs( currentPosition.z - goalZ );
Utility method for
determining whether
the navigable shape
has reached its target
// return true if current position within sphereRadius of
// goal coordinates
return ( ( x < sphereRadius ) && ( y < sphereRadius ) &&
( z < sphereRadius ) );
}
}
2002 Prentice Hall.
All rights reserved.
Outline
Fig. 4.27
Implementing a
position-checking
Behavior (part 6).
2002 Prentice Hall.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ControlPanel1.java
// ControlPanel1 is a JPanel that contains Swing controls
// for manipulating a Java3DWorld1.
package com.deitel.advjhtp1.java3dgame;
// Java core packages
import java.awt.*;
import java.awt.event.*;
// Java extension packages
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
public class ControlPanel1 extends JPanel {
Outline
Fig. 4.28
Implementing Swing
controls for the
Create JPanel that contains
Java3DWorld1
controls for specifying the
(part 1).
number of obstacles on screen
Line 15
Line 23
private static final int CONTAINER_WIDTH = 250;
private static final int CONTAINER_HEIGHT = 150;
private static final int NUMBER_OF_SHAPES = 20;
// JSliders control lighting color
private JSlider numberSlider;
private Java3DWorld1 java3DWorld1;
Declare JSlider to specify the
number of obstacles on screen
// ControlPanel constructor
public ControlPanel1( Java3DWorld1 tempJ3DWorld )
{
java3DWorld1 = tempJ3DWorld;
// assemble lighting color control panel
JPanel colorPanel = new JPanel(
new FlowLayout( FlowLayout.LEFT, 15, 15 ) );
TitledBorder colorBorder =
2002 Prentice Hall.
All rights reserved.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
new TitledBorder( "How Many Shapes?" );
colorBorder.setTitleJustification( TitledBorder.CENTER );
colorPanel.setBorder( colorBorder );
JLabel numberLabel = new JLabel( "Number of Shapes" );
// create JSlider for adjusting number of flying shapes
numberSlider = new JSlider(
SwingConstants.HORIZONTAL, 1, NUMBER_OF_SHAPES, 1 );
numberSlider.setMajorTickSpacing( 4 );
numberSlider.setPaintTicks( true );
numberSlider.setPaintTrack( true );
numberSlider.setPaintLabels( true );
Fig. 4.28
Implementing Swing
controls for the
Java3DWorld1
(part 2).
Lines 53-62
When user accesses JSlider, update
the number of obstacles on screen
// create ChangeListener for JSliders
ChangeListener slideListener = new ChangeListener() {
// invoked when slider has been accessed
public void stateChanged( ChangeEvent event )
{
java3DWorld1.switchScene( numberSlider.getValue(),
NUMBER_OF_SHAPES );
}
}; // end anonymous inner class
// add listener to sliders
numberSlider.addChangeListener( slideListener );
// add lighting
colorPanel.add(
colorPanel.add(
add( colorPanel
color control components to colorPanel
numberLabel );
numberSlider );
);
2002 Prentice Hall.
All rights reserved.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// set GridLayout
setLayout( new GridLayout( 2, 1, 0, 20 ) );
} // end ControlPanel1 constructor method
// return preferred dimensions of container
public Dimension getPreferredSize()
{
return new Dimension( CONTAINER_WIDTH, CONTAINER_HEIGHT );
}
Outline
Fig. 4.28
Implementing Swing
controls for the
Java3DWorld1
(part 3).
// return minimum size of container
public Dimension getMinimumSize()
{
return getPreferredSize();
}
}
2002 Prentice Hall.
All rights reserved.