OpenGL Lighting problems

Started by
13 comments, last by Etwinox 22 years, 5 months ago
Can somebody tell me how to specify the normal for each vertex? The book I have tells me how to get just the one normal (giving me flat shaded polygons. :<) Also, anybody know how to gourand shade polygons using materials? Please keep in mind that I''m real new to OpenGL... Thanks.
Advertisement
Specifing a normal for each vertex is easy - just call glNormalxxx() before each glVertexxxx(). Later, when you get better with using OpenGL, you''ll start using vertex arrays, but for learning purposes, you''ll probably eventually wrap every vertex with:
glNormal();
glTexCoords();
glVertex();
-- Succinct(Don't listen to me)
Uhh, I''m not trying to be ungrateful but...

How do I "get" the normal for each vertex...that OpenGL book I got only shows how to get the one normal and then it cheats on the rest of the examples and uses aux functions and therefor not telling me how to get them...
Well, you calculate it based on the object you''re trying to render.

If it''s a sphere, the normal is a vector pointing directly away from the center of the sphere.

If it''s a terrain or flatish polygonal model, people generally average the face normals of all the faces which share the vertex.

If you''re drawing some kind of mathematically defined surface, you can figure out the normal based on the derivative of the surface''s equation.
Oh, and don't forget about glShadeModel();

It accepts one of 2 parameters:
GL_FLAT for flat shading,
GL_SMOOTH of smooth shading.

At initialization, gl has glShadeModel set to GL_SMOOTH, so as long as you didn't call glShadeMode(), specifying a normal per vertex will give you smooth shading, so long as each normal is the normal to the surface, and not the polygon. Here is an example of the difference between a normal to the surface and the normals to the polygons apporximating the surface.



Edited by - succinct on November 2, 2001 3:15:28 PM
-- Succinct(Don't listen to me)
A sphere is definitely the easiest, because, as cheesegrater said, the normal for any point on a sphere is the line from the line from the center of the sphere to the point, normalized.

For an arbitrary mesh of polygons, you keep track of what polygons use what vertices and for each vertex computer the average of all the polygon normals that use that vertex. The necessary data structures for figuring this out are somewhat tricky, because each polygon must reference it's composing vertices, and each vertex must reference all of the polygons that reference it. It becomes a "chicken or the egg" type of problem, but you can solve it.

And, to my knowledge, the only other type of surface is a mathematically defined one. If you can define a surface parametrically, such that it is in terms of two variables, usually u and v, you can find the normal using a little calculus. For a given ( u,v ) on the surface, the surface normal is the unit tangent of the u curve crossed with the unit tangent of the v curve.

Basically, seperate the equation into it's f( u ) and g( v ) parts, expressed as vector functions. Find f'( u ) and g'( v ). Normalize them. Cross them. This is your unit normal vector.

Here is a visual explanation for the normals for a parametric torus.

The torus is just a circle (g(v)) swept around another curve (f(u)). The normal at any given point is the unit gradient of the sweeping curve crossed by the unit gradient of the swept curve.

For a circle defined as
x = r*cos( t )
y = r*sin( t )

the derivitaves (gradients) are
x' = r*-sin( t )
y' = r*cos( t )

just like you learn in highschool (and hopefully you've been to highschool and have had calculus!)

For further explanation, the picture generated used the following function.

    void gl::RenderTorus(    int Majors, // number of major subdivisions (along the greater circle)    int Minors, // number of minor subdivisions (along the lesser circle)    float MrX,  // major x radius    float MrY,  // major y radius    float mrX,  // minor x radius    float mrZ,  // minor z radius    float Msa,  // major start angle    float Mea,  // major end angle    float msa,  // minor start angle    float mea,  // minor end angle    bool InvertNormals){    // the vector class uses the operator ^ as a cross product    // the member function .Unit() normalizes the vector.    int NumMajorVertices = Majors + 1;    int NumMinorVertices = Minors + 1;    if( NumMajorVertices <= 2 )        NumMajorVertices = 3;    if( NumMinorVertices <= 2  )        NumMinorVertices = 3;    // calc angle deltas    float MajorAngleDelta = (Mea - Msa)*M_PI/(180*(NumMajorVertices - 1));    float MinorAngleDelta = (mea - msa)*M_PI/(180*(NumMinorVertices - 1));    float MajorAngle1 = Msa*M_PI/180;    float MajorAngle2 = MajorAngle1 + MajorAngleDelta;    for( int i = 0; i < NumMajorVertices - 1; ++i )    {        // calc major coordinates and normals        float uS1x = cos( MajorAngle1 );        float uS1y = sin( MajorAngle1 );        float uS2x = cos( MajorAngle2 );        float uS2y = sin( MajorAngle2 );        Vector uS1 = Vector(  MrX*uS1x,MrY*uS1y,0 );        Vector uN1 = Vector( -MrX*uS1y,MrY*uS1x,0 ).Unit() ^ Vector( 0,0,1 );        Vector uS2 = Vector(  MrX*uS2x,MrY*uS2y,0 );        Vector uN2 = Vector( -MrX*uS2y,MrY*uS2x,0 ).Unit() ^ Vector( 0,0,1 );        // calc rotation angles for minor ellipse (so it lines up with major normal)        float RotationAngle1 = acos( uN1.x );        if( ((-M_PI  < MajorAngle1) && (MajorAngle1 < 0   ))         || ((2*M_PI > MajorAngle1) && (MajorAngle1 > M_PI)) )            RotationAngle1 = -RotationAngle1;        float RotationAngle2 = acos( uN2.x );        if( ((-M_PI  < MajorAngle2) && (MajorAngle2 < 0   ))         || ((2*M_PI > MajorAngle2) && (MajorAngle2 > M_PI)) )            RotationAngle2 = -RotationAngle2;        // cache rotation coefficients        float ct1 = cos( RotationAngle1 );        float st1 = sin( RotationAngle1 );        float ct2 = cos( RotationAngle2 );        float st2 = sin( RotationAngle2 );        glBegin( GL_QUAD_STRIP );        float MinorAngle = msa*M_PI/180;        for( int j = 0; j < NumMinorVertices; ++j )        {            // v == minor param            float vSx = cos( MinorAngle );            float vSz = sin( MinorAngle );            // rotate minor ellipse so it is aligned with the normal of the major ellipse at this point            Vector vS = Vector( mrX* vSx,0,mrZ*vSz );            Vector vT = Vector( mrX*-vSz,0,mrZ*vSx );            Vector vS1r = Vector( ct1*vS.x,st1*vS.x,vS.z );            Vector vT1r = Vector( ct1*vT.x,st1*vT.x,vT.z );            Vector vS2r = Vector( ct2*vS.x,st2*vS.x,vS.z );            Vector vT2r = Vector( ct2*vT.x,st2*vT.x,vT.z );            Vector vN1 = ((vT1r ^ vS1r).Unit() ^ vT1r).Unit();            Vector vN2 = ((vT2r ^ vS2r).Unit() ^ vT2r).Unit();            if( InvertNormals )            {                vN1 = -vN1;                vN2 = -vN2;            }            glNormal3fv( vN1 );            glVertex3fv( uS1 + vS1r );            glNormal3fv( vN2 );            glVertex3fv( uS2 + vS2r );            MinorAngle += MinorAngleDelta;        }        glEnd();        MajorAngle1 += MajorAngleDelta;        MajorAngle2 += MajorAngleDelta;    }}    


I hope that helps,
-- Succinct

Edited by - succinct on November 2, 2001 5:14:11 PM
-- Succinct(Don't listen to me)
Uhh, hmm.

Ok, you guys are really being nice and putting lots of time into this but, all this info is really confusing...how do I "smooth shade" a cube? I thought you had to give a "normal" for each vertex...



>just like you learn in highschool (and hopefully you''ve been to >highschool and have had calculus!)
Hmm, uhh... In highschool.
If you have the object in a .3ds file you can use
a software named 3DExploration (search with www.google.com)
and this software give you a file (see "Save as..") with
all information about texturing normals vertex position...
as .cpp file for OpenGL.
That''s all
Hi,

When you have already the normal for a polygon it is
not difficult to find the vertex-normals.
take a vertex, go through your polygons, take the Face(polygon)-Normal from all the polygons who share that vertex,
add them and normalize it, so can get the vertex-normals.

Try a Cube, becaue a cube only has eight corners, vertices
Etwinox:

After you figure out the vertex issues, to gourand shade a polygon you can do the following:

//----------------------------------------

//define light and material properties
float ambientLight[] = {0.5f,0.5f,0.5f,1.0f}; // ambient light
float specularLight[]= {1.0f,1.0f,1.0f,1.0f }; //specular light

//material reacting to ambient light
float matAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};

then add the following to your scene initialization

glEnable (GL_LIGHTING); // Enable lighting
glEnable (GL_COLOR_MATERIAL); //enable materials
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

//Set the lighting materials
glMaterialfv(GL_FRONT, GL_AMBIENT, matAmbient);
glMaterialfv(GL_FRONT, GL_SPECULAR, specularLight);
glMateriali (GL_FRONT, GL_SHININESS, 128); //strong shiny effect

//Setup LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); //ambient light
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);//specular light
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);//light position

glEnable (GL_LIGHT0); //enable light0

glShadeModel (GL_SMOOTH);//enable gourand shading

/---------------------------------/

Hope it helps

This topic is closed to new replies.

Advertisement