Advertisement

Calculating normals

Started by September 22, 2003 07:17 AM
9 comments, last by Ruudje 21Β years, 5Β months ago
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.x + object->vertex[i+1].x + object->vertex[i+2].x;
                object->normal.y = object->vertex.y + object->vertex[i+1].y + object->vertex[i+2].y;
                object->normal.z = object->vertex.z + object->vertex[i+1].z + object->vertex[i+2].z;
        }
}
 </pre> 

This is my rendering function. It uses the values from the above function, but im not sure it uses them correctly. &#79;ne of these two (or both) are wrong:
<pre>
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&lt;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();
}
 </pre> 

Note: my functions lack good commenting at the moment…  </i>  
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.a].x;<br>                vec1.y = object->vertex[object->polygon.b].y - object->vertex[object->polygon.a].y;<br>                vec1.z = object->vertex[object->polygon.b].z - object->vertex[object->polygon.a].z;<br><br>                vector vec2;<br>                vec2.x = object->vertex[object->polygon.c].x - object->vertex[object->polygon.a].x;<br>                vec2.y = object->vertex[object->polygon.c].y - object->vertex[object->polygon.a].y;<br>                vec2.z = object->vertex[object->polygon.c].z - object->vertex[object->polygon.a].z;<br><br>                float x, y, z;<br>                x = vec1.y * vec2.z - vec1.z * vec2.y;<br>                y = vec1.z * vec2.x - vec1.x * vec2.z;<br>                z = vec1.x * vec2.y - vec1.y * vec2.x;<br><br>                float mag = sqrt(x*x + y*y + z*z);<br><br>                object->normal.x = x / mag;<br>                object->normal.y = y / mag;<br>                object->normal.z = z / mag;<br> </pre> <br><br>Ive also altered my render-function:<br><pre><br>…<br>    glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)<br>    for (i = 0; i < object->polygons_qty ; i++)<br>    {<br>        glNormal3f( object->normal.x,<br>                object->normal.y,<br>                object->normal.z<br>        );<br><br>        //—————– FIRST VERTEX —————–<br>…<br> </pre> <br><br>This makes a lot of sense to me, but the object is still not drawn as it should be drawn…  </i>  
Advertisement
never mind
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.
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.y,<br> object->vertex[ object->polygon[l_index].c ].z+object->normal.z);<br> </i>
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)
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)
Advertisement
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...
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.
Ignore all of the above code for a sec, and take a look at my current code

// Structure for holding a vertextypedef struct{        float x, y, z;        float norm[3];}vertex;// Structure for holding a facetypedef 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.a].x;<br>                vec1.y = object->vertex[object->face.b].y - object->vertex[object->face.a].y;<br>                vec1.z = object->vertex[object->face.b].z - object->vertex[object->face.a].z;<br><br>                vector vec2;<br>                vec2.x = object->vertex[object->face.c].x - object->vertex[object->face.a].x;<br>                vec2.y = object->vertex[object->face.c].y - object->vertex[object->face.a].y;<br>                vec2.z = object->vertex[object->face.c].z - object->vertex[object->face.a].z;<br><br>                float x, y, z;<br>                x = vec1.y * vec2.z - vec1.z * vec2.y;<br>                y = vec1.z * vec2.x - vec1.x * vec2.z;<br>                z = vec1.x * vec2.y - vec1.y * vec2.x;<br><br>                float mag = sqrt(x*x + y*y + z*z);<br><br><br>                /*<br><br>                        The following lines have been replaced<br>                        since they could cause errors<br><br>                */<br>                        // object->polygon.norm[0] = x / mag;<br>                        // object->polygon.norm[1] = y / mag;<br>                        // object->polygon.norm[2] = z / mag;<br><br>                /*<br><br>                        This is the new code. It prevents<br>                        division of zero, which would cause an<br>                        error<br><br>                */<br>                if(x != 0)<br>                        object->face.norm[0] = x / mag;<br>                else<br>                        object->face.norm[0] = 0;<br><br>                if(y != 0)<br>                        object->face.norm[1] = y / mag;<br>                else<br>                        object->face.norm[1] = 0;<br><br>                if(z != 0)<br>                        object->face.norm[2] = z / mag;<br>                else<br>                        object->face.norm[2] = 0;<br>        }<br>}<br> </pre> <br>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?  </i>  
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(...)

This topic is closed to new replies.

Advertisement