Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Ruudje

Calculating normals

This topic is 5558 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ive got my 3ds loader to work, but I need to calculate the normals of faces and integrate that into my rendring function. here''s some code This function is wrong i think:
void file_3ds::calculate_normals(void)
{
        for(int i = 0; i < object->polygons_qty; i++)
        {
                object->normal.x = object->vertex[i].x + object->vertex[i+1].x + object->vertex[i+2].x;
                object->normal[i].y = object->vertex[i].y + object->vertex[i+1].y + object->vertex[i+2].y;
                object->normal[i].z = object->vertex[i].z + object->vertex[i+1].z + object->vertex[i+2].z;
        }
}
 
This is my rendering function. It uses the values from the above function, but im not sure it uses them correctly. One of these two (or both) are wrong:
void file_3ds::render(void)
{
    int l_index;

    glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
    for (l_index=0;l_index<object->polygons_qty;l_index++)
    {
        //----------------- FIRST VERTEX -----------------
        glNormal3f( object->normal[ object->polygon[l_index].a ].x,
                object->normal[ object->polygon[l_index].a ].y,
                object->normal[ object->polygon[l_index].a ].z
        );

        // Texture coordinates of the first vertex
        glTexCoord2f( object->mapcoord[ object->polygon[l_index].a ].u,
                      object->mapcoord[ object->polygon[l_index].a ].v);
        // Coordinates of the first vertex
        glVertex3f( object->vertex[ object->polygon[l_index].a ].x,
                    object->vertex[ object->polygon[l_index].a ].y,
                    object->vertex[ object->polygon[l_index].a ].z); //Vertex definition

        //----------------- SECOND VERTEX -----------------
        glNormal3f( object->normal[ object->polygon[l_index].b ].x,
                object->normal[ object->polygon[l_index].b ].y,
                object->normal[ object->polygon[l_index].b ].z
        );

        // Texture coordinates of the second vertex
        glTexCoord2f( object->mapcoord[ object->polygon[l_index].b ].u,
                      object->mapcoord[ object->polygon[l_index].b ].v);
        // Coordinates of the second vertex
        glVertex3f( object->vertex[ object->polygon[l_index].b ].x,
                    object->vertex[ object->polygon[l_index].b ].y,
                    object->vertex[ object->polygon[l_index].b ].z);

        //----------------- THIRD VERTEX -----------------
        glNormal3f( object->normal[ object->polygon[l_index].c ].x,
                object->normal[ object->polygon[l_index].c ].y,
                object->normal[ object->polygon[l_index].c ].z
        );

        // Texture coordinates of the third vertex
        glTexCoord2f( object->mapcoord[ object->polygon[l_index].c ].u,
                      object->mapcoord[ object->polygon[l_index].c ].v);
        // Coordinates of the Third vertex
        glVertex3f( object->vertex[ object->polygon[l_index].c ].x,
                    object->vertex[ object->polygon[l_index].c ].y,
                    object->vertex[ object->polygon[l_index].c ].z);
    }
    glEnd();
}
 
Note: my functions lack good commenting at the moment...

Share this post


Link to post
Share on other sites
Advertisement
According to an article ive found, this si the correct way to calculate the normals:


vector vec1;
vec1.x = object->vertex[object->polygon.b].x - object->vertex[object->polygon[i].a].x;
vec1.y = object->vertex[object->polygon[i].b].y - object->vertex[object->polygon[i].a].y;
vec1.z = object->vertex[object->polygon[i].b].z - object->vertex[object->polygon[i].a].z;

vector vec2;
vec2.x = object->vertex[object->polygon[i].c].x - object->vertex[object->polygon[i].a].x;
vec2.y = object->vertex[object->polygon[i].c].y - object->vertex[object->polygon[i].a].y;
vec2.z = object->vertex[object->polygon[i].c].z - object->vertex[object->polygon[i].a].z;

float x, y, z;
x = vec1.y * vec2.z - vec1.z * vec2.y;
y = vec1.z * vec2.x - vec1.x * vec2.z;
z = vec1.x * vec2.y - vec1.y * vec2.x;

float mag = sqrt(x*x + y*y + z*z);

object->normal[i].x = x / mag;
object->normal[i].y = y / mag;
object->normal[i].z = z / mag;


Ive also altered my render-function:

...
glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
for (i = 0; i < object->polygons_qty ; i++)
{
glNormal3f( object->normal[i].x,
object->normal[i].y,
object->normal[i].z
);

//----------------- FIRST VERTEX -----------------
...


This makes a lot of sense to me, but the object is still not drawn as it should be drawn...

Share this post


Link to post
Share on other sites
To check what''s wrong, disable lighting and draw your normal as line starting from one point of your polygon. Your algorithm looks ok for me : your normal is the dot product of 2 edges (vec1 and vec2) of the polygon. One thing to consider is the "sens" of the edge, maybe your normal points downward, that could be the reason why you see nothing. if it is the case, you should invert your normal, but I''mnot sur how to detect it.

Share this post


Link to post
Share on other sites
quote:
and draw your normal as line starting from one point of your polygon

This requieres a bit more explanation

glVertex3f(
object->vertex[object->polygon[l_index].c ].x,
object->vertex[ object->polygon[l_index].c ].y,
object->vertex[ object->polygon[l_index].c ].z);

glVertex3f(
object->vertex[object->polygon[l_index].c ].x+object->normal.x,
object->vertex[ object->polygon[l_index].c ].y+object->normal[i].y,
object->vertex[ object->polygon[l_index].c ].z+object->normal[i].z);

Share this post


Link to post
Share on other sites
quote:
Original post by MV
One thing to consider is the "sens" of the edge, maybe your normal points downward, that could be the reason why you see nothing. if it is the case, you should invert your normal, but I''mnot sur how to detect it.


The cross product you use to calculate your normal must "match" the face you decided to cull/the orientation of front faces (CW or CCW).

BTW, you can also use a small optimization for sqrt (search for inverse square root with Google, you''ll get quite a few links about that).




SaM3d!, a cross-platform API for 3d based on SDL and OpenGL.
The trouble is that things never get better, they just stay the same, only more so. -- (Terry Pratchett, Eric)

Share this post


Link to post
Share on other sites
Well here''s why I said never mind

My code was correct, BUT I discovered I was selecting the wrong normals to go with the faces... (The formula was wrong) It''s fixed now, but now I discovered I also need something called vertex normals since all my faces are 1 color each, so I dont have any smooth shading... Dunno how to do that yet...

Share this post


Link to post
Share on other sites
quote:
Original post by Ruudje
Dunno how to do that yet...

You can have "smooth shade" a face from 2 different ways :
- Modify the color of the vertex (let''s say vertex A is red, B is blue and C is green) using glColor.
- Have a different normal for each of the vertex. A light has to be set for this solution to work. It''s the nicest solution, cause it''s near from real lighting model. This solution can''t work with your algorithm cause all the normal of your face are the same. You should compute your normal another way, using the average of all the face''s normals connected to each vertex for example.

Share this post


Link to post
Share on other sites
Ignore all of the above code for a sec, and take a look at my current code


// Structure for holding a vertex
typedef struct
{
float x, y, z;
float norm[3];
}vertex;

// Structure for holding a face
typedef struct
{
unsigned short a, b, c;
float norm[3]; // Unused at present
}face;

...

void file_3ds::calculate_normals(void)
{
// Loop through all faces
for(int i = 0; i < object->polygons_qty; i++)
{
vector vec1;
vec1.x = object->vertex[object->face.b].x - object->vertex[object->face[i].a].x;
vec1.y = object->vertex[object->face[i].b].y - object->vertex[object->face[i].a].y;
vec1.z = object->vertex[object->face[i].b].z - object->vertex[object->face[i].a].z;

vector vec2;
vec2.x = object->vertex[object->face[i].c].x - object->vertex[object->face[i].a].x;
vec2.y = object->vertex[object->face[i].c].y - object->vertex[object->face[i].a].y;
vec2.z = object->vertex[object->face[i].c].z - object->vertex[object->face[i].a].z;

float x, y, z;
x = vec1.y * vec2.z - vec1.z * vec2.y;
y = vec1.z * vec2.x - vec1.x * vec2.z;
z = vec1.x * vec2.y - vec1.y * vec2.x;

float mag = sqrt(x*x + y*y + z*z);


/*

The following lines have been replaced
since they could cause errors

*/
// object->polygon[i].norm[0] = x / mag;
// object->polygon[i].norm[1] = y / mag;
// object->polygon[i].norm[2] = z / mag;

/*

This is the new code. It prevents
division of zero, which would cause an
error

*/
if(x != 0)
object->face[i].norm[0] = x / mag;
else
object->face[i].norm[0] = 0;

if(y != 0)
object->face[i].norm[1] = y / mag;
else
object->face[i].norm[1] = 0;

if(z != 0)
object->face[i].norm[2] = z / mag;
else
object->face[i].norm[2] = 0;
}
}

This code works, but gives the lighting glicht mentioned above. With this code, I should be able to get the normals per vertex right? But can you tell me how?

Share this post


Link to post
Share on other sites
quote:
Original post by Ruudje
With this code, I should be able to get the normals per vertex right? But can you tell me how?


No, you can''t have a per vertex lighting with this code. To have so, you should have a normal vector per vertex:
glNormal3f(...)
glVertex3f(...)

glNormal3f(...)
glVertex3f(...)

glNormal3f(...)
glVertex3f(...)

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!