views:

192

answers:

4

I was wondering if there was any tutorial that introduces 3D Graphics theory while showing relevant code, without using OpenGL or DirectX or something. I'm very comfortable with engineering math (I'm an A/V DSP student, so I work with a lot of math all the time).

Most of the tutorials I see either show me the same old matrix translation/rotation examples, along with a discussion on projections and show me using similar triangles how projections work or assume you know everything about 3D or just use a bunch of OpenGL primitives. I've ordered a book (Interactive Computer Graphics: A Top-Down Approach) on the topic but I'd like to get started right now.

I'd really like something that just worked with an SDL surface or a Java Graphics2D object and just used matrix math to render everything. I was hoping to be able to do some simple stuff, like rendering some simple shapes before the book arrived. Ideally something that introduced topics and gave coded examples on how they worked.

EDIT: All the answers were great, but I just loved the code. Exactly what I was looking for, even if it was in Pascal ;)

+2  A: 

One way to avoid OpenGL and DirectX solutions is to look for older graphics books that predate OpenGL and DirectX - something from the mid 80's for example (OpenGL may have been around, but not in widespread use on the PC). Be prepared to translate from GWBasic or the like. ;>

Or, just pick up a trigonometry textbook. Projecting 3D coords to 2D is nothing but trig and is sometimes covered as an advanced topic in trig books.

dthorpe
What about filling shapes and stuff?
GrayGnome
Mid 80s is a bit too far back (probably far enough that any code examples wouldn't be in C++). I have a few game programming books from the late 90s that discuss software 3D in detail - data structures, geometry, rendering modes, optimization, etc. (The first consumer 3D hardware accelerators didn't hit the mass market until 1996-ish).
Seth
Look for SIGGRAPH papers. They cover a lot of stuff like that.
dthorpe
@Seth: Mid 80's worked for me. I was there! :P
dthorpe
Actually linear algebra helps to simplify the trig stuff :)
Hamish Grubijan
@Hamish - I agree. Trig is never used except for defining a rotation by a specific angle (usually a rotation matrix). If you see trig for any other use, it's probably not optimal code.
phkahler
Agreed, linear algebra brings in matrix operations which enable macro scale ops on 3D coords, but tutorials and fundamentals on the underlying math usually focus on the trig and bring matrices in only as an optimization later after the core concepts are established.
dthorpe
+2  A: 

This series of articles helped me understand the basics of 3D graphics: Exploring 3D in Flash. The articles are in Actionscript/ECMAScript in a Flash DOM environment but it can easily be translated to other environments.

I personally followed the articles by translating the examples to Tcl/Tk drawing on a Tk canvas. You could try Perl/Tk or TkInter instead or a much closer translation is to javascript using HTML5 canvas or something like Raphael to do the drawing. By the end of the article you will have a simple but usable 3D API.

slebetman
+4  A: 

Buried out some old pascal source :D About 14 years ago, I used it for displaying very simple 3d objects. xrot, yrot, zrot are to rotate points ([x,y,z] multiplied by rotation matrix). And I used a very simple 3d-to-2d-transformation, based on vanishing-point projection with the vanishing-point at the middle of the screen. As an example, there is a vertex array defined. You also have to add a trigons array.

const depth = 1500;
      deg = pi / 180;

      { some vertices for a dice :) }
      vertices:array[0..23] of real= (50, 50, 50,       { 0}
                                 -50, 50, 50,       { 1}
                                  50,-50, 50,       { 2}
                                 -50,-50, 50,       { 3}
                                  50, 50,-50,       { 4}
                                 -50, 50,-50,       { 5}
                                  50,-50,-50,       { 6}
                                 -50,-50,-50,       { 7}
                                  );

{ transform 3d coordinates to pixel coordinates }
procedure 3d_to_2d(x, y, z : real; var px, py : longint);
 var k:real;
begin
 k:=((depth shr 1)+z)/depth;
 px:=(getmaxx shr 1)+trunc(x*k);      { getmaxx is the width of the screen }
 py:=(getmaxy shr 1)+trunc(y*k);      { getmaxy is the height of the screen }
end;

{ rotate around the x axis by rx degrees }
procedure xrot(var x,y,z:real;rx:integer);
 var x1,y1,z1:real;
begin
 y1:=(y * cos(rx * deg))+(z* (sin(rx * deg)));
 z1:=(-y* sin(rx * deg))+(z* (cos(rx * deg)));
 y:=y1; z:=z1;
end;

{ rotate around the y axis by ry degrees }
procedure yrot(var x,y,z:real;ry:integer);
 var x1,y1,z1:real;
begin
 x1:=(x * cos(ry * deg))+(z*(sin(ry * deg)));
 z1:=(-x * sin(ry * deg))+(z*(cos(ry * deg)));
 x:=x1; z:=z1;
end;

{ rotate around the z axis by rz degrees }
procedure zrot(var x,y,z:real; rz:integer);
 var x1,y1,z1:real;
begin
 x1:=(x* cos(rz * deg))+(y*(sin(rz * deg)));
 y1:=(-x* sin(rz * deg))+(y*(cos(rz * deg)));
 x:=x1; y:=y1;
end;

For filled trigons, I used a friend's function, which draws the shape using horizontal lines (Hline(x,y,width, color)):

    TYPE pt=RECORD x,y:LongInt;END;  

PROCEDURE Tri(P:ARRAY OF pt;co:BYTE);
VAR q,w:INTEGER;
    S:pt;
    f12,f13,f23:LongInt;
    s1,s2:LongInt;


BEGIN

  IF p[0].y>p[2].y THEN BEGIN s:=p[0];p[0]:=p[2];p[2]:=s;END; { sort the points }
  IF p[0].y>p[1].y THEN BEGIN s:=p[0];p[0]:=p[1];p[1]:=s;END;
  IF p[1].y>p[2].y THEN BEGIN s:=p[1];p[1]:=p[2];p[2]:=s;END;

  q:=(p[0].y-p[1].y); { y distance between point 0 and 1 }
  IF q<>0 THEN f12:=LongInt((p[0].x-p[1].x) shl 6) DIV q ELSE f12:=0;

  q:=(p[0].y-p[2].y);
  IF q<>0 THEN f13:=LongInt((p[0].x-p[2].x) shl 6) DIV q ELSE f13:=0;

  q:=(p[1].y-p[2].y);
  IF q<>0 THEN f23:=LongInt((p[1].x-p[2].x) shl 6) DIV q ELSE f23:=0;

  s1:=p[0].x shl 6;s2:=s1;
  FOR q:=p[0].y TO p[1].y DO
  BEGIN
    Hline(s1 shr 6,s2 shr 6,q,co);
    s1:=s1+f12;
    s2:=s2+f13;
  END;
  s1:=p[2].x shl 6;s2:=s1;
  FOR q:=p[2].y DOWNTO p[1].y DO
  BEGIN
    Hline(s1 shr 6,s2 shr 6,q,co);
    s1:=s1-f23;
    s2:=s2-f13;
  END;
END;
terabaud
+1 for pascal :D
Seth
+4  A: 

Get this book

or at least borrow it from your nearest university library.

Computer graphics, principles and practice


It's a few years old now, but it was (before the programmable shader revolution) considered the graphics bible. You can probably skip a lot of the first couple of chapters about input methods and palletized displays, but pretty much everything else has stood up exceptionally well.

kibibu
It's one of 2 graphics books I keep (the other has gone missing) and it's thicker than a bible :-) Can't go wrong here.
phkahler