Enter the third dimension

Use a Swing component to explore three-dimensional computer graphics

1 2 3 4 Page 4
Page 4 of 4
 

private void clip (Graphics g, double x1, double y1, double z1, double x2, double y2, double z2) { int c, c1, c2; double t, x = 0.0, y = 0.0, z = 0.0;

c1 = code (x1, y1, z1); c2 = code (x2, y2, z2);

while (c1 != 0 || c2 != 0) { if ((c1 & c2) != 0) return;

c = c1; if (c == 0) c = c2;

if ((c & LEFT) != 0) { t = (z1 + x1) / ((x1 - x2) - (z2 - z1)); z = t * (z2 - z1) + z1; x = -z; y = t * (y2 - y1) + y1; } else if ((c & RIGHT) != 0) { t = (z1 - x1) / ((x2 - x1) - (z2 - z1)); z = t * (z2 - z1) + z1; x = z; y = t * (y2 - y1) + y1; } else if ((c & BOTTOM) != 0) { t = (z1 + y1) / ((y1 - y2) - (z2 - z1)); z = t * (z2 - z1) + z1; x = t * (x2 - x1) + x1; y = -z; } else if ((c & TOP) != 0) { t = (z1 - y1) / ((y2 - y1) - (z2 - z1)); z = t * (z2 - z1) + z1; x = t * (x2 - x1) + x1; y = z; }

if (c == c1) { x1 = x; y1 = y; z1 = z; c1 = code (x, y, z); } else { x2 = x; y2 = y;

z2 = z; c2 = code (x, y, z); } }

showLine (g, x1, y1, z1, x2, y2, z2); }

private int code (double x, double y, double z) { int result = 0;

if (x < -z) result = LEFT;

if (x > z) result |= RIGHT;

if (y < -z) result |= BOTTOM;

if (y > z) result |= TOP;

return result; }

Caution
Be careful when reading my textbook's 3D-clipping algorithm—it contains a bug. This bug and a solution are revealed by You-Dong Liang and Brian A Barsky in "A New Concept and Method for Line Clipping" (ACMTransactions on Graphics, Vol. 3, No. 1, January 1984). I employ their solution in my clipping code.

Projection onto a 2D screen

Subsequent to the clipping algorithm calculating the endpoints of the visible portion of a line, this line can be projected onto the 2D display screen—the final step in viewing a world. Although Panel3D's projection code requires clipping coordinates, it's helpful to think about projection in terms of eye coordinates. The following matrix operation converts clipping coordinates back to eye coordinates:

 [xe ye ze 1] = [xc yc zc 1] [S/D  0    0    0]
                            [0    S/D  0    0]
                            [0    0    1    0]
                            [0    0    0    1]

Projecting eye points—world points located in the eye coordinate system—onto the 2D display screen is accomplished by dividing each point's x and y values by its z value. For example, assume that the clipping algorithm has accepted eye point P, one of a line's endpoints. After dividing its x and y values by its z value, the projection of P—point P'—appears on the screen, as illustrated in Figure 12.

Figure 12. The projection of point P to point P' on the 2D display screen

The screen coordinates of the projected point, P', are obtained from observing a pair of similar triangles. In Figure 13's Ye/Ze plane, these similar triangles are OQ'P' and OQP, establishing the ys/D = ye/ze relation. For the Xe/Ze plane, similar triangles would establish xs/D = xe/ze. Rewriting these relations and dividing by half the screen size yields xs = Dxe/Sze and ys = Dye/Sze.

Figure 13. The details of projection for the Ye/Ze plane. Click on thumbnail to view full-sized image.

The xs and ys values are fractions of displacement across the screen. Each value is useless until it is converted to a screen coordinate. This conversion is accomplished by multiplying the value by half the screen's size (in the appropriate direction) and adding the result to the appropriate screen center value.

In keeping with textbook conventions, I've introduced the concept of a view-port (which defaults to the entire screen) into Panel3D via a private void setViewport(int x1, int y1, int x2, int y2) method, variables vsx and vsy (which contain half the size of the view-port), and variables vcx and vcy (which contain the center of the view-port):

 

private void setViewport (int x1, int y1, int x2, int y2) { height = y2-y1+1;

double vxl = x1; double vyb = y1; double vxr = x2; double vyt = y2;

vcx = (vxl+vxr)/2; vcy = (vyb+vyt)/2;

vsx = (vxr-vxl)/2; vsy = (vyt-vyb)/2; }

Taking these variables into consideration, xs = (Dxe/Sze)vsx+vcx and ys = (Dye/Sze)vsy+vcy return the appropriate view-port coordinates, which are basically the 3D panel's coordinates. For the equivalent clipping coordinates, these relations are expressed as xs = (xc/zc)vsx+vcx and ys = (yc/zc)vsy+vcy.

Because Panel3D's perspective() method is called to establish the D/S ratio prior to lineto() calling clip(), the latter clipping coordinates are used by the following private void showLine(Graphics g, double xc1, double yc1, double zc1, double xc2, double yc2, double zc2) method to carry out the projection:

 

private void showLine (Graphics g, double xc1, double yc1, double zc1, double xc2, double yc2, double zc2) { int xs1 = (int) ((xc1/zc1)*vsx+vcx); int ys1 = (int) ((yc1/zc1)*vsy+vcy);

int xs2 = (int) ((xc2/zc2)*vsx+vcx); int ys2 = (int) ((yc2/zc2)*vsy+vcy);

g.drawLine (xs1, height-ys1, xs2, height-ys2); }

The showLine() method subtracts each of the values in the ys1 and ys2 variables from the view-port's height variable because the values in ys1 and ys2 assume a screen where the (0, 0) origin locates in the lower-left corner. In contrast, a Java component places this origin in the upper-left corner.

Conclusion

Because 3D computer graphics theory can be hard to grasp, I hope this article's Panel3D component, Demo3D applet, and component-based 3D graphics tutorial have helped to simplify this fascinating topic. In the future, I'll expand the component and the applet to illustrate additional 3D graphics concepts.

For now, however, I have some homework for you: Create additional model files and make them accessible to Demo3D via appropriate buttons. Also, implement a checkbox for hiding/showing the coordinate axes.

Jeff Friesen is a freelance software developer and educator specializing in C, C++, and Java technology.

Learn more about this topic

1 2 3 4 Page 4
Page 4 of 4