Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 8 of 8

Thread: Problem with declaring vertex normals

  1. #1
    Junior Member Newbie
    Join Date
    Jan 2011
    Posts
    18

    Problem with declaring vertex normals

    Hello,
    I'm programming a small game with BulletPhysics and OpenGL (2.1).
    Yesterday I added lighting to the game, so I needed normals for the objects, too.
    But I've got a problem with that:
    I'm creating a cuboid with the following code:
    Code :
    m_vVertices.pObj = new CVector3D[8];
    GLfloat corners[] = {-vHalfExtents.x, vHalfExtents.y, vHalfExtents.z,
    		vHalfExtents.x, vHalfExtents.y, vHalfExtents.z,
    		vHalfExtents.x, -vHalfExtents.y, vHalfExtents.z,
    		-vHalfExtents.x, -vHalfExtents.y, vHalfExtents.z,
    		-vHalfExtents.x, vHalfExtents.y, -vHalfExtents.z,
    		vHalfExtents.x, vHalfExtents.y, -vHalfExtents.z,
    		vHalfExtents.x, -vHalfExtents.y, -vHalfExtents.z,
    		-vHalfExtents.x, -vHalfExtents.y, -vHalfExtents.z};
    for (int i = 0; i < 8; ++i)
    {
    	m_vVertices.pObj[i].x = corners[i*3];
    	m_vVertices.pObj[i].y = corners[i*3+1];
    	m_vVertices.pObj[i].z = corners[i*3+2];
    }
     
    m_VertexIndices.pObj = new GLuint[6*4];
    GLubyte indices[] = {0, 1, 2, 3,
    		4, 5, 1, 0,
    		3, 2, 6, 7,
    		5, 4, 7, 6,
    		1, 5, 6, 2,
    		4, 0, 3, 7};
    for (int i = 0; i < 24; ++i)
    {
    	m_VertexIndices.pObj[i] = indices[i];
    }

    Later, I'm rendering with this code:

    Code :
    glEnableClientState(GL_VERTEX_ARRAY);
     
    glVertexPointer(3, GL_FLOAT, 0, static_cast<void*>(m_vVertices.pObj));
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT,
    		static_cast<void*>(m_VertexIndices.pObj));
     
    glDisableClientState(GL_VERTEX_ARRAY);

    But when I wanted to add normals, I had a problem: As far as I know OpenGL doesn't support surface normals, only vertex normals.
    But because I'm reusing shared vertices with the help of an index array, I can't specify normals per vertex beacause - dependent on which face a vertex belongs to - each vertex can have different normals. Is there a way I can still use indices to specify the order of the vertices drawn or do I have to declare shared vertices multiple times (for every face needed)?

    Thank you for your answers in advance!

  2. #2
    Junior Member Newbie
    Join Date
    Jan 2011
    Posts
    18

    Re: Problem with declaring vertex normals

    OK, I've just noticed that I misunderstood what vertex normals are ( http://www.opengl.org/discussion_boards/...;gonew=1#UNREAD : "for the normal at a vertex, sum the normals for all the triangles it is shared by; divided by the number of triangles; then normalise this vector" ).
    So I tried it with the following code:

    Code :
    m_vNormals.pObj = new CVector3D[8];
    // Every vertex normal is set here
    for (size_t i = 0; i < 8; ++i)
    {
    	size_t  iNumI = 0; // number of this vertex in the indices
    	GLubyte *pIndices = 0; // locations where the vertex appears
    	CVector3D vVertNorm = CVector3D(0.0f, 0.0f, 0.0f); // the normal
    	for (size_t ii = 0; ii < 24; ++ii)
    	{
    		if (m_VertexIndices.pObj[ii] == i) ++iNumI; // number of this vertex is determined
    	}
    	pIndices = new GLubyte[iNumI];
    	size_t  iNumICounter = 0;
    	for (size_t ii = 0; ii < 24; ++ii)
    	{
    		// if this vertex appears in this location
    		if (m_VertexIndices.pObj[ii] == i)
    		{
    			pIndices[iNumICounter] = ii;
    			++iNumICounter;
    		}
    	}
    	for (size_t j = 0; j < iNumI; ++j)
    	{
    		size_t uiStartPos = pIndices[j]/4;
    		cerr << "uiStartPos: " << uiStartPos << "; iNumI: " << iNumI << endl;
    		CVector3D vAB = m_vVertices.pObj[m_VertexIndices.pObj[uiStartPos+1]]-m_vVertices.pObj[m_VertexIndices.pObj[uiStartPos]];
    		CVector3D vAC = m_vVertices.pObj[m_VertexIndices.pObj[uiStartPos+2]]-m_vVertices.pObj[m_VertexIndices.pObj[uiStartPos]];
    		vVertNorm += Vector3DNormalize(Vector3DCross(vAB, vAC));
    	}
    	vVertNorm /= iNumI;
    	vVertNorm = Vector3DNormalize(vVertNorm);
    	m_vVertices.pObj[i] = vVertNorm;
    	delete[] pIndices;
    }

    But it showed some very strange result and doesn't seem to be correct.

    Does somebody know what I've done wrong?

  3. #3
    Advanced Member Frequent Contributor
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    720

    Re: Problem with declaring vertex normals

    ok I check my code and I was wrong about the divide.

    I have tried to make your code look like mine - beware it may not compile

    Code :
    CVector  normal[8], temp;
     
    for (int i = 0; i < 8; i++)
    {
      normal[i].x = normal[i].y = normal[i].z = 0;
    }
     
    for (int i = 0; i < 24; i += 3)
    {
      CVector3D vAB = m_vVertices.pObj[m_VertexIndices.pObj[i+1]]-m_vVertices.pObj[m_VertexIndices.pObj[i];
      CVector3D vAC = m_vVertices.pObj[m_VertexIndices.pObj[i+2]]-m_vVertices.pObj[m_VertexIndices.pObj[i];
      // normal for triangle face
      temp = Vector3DCross(vAB, vAC);
      // add normal to all vertices in triangle
      for (int j = 0; j < 3; j++)
      {
        normal[m_VertexIndices.pObj[i+1]] += temp
      }
    }
    // normalise vertex normals
    for (int i = 0; i < 8; i++)
    {
      Vector3DNormalize(normal);
    }

  4. #4
    Junior Member Newbie
    Join Date
    Jan 2011
    Posts
    18

    Re: Problem with declaring vertex normals

    Yes, the code seems to work (with some small corrections). But the faces seem to be drawn in a wrong way (only the faces inside seem to be drawn).
    But it doesn't seem to help to to put a minus sign in front of "normal" (code:
    Code :
    // normalise vertex normals
    for (int i = 0; i < 8; i++)
    {
    	normal[i] = Vector3DNormalize(normal[i]);
    	m_vNormals.pObj[i] = -normal[i];
    }
    ).
    Does someone know what I have to change in the code so that it works correctly?

  5. #5
    Advanced Member Frequent Contributor
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    720

    Re: Problem with declaring vertex normals

    The normal has a direction, so it can point in or out depending on the order of the vertices. You can reverse the normal by reversing the cross product

    if Vector3DCross(vAB, vAC) points in, then Vector3DCross(vAC, vAB) points out.

    Google a bit on normals and you find something with a diagram.

  6. #6
    Junior Member Newbie
    Join Date
    Jan 2011
    Posts
    18

    Re: Problem with declaring vertex normals

    I've tried it with reversed normals but it didn't seem to help ( here you can see the results (the right picture uses vAB, vAC and the left picture vAC, vAB): http://dl.dropbox.com/u/32334047/VertexNormals.png ).
    Here the output of the program that produces the right image (with "cerr << (m_vNormals.pObj[i]).x << "; " << (m_vNormals.pObj[i]).y << "; " << (m_vNormals.pObj[i]).z << endl;"):
    Code :
    0; 0; 1
    -0.707107; 0; -0.707107
    -0.0499376; -0.998752; 0
    1; 0; 0
    0; -1; -2.48353e-09
    -nan; -nan; -nan
    0; 1; 0
    -nan; -nan; -nan
    And here the output of the program that produces the left image:
    Code :
    0; 0; -1
    0.707107; 0; 0.707107
    0.0499376; 0.998752; 0
    -1; 0; 0
    0; 1; 2.48353e-09
    -nan; -nan; -nan
    0; -1; 0
    -nan; -nan; -nan

  7. #7
    Advanced Member Frequent Contributor
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    720

    Re: Problem with declaring vertex normals

    The normals are reversing; your problem must be that you triangles at not all using the same winding; ie clockwise or counter clockwise.

    For normals to give consistent results the winding must be consistent - this is easy to say than do if you are manually creating the objects.

    If you have access to a 3D program, create a cube and export it as .obj and look the the ordering of the face indices.

    Also with flat surfaces like cubes, you will not want to average the normal at a vertex; instead you have to duplicate the vertex and use the face normal for that vertex. If you don't the light interpolation across the surface will be wrong.

  8. #8
    Junior Member Newbie
    Join Date
    Jan 2011
    Posts
    18

    Re: Problem with declaring vertex normals

    I've checked the winding of the vertices; it seems that I always used clockwise winding instead of counter clockwise winding.
    I've corrected that and did what you said:
    Also with flat surfaces like cubes, you will not want to average the normal at a vertex; instead you have to duplicate the vertex and use the face normal for that vertex. If you don't the light interpolation across the surface will be wrong.
    Now it seems to work OK.
    Thank you for your help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •