Duplicating md2 vertices gives problems with normals...

Started by
7 comments, last by Spencer 19 years, 3 months ago
Hi! Hope this is the right forum for my question. Anyhow, in my .md2 model loader i want to convert the datastructure to be able to use glDrawArrays. This involves duplicating the vertices and the texture coordinates. So far no problems. But when i want to calculate the normals it doesnt work like i want it to. What i do is that first i create all the vertices like you would probably normaly do by reading the vertex indices from the .md2 file and then i go through the triangle list and just duplicate it to the positions where it is used. I also do the same thing when i calculate the normals. In my mind this would give the same normals for duplicated points, but this does not seem to be the case. In order to explain furhter i will paste the relevant part of my code

 Point *p;
  vector<Point*> tmpPoints;
  vector<Vector*> tmpNormals;

//build the actual vertices
  for(int i = 0; i < m->nrOfFrames; i++){
   for(int j = 0; j < header->numVertices; j++){
      y =  frame->vertices[j].vertex[2] *
	frame->scale[2] + frame->translate[2];
      x = frame->vertices[j].vertex[0] *
	frame->scale[0] + frame->translate[0];
      z = frame->vertices[j].vertex[1] *
	frame->scale[1] + frame->translate[1];
		   
      p = new Point(x, y,z);
      //store the points temporarily
      tmpPoints.push_back(p);
    }
    
    Vector *triNorm,*uv,*vv;
    int cnt = 0;
 
    //calculate a normal for each triangle surface
    for(int tris = 0; tris < header->numTriangles; tris++){

      uv = new Vector(tmpPoints[triangles[tris].vrtxIndices[0]],
		      tmpPoints[triangles[tris].vrtxIndices[1]]);
      vv = new Vector(tmpPoints[triangles[tris].vrtxIndices[0]],
		      tmpPoints[triangles[tris].vrtxIndices[2]]);
      
      m->frames.setTriangleNormal(uv->crossProduct(*vv),tris);
      delete uv;
      delete vv;
    }

    //use surface normals to calculate vertex normals
    for(int v = 0; v < header->numVertices; v++){
      triNorm = new Vector(0,0,0);
      for(int v2 = 0; v2 < header->numTriangles; v2++){
	if((triangles[v2].vrtxIndices[0]    == v)
	   || (triangles[v2].vrtxIndices[1] == v)
	   || (triangles[v2].vrtxIndices[2] == v)){

	  
	  (*triNorm) += *(m->frames.getTriangleNormal(v2));
	  cnt++;
	}
      }
      triNorm->divideByScalar((float)cnt);
      triNorm->normalize();
      
      cnt = 0;
      //store normals tem.
      tmpNormals.push_back(triNorm);
    }
    
//duplicate the vertices and normals
    for(int tr = 0; tr < header->numTriangles; tr++)
      {
	m->frames.setPoint(*tmpPoints[triangles[tr].vrtxIndices[0]],tr*3+0);
	m->frames.setPoint(*tmpPoints[triangles[tr].vrtxIndices[1]],tr*3+1);
	m->frames.setPoint(*tmpPoints[triangles[tr].vrtxIndices[2]],tr*3+2);

      m->frames.setNormal(*tmpNormals[triangles[tr].vrtxIndices[0]],tr*3+0);
      m->frames.setNormal(*tmpNormals[triangles[tr].vrtxIndices[1]],tr*3+1);
      m->frames.setNormal(*tmpNormals[triangles[tr].vrtxIndices[2]],tr*3+2);
      }

    tmpPoints.clear();
    tmpNormals.clear();
    ((char*)frame) += sizeOfFrame;
  }
 

Is my problem just a bug somewhere or "is my logic flawed"? Peace :) --Spencer
--Spencer"All in accordance with the prophecy..."
Advertisement
I don't have much time so I won't provide you code.
But try to remove your overwhelming pointers. You don't need them.

- AdMiRaLP.S. sorry, I'm french, so i may not always speak english perfectly.
Indeed, STL may make your code huge if you use it.
As for myself i use STL whenever I have to, but it is far better to avoid it whenever possible.

What I mean is, if you know the number of entires (vertices), you don't need a resizable buffer. So if you're sure that your mesh has 1200 vertices and 500 faces you don't need a dynamic buffer. D3DXVECTOR3 pVertices = new D3DXVECTOR3[numVertices]; When using OpenGL i suppose, on the end you will have:

NumVertices = NumFaces*3;
NumNormals = NumVertices;

Like a debug approach, i would suggest, that you compute normals before duplicating the vertices, and render. Then try to compute normals after your whole mesh is generated. Then you will be able to compare the visual results. Maybe they aren't so dramatic? I'm only guessing.

A good place for algebra (matrices, vectors, flat/smooth normals, quaternion) is euclidian space by Martin Baker. Try to enter martin baker math into goolge and check some results. I'm sure it will help you out!

As for math libraries, you could use directx math libraries for math, they are awesome - and besides, they are in the 9nth release, they are tested and approved. An alternative is the nvidia math library on developer.nvidia.com.

Don't be affraid to use directx math library in opengl, it is only some classes provided by D3DX, it has nothing to do directly with graphics as an vector does not neccessary represent a point in 3d space or neither is a pixel direcly a part of an image - it might be just a char or dword in memory as directx math vector are just 3 floats in ram and some great ultilisation functions!
Quote:Original post by Samurai Jack
Indeed, STL may make your code huge if you use it.
As for myself i use STL whenever I have to, but it is far better to avoid it whenever possible.

What I mean is, if you know the number of entires (vertices), you don't need a resizable buffer. So if you're sure that your mesh has 1200 vertices and 500 faces you don't need a dynamic buffer. D3DXVECTOR3 pVertices = new D3DXVECTOR3[numVertices]; When using OpenGL i suppose, on the end you will have:

NumVertices = NumFaces*3;
NumNormals = NumVertices;


Sure thing, however Optimization will be done _After_ the stuff works...

Quote:
Like a debug approach, i would suggest, that you compute normals before duplicating the vertices, and render. Then try to compute normals after your whole mesh is generated. Then you will be able to compare the visual results. Maybe they aren't so dramatic? I'm only guessing.

I did that before i decided to use glDrawArrays, and it looked right. The difference is huge...

Quote:
A good place for algebra (matrices, vectors, flat/smooth normals, quaternion) is euclidian space by Martin Baker. Try to enter martin baker math into goolge and check some results. I'm sure it will help you out!


Thanks for the tips...but i am sure the math is not the problem.

Quote:
As for math libraries, you could use directx math libraries for math, they are awesome - and besides, they are in the 9nth release, they are tested and approved. An alternative is the nvidia math library on developer.nvidia.com.


I am deeveloping on a linux box so the directx lib is not an option ;)
--Spencer"All in accordance with the prophecy..."
Funny just been working on updating my own md2 loader ;)

A few points

First you realise the vertex normals are provided in the md2 file?
They are not sotred like vertices though, the normal indices provided are indicies into a LUT. So they are not precise, but I've not had call to change them yet.

Secondly you might want to consider not duplicating vertices at this stage as it will increase the number of operations you'll need whenever you interpolate the model. Instead keep everything as loaded from the md2 file, convert vertices, uvs, normals to float and what not. Then when you need to interpoalte a frame have two loops. First interpolates vertices and normals using the header.numvertices count. The second loop goes through the md2 traingle index arrays (verts & norms are the same indices, texture coords are different) and builds the structure for your vertexarray using the indices into interpolated vertices/normals.

Although you've got two loops, you should be saving as you'll only interpolate each vertex/normal once. Its the interpolation that takes time rather than the rebuilding of a suitable structure for opengl.

There are a few more optimsations you can make, but thats the basic idea.

Finally i've glanced through the code, but it doesn't feel very easy to read. Haven't noticed anything bad in it though.

Perhaps you could elabroate on 'it doesnt work like i want it to.' as thats really no information at all. Does it crash? is the model drawn correctly, are the normals wrong, or just look bad?
Hi!

I thought the LUT for the normals where located in an external file that had to be downloaded from ID or something...are they actually provided in the file? If so, where in the file?
If they are, all my problems are solved ;)

I will test your suggestion for optimization as soon as i get the normals right.

And as for the "doesnt work like i want it to". It is only the normals that ends upp wrong. Everything else is fine...

Thanks for the replies.
--Spencer"All in accordance with the prophecy..."
hi,

Well I don't know where i got it from, presumably one of the many md2 tutorials.

float avertexnormals[162][3] = {{-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f}, {-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f}, {-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f}, {0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f}, {0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f}, {0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f}, {0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f}, {0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f}, {-0.809017f, 0.309017f, 0.500000f}, {-0.587785f, 0.425325f, 0.688191f}, {-0.850651f, 0.525731f, 0.000000f}, {-0.864188f, 0.442863f, 0.238856f}, {-0.716567f, 0.681718f, 0.147621f}, {-0.688191f, 0.587785f, 0.425325f}, {-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f}, {-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f}, {-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f}, {0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f}, {0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f}, {0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f}, {-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f}, {0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f}, {0.238856f, 0.864188f, -0.442863f}, {0.262866f, 0.951056f, -0.162460f}, {0.500000f, 0.809017f, -0.309017f}, {0.850651f, 0.525731f, 0.000000f}, {0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f}, {0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f}, {0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f}, {0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f}, {0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f}, {1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f}, {0.850651f, -0.525731f, 0.000000f}, {0.955423f, -0.295242f, 0.000000f}, {0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f}, {0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f}, {0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f}, {0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f}, {0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f}, {0.681718f, -0.147621f, -0.716567f}, {0.850651f, 0.000000f, -0.525731f}, {0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f}, {0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f}, {0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f}, {0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f}, {0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f}, {-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f}, {-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f}, {-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f}, {0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f}, {0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f}, {-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f}, {0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f}, {0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f}, {0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f}, {0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f}, {0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f}, {0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f}, {0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f}, {0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f}, {0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f}, {0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f}, {0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f}, {0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f}, {-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f}, {-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f}, {-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f}, {-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f}, {-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f}, {-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f}, {-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f}, {-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f}, {-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f}, {-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f}, {0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f}, {0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f}, {0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f}, {0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f}, {-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f}, {-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f}, {-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f}, {-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f}, {-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f}, {-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f}, {-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f}, {-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f}, {-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f}, {-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f}};
and my loop for building vertices nad normals is like this

// Convert and store byte format vertices and normals into floats		for (v=0; v<m_Header.numVertices; v++){m_pFrames.vertices[v].vertex[f0] =		tScalar*  (float) ((int) Inframe->inElement[v].vertex[0]) * Inframe->scale[0] + Inframe->translate[0];m_pFrames.vertices[v].vertex[f1] =  		-tScalar* ((float) ((int) Inframe->inElement[v].vertex[1]) * Inframe->scale[1] + Inframe->translate[1]);m_pFrames.vertices[v].vertex[f2] =		tScalar*  (float) ((int) Inframe->inElement[v].vertex[2]) * Inframe->scale[2] + Inframe->translate[2];			// Normals m_pFrames.vertices[v].normal[f0] = avertexnormals[Inframe->inElement[v].lightNormalIndex][0];m_pFrames.vertices[v].normal[f1] = -avertexnormals[Inframe->inElement[v].lightNormalIndex][1];m_pFrames.vertices[v].normal[f2] = avertexnormals[Inframe->inElement[v].lightNormalIndex][2];}


Scalar is simply a float i use to scale all vertices by, whilst f0,f1,f2 give the vertex order to use to flip axis, but they can just be 0,1,2
dude...thanks :)
And thanks to all who replied!

--Spencer"All in accordance with the prophecy..."

This topic is closed to new replies.

Advertisement