Sign in to follow this  

MS3D Trianglebased mesh to VBO arrays

This topic is 2783 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

I'm struggeling a bit with converting my mesh-loaded object into VBO supported arrays. The mesh is of ms3d (milkshape) format, and the structure looks something like this:
<Group>
	triangle_indices
	material
</Group>
<Triangle>
	vertex_indices
	vertex_normals
	texture_coord_st
	normal_coord_xyz
</Triangle>
<Vertex>
	vertex_coord_xyz
</Vertex>


For now I only look at solving for 1 group. So, I have arrays set up for my VBO (indices, vertices, normals, texCoords) Filling the vertex array is pretty much straight forward. For vertices I can do:
for(int i = 0; i < model->GetNumVertices(); i++)
{
	vertices.push_back(model->GetVertex(i)->vertex[0]);
	vertices.push_back(model->GetVertex(i)->vertex[1]);
	vertices.push_back(model->GetVertex(i)->vertex[2]);
}


but then things get a bit complicated. Filling the indices would consist of something like
for each tri_index in model->getGroup()->getTriIndices() do
  triangle = model->getTriangle(tri_index);
  for each index in triangle->getVertexIndices() do
    indices.push_back(index);
  end
  ...


I could probably also extract each vertex normal like I do the indices. But how about the texture coords? Since each triangle has a shared tex-coord, this means that for each vertex that is shared between 4 triangles, it "should" have 4 texture coords? I'm not quite seeing the solution to how to convert that into a flat texCoord array for use in the VBO. Is there a common way to treat this kind of triangle structures when it comes to VBOs? Thanks for any help and insight on the matter! [Edited by - Trefall on April 28, 2010 4:20:57 AM]

Share this post


Link to post
Share on other sites
Here's the ms3d model loader structure:
msModel.h

and here's a first attempt that fails misserably:


for(int i = 0; i < model->GetNumVertices(); i++)
{
vertices.push_back(model->GetVertex(i)->vertex[0]);
vertices.push_back(model->GetVertex(i)->vertex[1]);
vertices.push_back(model->GetVertex(i)->vertex[2]);
colors.push_back(model->GetVertex(i)->renderColor[0]+0.4f);
colors.push_back(model->GetVertex(i)->renderColor[1]+0.4f);
colors.push_back(model->GetVertex(i)->renderColor[2]+0.4f);
colors.push_back(1.0f);
normals.push_back(0.0f);
normals.push_back(0.0f);
normals.push_back(0.0f);
texCoords.push_back(0.0f);
texCoords.push_back(0.0f);
}

for(int i = 0; i < model->GetNumGroups(); i++)
{
for(unsigned int j = 0; j < model->GetGroup(i)->triangleIndices.size(); j++)
{
unsigned short indX = model->GetTriangle(j)->vertexIndices[0];
unsigned short indY = model->GetTriangle(j)->vertexIndices[1];
unsigned short indZ = model->GetTriangle(j)->vertexIndices[2];
indices.push_back(indX);
indices.push_back(indY);
indices.push_back(indZ);

normals[indX+0] = model->GetTriangle(j)->vertexNormals[0][0];
normals[indX+1] = model->GetTriangle(j)->vertexNormals[0][1];
normals[indX+2] = model->GetTriangle(j)->vertexNormals[0][2];

normals[indY+0] = model->GetTriangle(j)->vertexNormals[1][0];
normals[indY+1] = model->GetTriangle(j)->vertexNormals[1][1];
normals[indY+2] = model->GetTriangle(j)->vertexNormals[1][2];

normals[indZ+0] = model->GetTriangle(j)->vertexNormals[2][0];
normals[indZ+1] = model->GetTriangle(j)->vertexNormals[2][1];
normals[indZ+2] = model->GetTriangle(j)->vertexNormals[2][2];

texCoords[indX+0] = model->GetTriangle(j)->s[0];
texCoords[indX+1] = model->GetTriangle(j)->t[0];

texCoords[indY+0] = model->GetTriangle(j)->s[1];
texCoords[indY+1] = model->GetTriangle(j)->t[1];

texCoords[indZ+0] = model->GetTriangle(j)->s[2];
texCoords[indZ+1] = model->GetTriangle(j)->t[2];
}
}


Share this post


Link to post
Share on other sites
Probably it has to do with the smoothing groups in Milkshape. Smoothed vertices also share the same texcoord/normal. Maybe not the easiest way, but you could rebuild the mesh and do the smoothing/optimization yourself, creating suitable array's for VBO's. At least, that's what I'm doing. Maybe not fast, but you could store the mesh in your own format afterwards so you only have to do this once.

Load the model as usual. The MS3D format holds triangles where each triangle has it's own 3 normals and texture coordinates. Only the positions are possibly shared amongst multiple triangles.

TMS3D_Triangle = packed record
flag : word; // selected / hidden info

indices : array[0..2] of word;
normal : array[0..2] of TVector3f;

{ UV }
s : array[0..2] of single;
t : array[0..2] of single;

SmoothingGroup : byte;
IndexGroup : byte;
end; // TMS3D_Triangle

Instead of indices, store 3 vertex coordinates as well here for now.

Next step is to rebuild the mesh and do the smoothing yourself, given a threshold parameter. Create empty output array's for the positions, normals, texcoords and possibly weights in case you're planning animations as well.

For each triangle vertex, find the matching vertices:
- positions are the same
- texture coordinates are the same
- normals (almost) the same: dot( referenceNormal, otherVertex.normal ) > smooth_threshold_parameter
If the match fails, skip the vertex. Later on it will get it's own index. Otherwise if it matches, add the normal and count the samples. Also mark the vertex so you can't use it again for another vertex. When you looped through the entire thing, calculate the average normal and add the results to the output array's. And add the output-array index to an indices array.

Repeat the process until all vertices were marked. Finally you will have array's suitable for VBO's with optimized data.

Greetings,
Rick

Share this post


Link to post
Share on other sites
Thanks spek for your insight. I'll dig into this some more! Sounds like I'm not the only one who has come over this little headache:
linky

So basicaly what you say is that if I want smoothing-groups I have to go over the mesh and perform the conversion like you do... I'm having problems just converting it to a flat array without smoothing though :/ hrm, maybe I just have to stop for a second and think.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trefall
I could probably also extract each vertex normal like I do the indices. But how about the texture coords? Since each triangle has a shared tex-coord, this means that for each vertex that is shared between 4 triangles, it "should" have 4 texture coords? I'm not quite seeing the solution to how to convert that into a flat texCoord array for use in the VBO. Is there a common way to treat this kind of triangle structures when it comes to VBOs?

Thanks for any help and insight on the matter!


I recently had to deal with this problem. The way I solved it for every new triangle in the file, I first search through the list of triangles that have already been seen. If the new triangle we're trying to add has a different texture coordinate from any of it's shared vertices, then I create a new vertex. If you want to see some code, it's here:

http://github.com/stephenlombardi/slib/blob/master/examples/ms3dview/MS3DToMesh.cpp

In my code, each function of that class is a callback. Vertex( .. ) gets called for each vertex, Triangle( .. ) for each triangle, etc.,. You can see in the Triangle method that there is a boolean variable which is set to true if a conflicting texture coordinate is found. When this happened a new vertex is created.

Share this post


Link to post
Share on other sites

This topic is 2783 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this