Skip to main content
GameDev.net gamedev.net
🔒 Locked

Mesh data structure question?

Started by Scythen Jul 27, 2007 at 9:49 PM 0 replies 1.1k views
Original Post
Scythen
Scythen
Hello everyone, In my naive attempt to create smoothed vertex normals for meshs I have run into a little snag. Actually creating the normals and smoothing them is easy my problem is with the structure of my mesh data. I have a very basic mesh object that contains an array of faces and an array of vertices. As long as faces share vertices with the all adjacent faces my smoothing works great. However, if two adjacent faces do not share vertices for some reason (different texture coordinates) smoothing is broken between those faces. Is there some simple way to deal with this? My first thought is to go through the mesh looking for faces that share congruent edge / vertices and set up adjacency information but is that the best way to deal with this? How does D3D create adjacency data? That is probably what I need to do.
RobTheBloke
RobTheBloke
If you've got the orignal vertex data with seperate indices for normals and vertices, then the simple way is to map that to your vertex array(or buffer) data. So first off, do a pre-processing step to organise your data something like this :

struct NormalHack { unsigned short vert_index; // original vertex index unsigned short norm_index; // original normal index unsigned short uv_index;   // original UV coord index. unsigned short output_index; // the output vertex array index};std::vector<NormalHack> AllIndexMappings; // fill this with the mesh data


Now run through those elements and find a map of all those elements that share normal and vertex indices. ie,

typedef std::map<unsigned,std::vector<NormalHack*> > NormalHackMap;NormalHackMap NormalHacks;for(unsigned i=0;i<AllIndexMappings.size();++i){  NormalHack* nh = &(AllIndexMappings);  unsigned key = ((unsigned)(nh->vert_index) << 16) & nh->norm_index;  NormalHackMap::iterator it = NormalHacks.find(key);  if(it == NormalHacks.end())   {    std::vector<NormalHack*> v;    v.push_back( nh );    NormalHacks.insert( std::make_pair( key, v ) );  }  else   {    it->second.push_back( &nh );  }}


At this point, you now have a mapping between all shared verts and normals. so Do something along the lines of :

NormalHackMap::iterator it = NormalHacks.begin();for( ; it != NormalHacks.end(); ++it ) {  unsigned short v_index = (it->first >> 16) & 0x0000FFFF;  unsigned short n_index = (it->first & 0x0000FFFF);  std::vector<NormalHack*>& vinfo = it->second;  if( vinfo.size() > 1 )  {    // build a list of all the vertex array indices since there are     // more than 1 vertex array element that share the same vertex     // and normal.....  }  else  {    // the vertices and normals are all shared, so we can ignore...  }}


So, in the end you'll end up with a data structure that is something like :

struct NormalFix {  unsigned num_of_indices;  std::vector<unsigned> indices;};std::vector<NormalFix> AllFixes;


When you come to sorting out the seams, you can do this for all normal fixes before you do the normalisation step (unless of course you enable auto normalise in D3D or GL_NORMALIZE in openGL).....

struct Vertex {  Point3 v;  Point3 n;  Point2 t;};void Fix_Normals(Vertex* vertex_array){  std::vector<NormalFix>::const_iterator it = AllFixes.begin();  for(;it != AllFixes.end(); ++it)  {    const NormalFix& nf = *it;       Vertex* first_vert = vertex_array + nf.indices[0];    // sum into the first normal    for(unsigned i=1;i!=num_of_indices;++i)    {      Vertex* vertex = vertex_array + nf.indices;      first_vertex.n += vertex.n;    }    // copy back into the other normals    for(unsigned i=1;i!=num_of_indices;++i)    {      Vertex* vertex = vertex_array + nf.indices;      vertex.n = first_vertex.n;    }  }}


Anyhow, that works rather nicely for me, but make sure you do this as a pre-processing step and save out the final data. The building of the mappings is definately not something you want happening in your engine.

If for some reason you do not have access to the original indexing info, then you can get close to the desired result by comparing the fmodf(u) and fmodf(v) of all the UV's and see if they wrap. This however does not work all the time, but it does work 90% of the time and is an improvement over nothing.

It's always guarenteed if it's coming from the original indices, So i'd recommend the above method that if you have access to them.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.