Heck I'm pretty proud of myself, a rotating cube ! now some more depth...

Started by
7 comments, last by Afterlife 22 years, 8 months ago
I made a cube that is constructed of twelve triangle polygons, but now I want more depth to it. And I''m having seriouse problems achieving it... defining the cube : typedef struct POINT{ float x,y,z; }POINT; POINT polygons[12][3]; /*3d*/ POINT poly2d[12][3]; I transform the 3d polygons into 2d like this : ... for(i=0;i<8;i++) for(j=0;j<3;j++) flatten(polygons[j].x,polygons[j].y,polygons[j].z,i,j); … void flatten(float x, float y, float z, short i, short j) { poly2d[j].x=x; /*See? No real depth yet…*/ poly2d[j].y=-y; } Here''s how I draw the cube : for(i=0;i<8&&!key[KEY_ESC];i++) {line(buffer,320+poly2d[0].x,240+poly2d[0].y,320+poly2d[1].x,240+poly2d[1].y,makecol(255,255,255)); line(buffer,320+poly2d[1].x,240+poly2d[1].y,320+poly2d[2].x,240+poly2d[2].y,makecol(255,255,255)); That just draws a line from triangles first point to second and from second to third so that the order goes like this : 2___1 | | 3 (so that it won''t go from point 1 to 3) Here are a few 4by4 rotation matrices that I use to rotate the cube around x and y axels : X Rotational Matrix M = [ 1 0 0 0 ] (A is 0.3, guess it''s not degrees, because 1 is way too big rotation) [ 0 cos A sin A 0 ] [ 0 -sin A cos A 0 ] [ 0 0 0 1 ] Y Rotational Matrix M = [ cos A 0 -sin A 0 ] [ 0 1 0 0 ] [ sin A 0 cos A 0 ] [ 0 0 0 1 ] // matrix A contains the result of scaling, rotational and translation matrices combined new_x = ( A.m[0][0] * x ) + ( A.m[1][0] * y ) + ( A.m[2][0] * z ) + A.m[3][0]; new_y = ( A.m[0][1] * x ) + ( A.m[1][1] * y ) + ( A.m[2][1] * z ) + A.m[3][1]; new_z = ( A.m[0][2] * x ) + ( A.m[1][2] * y ) + ( A.m[2][2] * z ) + A.m[3][2]; (I''m quoting straight from the website that helped me to do it) Now, this all works fine, I get a nice cube that rotates… But, further looks smaller so I add this to flatten function : void flatten(float x, float y, float z, short i, short j) { if(z!=0) {poly2d[j].x=40*x/z; poly2d[j].y=-(40*y/z);} else {poly2d[j].x=x; poly2d[j].y=-y;} } At first it looks just like I wanted it. When the cube is in the original position : .___ |\_/| ||.|| |/-\| .— But when I press the buttons to rotate it into either one of the directions it gets all strange. When I only rotate it a bit to one direction it looses most of its sides and only has two left with crossed lines on the other side. After that when I rotate it a bit to the other dir, it gets all tangled up, can''t explain how it looks after that. The possible values for x, y and z are -50/50 for x and y and 0/50 for z. Can you make any assumptions on what''s wrong with my code based on this information? I feel a great urge to be skilled in 3d programming, so please help me :p. Thanks.. </i>
------------------------------If there be no heaven,may there atleast be a hell.-------------------------------Afterlife-
Advertisement
Hmmm... My only suggestion would by to try making the bounds of the Z coordinates betwwwen -50/50 instead of 0/50. Sometimes centering an object helps rotate it. Probably not what your looking for though.

-----------------------------

Vash the Stampede

"Love & Peace!"
// Tojiart
A cursory glance through your code suggests the problem lies in your flatten() function, where you simulate depth. Because you divide by z for all non-zero values of z, your vertices'' x- and y-coordinates may be divided by negative values (you don''t check to bound z to zero after rotation, do you?) Some cosines/sines are negative, and the aggregation of them may result in negative z - or even x or y. It''s all a question of your axis of rotation.

Unfortunately, the "default" or "natural" axis of rotastion is the origin - (0,0,0) - meaning that portions of your cube may be rotated behind the camera! To solve that problem, define your cube''s vertices relative to an object axis. This object axis is located as some position relative to the camera, so the object position is added to all the vertices of the cube before projection (flatten()).

ie
  // it also helps to put your code in [source - /source] brackets.// note that all vertices are defined in abolute terms _around_ a (0,0,0) axisPOINT polygons[12][3] = {{1,1,1}, {1,1,-1}, {1,-1,-1},                         {1,-1,1), {1,1,1), {-1,1,1),                         ...};...// now before projection or rotation, move the vertices to the cube''s positionPOINT display_polygons[12][3];POINT cube_position[3] = { 0, 10, 25 };for( int i = 0; i < 12; i++ ){  for( int j = 0; j < 3; j++ )  {    display_polygons[i][j] = polygons[i][j] + cube_position[j];  }}// now flatten() and rotate to your hearts content...  


Hope that helps. For a more complete discussion on 3D theory, search for a recent article on 3D from the basics, or something like that.
Of course! Some z coords get negative when they are rotated thus making the x and y coordinates negative aswell resulting chaos . Thanks Olyseui! I''m never good at figuring these things out by my self... So all I need to do is add to the original coordinates so the z has no chanse of getting negative? I presume struct + struct is some sort of neat c++ trick to add the same struct components together? Or perhaps I could do what Blue Omega said and make z negative anyway and check if z is negative and multiply x and y coordinates with -z... Well I''m sure I''ll figure out something now. Thanks you two, I almost gave up hope that anyone would actually read that long long question .
------------------------------If there be no heaven,may there atleast be a hell.-------------------------------Afterlife-
quote:Original post by Afterlife
I presume struct + struct is some sort of neat c++ trick to add the same struct components together?


Whoops!

The line:
    display_polygons[i][j] = polygons[i][j] + cube_position[j];  


should be replaced by the lines:
        display_polygons[i][j].x = polygons[i][j].x + cube_position.x;display_polygons[i][j].y = polygons[i][j].y + cube_position.y;display_polygons[i][j].z = polygons[i][j].z + cube_position.z;  


and cube_position should be declared as:
  POINT3 cube_position;  


where POINT3 is a struct with x, y and z components.

My bad. If you're using C++, however, you can overload the addition operator( + ) so you can add your structs together (POINTS are simply 2D vectors). But maybe I should let you learn the language properly first...

Good luck. If you need more explanation, post (I'll monitor this thread for a few days).

Edited by - Oluseyi on July 18, 2001 4:20:35 PM
Got it now. When cube position had other values than 0 in x and y it looked a little funny in some angles, some of the points were too far. But when I used {0,0,50} and multiplied final x and y coords with 200, it had just the perfect depth and looked like an actual cube. Thanks for your help. Now I need to move on, perhaps add some textures... Hey, you wouldn''t happen to know a way to determin which polygon is on top so I wouldn''t draw the lower layers on the visible parts? I''ve been using "wire-graphics" till now..
------------------------------If there be no heaven,may there atleast be a hell.-------------------------------Afterlife-
Software 3D is my soft spot... too many "kids" running around with their DirectX and OpenGl that don''t know didly these days.

To determine whether a polygon is facing the screen/camera, take the cross product of two of it edges (adjacent edges require only 3 vertices - which make up a triangle anyway). The order of specifying your vertices must be consistent across all your polys: either clockwise or counter-clockwise. I provide the 3D operation, using 3D points (x,y,z).

  bool is_facing( POINT3 &vx1, POINT3 &vx2, POINT3 &vx3 ){// VECTOR3 is a 3D vector, which is identical to a 3D point, but semantics...  VECTOR3 v1 = vx1 - vx2;  // v1.x = vx1.x - vx2.x; etc  VECTOR3 v2 = vx2 - vx3;// This is C++ syntax, but you should be able to see the C equivalent:  VECTOR3 cp = VECTOR3( v1.y*v2.z - v1.z*v2.y, -(v1.x*v2.z - v1.z*v2.x), v1.x*v2.y - v1.y*v2.x ); //cross product  return( cp.z < 0 ); // if your +ve Z-axis heads _into_ the screen}  


If you want I can even show you how to do Cosine shading... post back here.
quote:
If you want I can even show you how to do Cosine shading... post back here.

Sure, that''d be great. And thanks for the previouse code, alltough I had some problems with it, it leaves out polygons, but the wrong ones. Can you see what I screwed up with this one? :
  /*calling the facing check function :*/if(facing_screen(polygon[0],polygon[1],polygon[2]))<br>/*draw it*/<br><br><br>/*The function :*/</font><br><br>BOOLEAN facing_screen(PO<font color="blue">INT</font> vect1,PO<font color="blue">INT</font> vect2,PO<font color="blue">INT</font> vect3)<br>{<br>PO<font color="blue">INT</font> v1;<br>PO<font color="blue">INT</font> v2;<br>PO<font color="blue">INT</font> crossvect;<br>v1.x = vect1.x - vect2.x;<br>v2.x = vect2.x - vect3.x;<br>v1.y = vect1.y - vect2.y;<br>v2.y = vect2.y - vect3.y;<br>v1.z = vect1.z - vect2.z;<br>v2.z = vect2.z - vect3.z;<br>crossvect.x = v1.y*v2.z - v1.z*v2.y;<br>crossvect.y = -(v1.x*v2.z - v1.z*v2.x);<br>crossvect.z = v1.x*v2.y - v1.y*v2.x;<br><font color="blue">return</font>(crossvect.z &lt; 0);<br>}<br>  </pre></font></td></tr></table></center><!–ENDSCRIPT–>     
------------------------------If there be no heaven,may there atleast be a hell.-------------------------------Afterlife-
If your backface culling (that''s the name of the method) function leaves out the wrong polygons, then my first hunch is that your test is backwards. How are your 3D axes set up? Left- or Right-handed? At this point, the important bit is which way your positive z-axis points (from the monitor screen, which is your virtual camera). If your +ve z extended into the screen, then your normal vector''s z-coordinate should be negative for the polygon to show (opposite directions). And vice versa.

To determine if that''s the problem, simply switch the test from less than to greater than.ie:
  return (crossvector.z > 0);  

instead of
  return (crossvector.z < 0);  


Now, the basics of Cosine Shading.

There are 2 types of light we consider in a simple 3D scene: ambient (or diffuse ) and specular . Ambient light is everywhere in the scene. It''s the "background" light that makes things visible and illuminates all objects the same (you can simulate a "dark" scene by having very low ambient lighting).

Specular lighting refers to the effects of "point sources" of light - closer, more direct source that reflect off surfaces in different amounts. Lambert''s Law states that the reflection of light from a perfectly diffusing surface varies as the cosine of the angle between the normal to the surface and the direction of the reflected ray. Thus, cosine shading.

Okay, enough theory. This all boils down to the proportion of the intensity of a point light source that is "reflected" by a surface for the eye to see is the cosine of the angle between the normal of the surface and the direction vector of the light. We know that the desired cosine can be obtained as the dot product of the normalized vectors. So:
Fraction of light intensity = dotp( surface_normal, light_dir_vector)

Say you had a ray of light in the direction l = (lx, ly, lz) with a magnitude L and RGB color values (lr, lg, lb). To determine the color of a white triangle (ambient lighting set to 0.2 so we can see something):
  vector pnorm = surf_norm(white_tri);// pnorm is already normalizedfloat spec = dotp(pnorm, l/L);white_tri.color = RGB(lr*spec, lg*spec, lb*spec) + RGB(0.2,0.2,0.2); // add ambient  


At this point I''d advocate C++ as your programming language if only because you can replace ugly functions like dotp(), etc with operators (symbols) like * (dot product), ^ (cross-product) and you can overload them so that you can add RGB values using +. Cleaner to read and understand, and very powerful.

Okay, I don''t check GameDev too often right now (I''m travelling this weekend, and moving once I get back), so email me if you have more questions you''d like me to answer.

Good luck.

This topic is closed to new replies.

Advertisement