Heck I'm pretty proud of myself, a rotating cube ! now some more depth...
Started by Afterlife, Jul 16 2001 02:25 AM
8 replies to this topic
#1 Members  Reputation: 122
Posted 16 July 2001  02:25 AM
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[i][j].y,polygons[i][j].z,i,j);
...
void flatten(float x, float y, float z, short i, short j)
{
poly2d[i][j].x=x; /*See? No real depth yet...*/
poly2d[i][j].y=y;
}
Here''s how I draw the cube :
for(i=0;i<8&&!key[KEY_ESC];i++)
{line(buffer,320+poly2d[i][0].x,240+poly2d[i][0].y,320+poly2d[i][1].x,240+poly2d[i][1].y,makecol(255,255,255));
line(buffer,320+poly2d[i][1].x,240+poly2d[i][1].y,320+poly2d[i][2].x,240+poly2d[i][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[i][j].x=40*x/z;
poly2d[i][j].y=(40*y/z);}
else
{poly2d[i][j].x=x;
poly2d[i][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..
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[i][j].y,polygons[i][j].z,i,j);
...
void flatten(float x, float y, float z, short i, short j)
{
poly2d[i][j].x=x; /*See? No real depth yet...*/
poly2d[i][j].y=y;
}
Here''s how I draw the cube :
for(i=0;i<8&&!key[KEY_ESC];i++)
{line(buffer,320+poly2d[i][0].x,240+poly2d[i][0].y,320+poly2d[i][1].x,240+poly2d[i][1].y,makecol(255,255,255));
line(buffer,320+poly2d[i][1].x,240+poly2d[i][1].y,320+poly2d[i][2].x,240+poly2d[i][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[i][j].x=40*x/z;
poly2d[i][j].y=(40*y/z);}
else
{poly2d[i][j].x=x;
poly2d[i][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..
Sponsor:
#2 Members  Reputation: 150
Posted 18 July 2001  06:57 AM
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!"

Vash the Stampede
"Love & Peace!"
#3 Staff Emeritus  Reputation: 2076
Posted 18 July 2001  07:23 AM
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 nonzero values of z, your vertices'' x and ycoordinates 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
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.
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

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.
#4 Members  Reputation: 122
Posted 18 July 2001  08:23 AM
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 .
#5 Staff Emeritus  Reputation: 2076
Posted 18 July 2001  09:16 AM
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:

should be replaced by the lines:

and cube_position should be declared as:

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
#6 Members  Reputation: 122
Posted 18 July 2001  10:36 AM
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 "wiregraphics" till now..
#7 Staff Emeritus  Reputation: 2076
Posted 19 July 2001  01:09 PM
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 counterclockwise. I provide the 3D operation, using 3D points (x,y,z).
If you want I can even show you how to do Cosine shading... post back here.
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 counterclockwise. I provide the 3D operation, using 3D points (x,y,z).

If you want I can even show you how to do Cosine shading... post back here.
#8 Members  Reputation: 122
Posted 20 July 2001  01:28 AM
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? :

#9 Staff Emeritus  Reputation: 2076
Posted 23 July 2001  03:12 PM
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 Righthanded? At this point, the important bit is which way your positive zaxis points (from the monitor screen, which is your virtual camera). If your +ve z extended into the screen, then your normal vector''s zcoordinate 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:
instead of
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):
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), ^ (crossproduct) 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.
To determine if that''s the problem, simply switch the test from less than to greater than.ie:

instead of

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):

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), ^ (crossproduct) 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.