mlab2@kuhub.cc.ukans.edu (12/01/90)
Graf3D and What I Discovered Therein - part3 Well, I must say I'm posting this all a piece at a time. I don't have any of this written all out in one place. So if you want this, here it is, capture it. Also, I'll say again that I am not an expert with this at all. I have only experimented with it for a couple of months back when I was first learning to program the Mac (and learning Pascal too). So, feel free to post corrections of any of my errors and take my 'tutorial' as a starting point only. I just saw all the confusion about Graf3D and thought, "Well, I could explain a little bit of it." Drawing in 3D- As I may have hinted at before, all drawing is done 'wireframe' with Graf3D. You set up a group of 3D points and use Move3D, MoveTo3D, LineTo3D, etc. to display your drawing. I'm sure a guru could take the 2D equivalents of these screen points and create regions and paint them etc. For my own purposes, this would clearly have been too slow. So, how did I optimize Graf3D within the bounds allowed by Graf3D? Setting up your 3D points- Consider a simple cube. Counting up the vertices gives us 8 points. If we set up an array [0..7] of Point3D, we can initialize all these points and then repeatedly connect-the-dots. Calls to Yaw, Pitch, etc, and moving the 'eye' around in space will give us different views of this simple cube. The scale you use for the cube is fairly arbitrary. Lets use a cube with a side of length 100 for simplicity. In your initialization routine you caould call this: var cubeVertices: array [0..7] of Point3D; begin SetPoint3D(cubeVertices[0], 0, 0, 0); SetPoint3D(cubevertices[1], 100, 0, 0); SetPoint3D(cubeVertices[2], 100, 100, 0); SetPoint3D(cubeVertices[3], 0, 100, 0); SetPoint3D(cubeVertices[4], 0, 0, 100); SetPoint3D(cubeVertices[5], 100, 0, 100); SetPoint3D(cubeVertices[6], 100, 100, 100); SetPoint3D(cubeVertices[7], 0, 100, 100); ... end; An alternate (and perhaps quicker) way of doing this would be to have set up an array of Fixed [0..7, 0..2]. This way, you never create the 3D points, but assign the x, y, and z coordinates of each verticee. MoveTo3D and LineTo3D (etc) expect you to pass the fixed x, y, and z coordinates anyway. Using Point3D's is convenient, but you'll still have to "dissect" the corrdinates out of these points when you call MoveTo3D, etc. A 'convenient' way around this hassle would be to create your own procedures: As an example: Long way: MoveTo3D(cubeVertices[i].x, cubeVertices[i].y, cubeVertices[i].z); A nice procedure: procedure MoveTo3DPt (thePoint: Point3D); begin MoveTo3D(thePoint.x, thePoint.y, thePoint.z); end; -now simply call- MoveTo3DPt(cubeVertices[i]); I think I'll use this second way here. (You could make a whole library of routines that translate 3D points, etc.) So, you've set up your 3D port (from part 2 of this little piece), and you've initialized the 8 vertices of your cube, - here is a simple loop to use the mouse to rotate the points from the perspective of the eye. var mousePt:Point; {A STANDARD QuickDraw point that is} {------} procedure MoveTo3DPt (thePoint: Point3D); begin MoveTo3D(thePoint.x, thePoint.y, thePoint.z); end; {------} procedure LineTo3DPt (thePoint: Point3D); begin LineTo3D(thePoint.x, thePoint.y, thePoint.z); end; {------} begin ... repeat GetMouse(mousePt); Roll((256 - mousePt.h) * 3276); {3276 is about 1/10 of a degree, thus on a 512 Mac screen, +/- 25 degrees is your roll velocity} origin.z:=origin.z+mousePt.v; {We'll use the vertical position of the mouse to change the z coordinate of the origin (see part 2 for origin} gPort3D.eye:=origin; {Now we set the 'eye' of the 3D port to the new location of the var origin} FillRect(gPort3D.ViewRect, black); {Erase other points drawn} MoveTo3DPt(cubeVertices[0]); LineTo3DPt(cubeVertices[1]); LineTo3DPt(cubeVertices[2]); LineTo3DPt(cubeVertices[3]); LineTo3DPt(cubeVertices[0]); {We have just drawn the bottom of the cube} MoveTo3DPt(cubeVertices[4]); LineTo3DPt(cubeVertices[5]); LineTo3DPt(cubeVertices[6]); LineTo3DPt(cubeVertices[7]); LineTo3DPt(cubeVertices[4]); {We have now drawn the top of the cube, now to connect the top & bot} MoveTo3DPt(cubeVertices[0]); LineTo3DPt(cubeVertices[4]); MoveTo3DPt(cubeVertices[1]); LineTo3DPt(cubeVertices[5]); MoveTo3DPt(cubeVertices[2]); LineTo3DPt(cubeVertices[6]); MoveTo3DPt(cubeVertices[3]); LineTo3DPt(cubeVertices[7]); until button; {clicking the mouse button exits the program} end. So, try that one out. It's bits from a little test program I wrote. You'll also have to have part 2 of my posts to do the port setting up stuff. I'm hoping to that this is enough to get most everyone started. I could post more, but mostly program specific stuff. I will say that my biggest annoyance with Graf3D was that it is difficult (impossible?) to actually rotate both the cube AND the eye at the same time. As I recall, rotation calls to Yaw and the like actually rotate space about the point (0,0,0). If you have, for example, two cubes located in differnt places in space, calls to pitch will rotate BOTH cubes teeter-totter like about the point (0,0,0) of space. I could only imagine setting up SEPERATE 3D grafports for each cube and copybitting the two (via XOr) to a single 2D grafport on the screen. Slow. If anyone has any questions, post them to the net (or mail me I suppose). I can't reply to mail sent to me, but I could post more on a particular aspect of Graf3D to the net. One person mailed me about rotating 3D waveforms and displaying them. That would probably be fairly easy to do given the code I've posted. Define the waveform as a chain of 3D points stretching across the point (0,0,0). Move the eye out away from (0,0,0) but look TOWARD the center of space. Yaws and Rolls will gimble the waveform about. Redraw (point to point) the waveform after each transformation. You can scale the waveform by simply moving the eye of the 3D port toward and away from the center of space. Cheerio. I'll check the net for requests. john calhoun
oster@well.sf.ca.us (David Phillip Oster) (12/08/90)
In article <27177.2756a557@kuhub.cc.ukans.edu> mlab2@kuhub.cc.ukans.edu writes:
_>I could post more, but mostly program specific stuff. I will say that my
_>biggest annoyance with Graf3D was that it is difficult (impossible?) to
_>actually rotate both the cube AND the eye at the same time. As I recall,
_>rotation calls to Yaw and the like actually rotate space about the point
_>(0,0,0). If you have, for example, two cubes located in differnt places in
_>space, calls to pitch will rotate BOTH cubes teeter-totter like about the point
_>(0,0,0) of space. I could only imagine setting up SEPERATE 3D grafports for
_>each cube and copybitting the two (via XOr) to a single 2D grafport on the
_>screen. Slow.
There is nothing magic about what Graf3D is doing. It is just doing simple
matrix multiplication to do the transformation of the coordinates of the
3d wireframe cube to its final position. Any elementary book on computer
graphics gfoes into this process in excuricating detail. I like "Interactive
Computer Graphics" by Giloi. Just make sure to use the Fract trig routines
(inside Mac vol 4) and right your matrix mutiply routine to use Fixed
numbers.
A cute trick: given a quadrilateral in 3-space, do your Line3To()s inside
BeginRegion(), EndRegion()s. Then, uyou can do a PaintRegion to actually
draw the face in "three space". Regions work better than Polygons for this,
since pin a polygon, the pen hangs down, but in a region, the pen stays
within the region.
--
-- David Phillip Oster - At least the government doesn't make death worse.
-- oster@well.sf.ca.us = {backbone}!well!oster