Thread: FAQ: Graphics Math

  1. #1
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94

    Cool FAQ: Graphics Math

    Hey guys,

    this is more of a meth question and less of c, but after searching google for a long time I wasn't getting aynwhere.

    Basically, I would like to render a 3d wireframe on the screen, WITHOUT LIBRARIES. I want to hack a few functions to draw lines, then use those, along with math, to make, for instance, a grid-plane that I can 'rotate' around, and have the lines stay in perspective.

    so really there are two questions here:

    1) (main) How can I use "transformation matrices" to move around this grid and keep the lines correct?

    2) (insignificant) How can I stick a single pixel on the screen?

    I'm not really looking for straight answers, but perhaps some article people might have seen over the years.

    Thanks again,
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Well this is a nice long read
    http://thorkildsen.no/faqsys/
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Start here, it's a 4 part series...

    http://www.devmaster.net/articles/so...ring/part1.php
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  4. #4
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    Quote Originally Posted by Salem
    Well this is a nice long read
    http://thorkildsen.no/faqsys/
    Seems to be the opening page... didn't have a lot of time now, but tomorrow whould I read the whole site? Or is there just a good long peice....

    Thanks guys...

    And a func to turn on a pixel in c?
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  5. #5
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    After reading the devmaster article..... I understand the math but fail to see how to take an x,y,z point and, using perspective, make it on the screen. (other than by dropping z, and having the camera dead-center)

    I will read it again though, perhaps I missed something.....
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You divide by Z - or in the case of modern graphics you divide by W. This is the perspective projection.

    Before matrices were widely used this was the formula used for dividing by Z.

    Screen.x=(View.x*Dist_To_Plane)/(View.z+CenterScreen.x);
    Screen.y=(View.y*Dist_To_Plane)/(View.z+CenterScreen.y);

    But with matrices this can be done quite easily and it can also then be added into the graphics pipeline that already uses matrices quite heavily. The advantage is you don't have to change your projection function significantly to perspective project your vertices into screen space.

    You really need to buy a book on the mathematics of 3D graphics in order to understand how it all works.

    Translation is really just this:

    x+=distance_x;
    y+=distance_y;
    z+=distance_z;

    But because of the way we multiply or concatenate matrices a 4x4 homogneous matrix works very well for this:

    [1,0,0,0]
    [0,1,0,0]
    [0,0,1,0]
    [distance_x,distance_y,distance_z,1]

    A simple concatenation function (and not by any means the fastest) for a 4x4 matrix. Matrix is assumed to be a 4x4 array - again not the best way.


    Code:
    void MatMultiply(float mat1[4][4],float mat2[4][4],float result[4][4])
    {
      for (int i=0;i<4;i++)
      {
    	for (int j=0;j<4;j++)
    	{
    	  result[i][j]=0.0f;
    	  for (int k=0;k<4;k++)
    	  {
    		result[i][j]+=mat1[i][k]*mat2[k][j];
    	  }
    	}
      }
    }

    And a simple world transform function.

    Code:
    void WorldTransform(vertex *vtxs,int numvtxs,float wm[4][4])
    {
      for (int i=0;i<numvtxs;i++)
      {
    	float lx=vtxs[i].model.x;
    	float ly=vtxs[i].model.y;
    	float lz=vtsx[i].model.z;
     
    	float wx,wy,wz=0.0f;
     
    	wx=lx*wm[0][0]+ly*wm[1][0]+lz*wm[2][0]+wm[3][0];
    	wy=ly*wm[0][1]+ly*wm[1][1]+lz*wm[2][1]+wm[3][1];
    	wz=lz*wm[0][2]+ly*wm[1][2]+lz*wm[2][2]+wm[3][2];
    	vtxs[i].world.x=wx;
    	vtxs[i].world.y=wy;
    	vtxs[i].world.z=wz;
       }
    }
    But thankfully in DirectX you don't need to worry about all of this because it is done for you. No more tracking of model, world, view, and screen vertexes/coordinates. But the above code is from a software 3D engine I wrote quite some time ago.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > Seems to be the opening page
    Yeah, click the mathematics link for actual tutorials
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    Salem, that site will keep me busy for the next 11 hours....

    OK bubba, I did your example. I finally saw that it works, and how, however it was in the article you previously sent me as x=D*X'/z... and D was a constant they showed how to get: 1/tan(theta). I figured theta was the angle to look at... but actually, as you posted, it's the distance from the plane.

    That's cool.... but I was hoping to figure out how to make an x,y,z point become and x,y, but showing the peices behind the front at an angle, for instance up and to the right maybe, not just expanding sideways in the back. Do I do this with the rotation peice you showed me? Or am I paddling up the wrong creek?

    Thanks guys,
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  9. #9
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    You need to first perform all the rotations and translations in 3D, then project the resulting vertices on to the projection plane.

  10. #10
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    so... say I have 8 points that make a box. I rotate the box sideways, then when I use the formula from about to get the 2-D points, it works?

    I'l hack that up real quick and see if i can get it to work.

    Thanks
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  11. #11
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    Ok, i'm having a hard time conceptualtizing this. I'mm trying to just make a wireframe box rotate. So I can draw one box... but getting the next point by a 2-degree rotation is hard.

    So, I was wondering, does anyone know of any tutorials with example code that show how to do this? If I could just see someone else's code, I could figure it out. I've just never seen how these things are done in the "real world" (ie, not some little dude like me trying to do a big math thing.)

    Thanks again you guys,
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You are confused as to what is happening.

    First all graphics in 3D are centered around 0,0,0. Every object is centered around 0,0,0 in model space or at least should be or weird things begin to happen. Since you want to always see your 2D wireframe box set the z coordinates to something greater than or equal to 1.0f, but greater than 1.0f is your best bet.

    So imagine a universe. A universe is made of planets. The sun is just another very bright planet. All planets have their center at 0,0,0 in their model space. But you want to transform them to world space. So if you want your model to rotate in model space you must rotate first and then translate. If you translate first and then rotate your rotation will be in world space or will make the planet orbit the sun.

    All models start in model space. They are then transformed to world space. Then to camera/view space, then to clip space, then to screen space.

    It truly is impossible for me to explain 3D mathematics, matrix concatenation, and matrix transformation in one post. I would suggest purchasing a book about 3D to start you on your way. I could write a huge post here with all kinds of code, but it would only confuse the heck out of you. Get a book.
    Last edited by VirtualAce; 09-29-2004 at 11:48 PM.

  13. #13
    Registered User crepincdotcom's Avatar
    Join Date
    Oct 2003
    Posts
    94
    OK, I will get a book. But, about centering 0,0,0: I first tryed that a while ago, and what came out was sorts of strange. But probably my fault. So, can you have negative values in the 3d-2d conversion? Ie, is 5,5,5 the same as 5,5,-5? It shouldn't be, I had trouble with that. So, basically, if I just make a box like 5,5,5 5,-5,5 -5,-5,5, etc for all 8 points, that should work?

    Thanks agian,
    -Jack C
    jack {at} crepinc.com
    http://www.crepinc.com

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    This depends on your coordinate system. For all of my systems thus far I use this:

    -X is left.
    +X is right.
    -Y is up.
    +Y is down.
    -Z is toward the camera.
    +Z is away from the camera.

    So a 2D 20x20 unit box that lies 1.0 z unit from the camera has the following vertexes wound in counterclockwise rotation. I say unit because these values must be appropriate for the system of measurement you are using. For now let's say that all units are pixels.

    Vertex 0.......-20,-20,1
    Vertex 1........20,-20,1
    Vertex 2........-20,20,1
    Vertex 3........20,20,1

    Okay that is the front face. Now a 3D cube is just a front and a back face connected by 4 lines - which then create 4 more faces. So create the backface. Let's say it is 21 units away from the camera, thus giving our cube a width of 20, height of 20, and depth of 20.

    Vertex 4.....-20,-20,21
    Vertex 5.....20,-20,21
    Vertex 6.....-20,20,21
    Vertex 7.....20,20,21

    Okay you now have all the vertexes needed for a 6 sided 3D cube. The only thing left to do is create the indices or indexes for the cube. Indexes allow you to specify vertex numbers that make up triangles. So each triangle will have 3 indexes. For instance let's triangulate the front face in a counter-clockwise fashion.

    Triangle 1
    Vertex 0
    Vertex 1
    Vertex 2

    So the indices for triangle 1 are 0,1,2

    Triangle 2

    Vertex 1
    Vertex 3
    Vertex 2

    Indices: 1,3,2

    So your first 2 sets of indexes for the front face are:

    0,1,2
    1,3,2

    Notice that you can specify these vertexes in any order as long as they proceed counterclockwise around the triangle when viewed from the front if your culling mode is counter-clockwise culling else you must specify vertices in clockwise order.

    As you will notice indexing into the vertex data is much more efficient. In this picture alone you can see that these triangles share vertices 1 and 2 but we only declare them once. This means that you index array will be larger than your vertex array, but indices are integers and vertexes are normally floats - 3 of them to be exact. Indexing saves a lot of memory.

    Also not that when you specify a triangle you need not specify the closing leg. For instance specifying 0,1,2 to Direct3D will cause a line to be drawn from 0 to 1, 1 to 2, and 2 to 0. You need not specify 2,0 in your index array. Most APIs automatically close the triangle for you so you only need to specify 3 indexes per triangle. Specifying 0,1,2 is much more effienct than doing this:

    0,1
    1,2
    2,0

    So instead of specifying six indexes per triangle you can specify three.
    Last edited by VirtualAce; 10-04-2004 at 11:25 AM.

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I omitted the texture coords from my first picture. Here is another picture with the texture coords.

    They are specified in (u,v) format where u is the horizontal and v is the vertical.

    They are specified in range 0.0f to 1.0f - which means that your texture coords are independent of texture size. If you specify .50f,.50f on a 100x100 texture it will be 50,50. If you specify .50f,.50f on a 1000x1000 texture it will be 500x500. Notice both correspond to the center of the texture regardless of size. These are called normalized texture coordinates since they always fall in the range 0.0f to 1.0f.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Wiki FAQ
    By dwks in forum A Brief History of Cprogramming.com
    Replies: 192
    Last Post: 04-29-2008, 01:17 PM
  2. an easy, portable, python accessible graphics math library
    By ichijoji in forum Game Programming
    Replies: 2
    Last Post: 12-07-2006, 12:10 AM
  3. Beginning Game Programming Type Books
    By bumfluff in forum Game Programming
    Replies: 36
    Last Post: 09-13-2006, 04:15 PM
  4. how to use operator+() in this code?
    By barlas in forum C++ Programming
    Replies: 10
    Last Post: 07-09-2005, 07:22 PM
  5. Min Math level req for 3d graphics?
    By EvBladeRunnervE in forum Game Programming
    Replies: 12
    Last Post: 02-24-2003, 10:32 PM