Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

NVMeshMender.cpp

Go to the documentation of this file.
00001 /*********************************************************************NVMH2****
00002 Copyright (C) 1999, 2000, 2001, 2002 NVIDIA Corporation
00003 This file is provided without support, instruction, or implied warranty of any
00004 kind.  NVIDIA makes no guarantee of its fitness for a particular purpose and is
00005 not liable under any circumstances for any damages or loss whatsoever arising
00006 from the use or inability to use this file or items derived from it.
00007 
00008 Questions to sim.dietrich@nvidia.com
00009 
00010 Comments:
00011 
00012     This tool is designed to help condition meshes for use in vertex & pixel shaders.
00013 
00014     It can generate normals, texture coordinates, and perhaps most importantly, texture space 
00015   basis matrices.  It also can fix common texuring problems that come up when bump mapping, including
00016 
00017   Texture Mirroring -  When two one halves of a character use the same part of a texture.
00018 
00019   Cylindrical TexGen - When the rendering relies on cylindrical wrapping, texture space computation
00020                         won't work right.
00021 
00022   Stretched Basis -    When two adjacend faces use wildly different texture mappings, causing stretching
00023                         that can ruin per-pixel lighting.
00024  
00025 
00026   Here is an example usage scenario : 
00027 
00028   Say you have positions & indices, and want textures, normals, and tangents.
00029 
00030   NVMeshMender aMender;
00031 
00032   MVMeshMender::VAVector inputAtts;  // this is what you have
00033 
00034   MVMeshMender::VAVector outputAtts; // this is what you want
00035 
00036   MVMeshMender::VertexAttribute att;  // this is my working attribute
00037 
00038   att.Name_ = "position";
00039 
00040   for ( int p = 0; p < number_of_vertices; ++p )
00041   {
00042     att.floatVector_.push_back( myPositions[ p ].x );
00043     att.floatVector_.push_back( myPositions[ p ].y );
00044     att.floatVector_.push_back( myPositions[ p ].z );
00045   }
00046 
00047   att.floatVector.clear();
00048 
00049   att.Name_ = "indices";
00050 
00051   for ( int i = 0; i < number_of_indices; ++i )
00052   {
00053     att.intVector_.push_back( myIndices[ i ] );
00054   }
00055 
00056   // All inputs except for indices are assumed to be sets of 3 floats
00057 
00058   // "indices" are assumed to be unsigned ints
00059 
00060   // "tex0" is used for the tangent space calculation
00061 
00062   // "tex0" is the only coordinate set generated, and the texture matrix applies only to it
00063 
00064   //  All unknown attribute types, including "tex1", "tex2", "random_attribute", "weights", "bones", etc.
00065   // are simply passed through.  They will be duplicated as needed just like positions, normals, etc.
00066 
00067   bool bSuccess = aMender.Munge( inputAtts,              // these are my positions & indices
00068                                  outputAtts,             // these are the outputs I requested, plus extra stuff generated on my behalf
00069                                  3.141592654f / 2.5f,    // tangent space smooth angle
00070                                  NULL,                   // no Texture matrix applied to my tex0 coords
00071                                  FixTangents,            // fix degenerate bases & texture mirroring
00072                                  FixCylindricalTexGen    // handle cylidrically mapped textures via vertex duplication
00073                                  WeightNormalsByFaceSize // weight vertex normals by the triangle's size
00074                                  );
00075 
00076 
00077   if ( !bSuccess ) return false;
00078 
00079   // Now the outputAtts may contain more vertex then you sent in !
00080   //  This is because in handling tangent space smoothing, and solving texture mirroring & 
00081   // cylindrical texture wrapping problems, we partially duplicate vertices.
00082 
00083   // All attributes are duplicated, even unknowns.
00084 
00085   //  You may also get things you didn't ask for.  For instance, if you ask for tangent space,
00086   // in other words, you ask for "tangent" or "binormal",  you will get "normal", "tex0", 
00087   // "tangent" and "binormal".  You can then ignore things in the output vector that you don't want.
00088 
00089   //   If you ask for FixCylindricalTexGen, it will fix any absolute change in texture coordinates > 0.5 
00090   // across a single edge.  Therefore, if you pass in a single quad or cube, it won't work.  Any more 
00091   // complicated or tessellated mesh should work fine.
00092 
00093 ******************************************************************************/
00094 
00095 #ifdef _WIN32
00096 #  pragma warning (disable : 4786)
00097 #endif
00098 
00099 #include "NVMeshMender.h"
00100 #include "nv_math/nv_math.h"
00101 #include <map>
00102 #include <set>
00103 #include <assert.h>
00104 
00105 bool NVMeshMender::Munge(  const NVMeshMender::VAVector& input, 
00106                            NVMeshMender::VAVector& output, 
00107                            const float bSmoothCreaseAngleRadians,
00108                            const float* pTextureMatrix,
00109                            const Option _FixTangents,
00110                            const Option _FixCylindricalTexGen,
00111                            const Option _WeightNormalsByFaceSize )
00112 {
00113     typedef std::map< std::string, unsigned int > Mapping;
00114     typedef std::set< Edge > EdgeSet;
00115     typedef std::vector< std::set< unsigned int > > IdenticalVertices;
00116 
00117     IdenticalVertices IdenticalVertices_;
00118 
00119     // make room for potential tex coords, normals, binormals and tangents
00120     output.resize( input.size() + 4 ); 
00121 
00122     Mapping inmap;
00123     Mapping outmap;
00124 
00125     for ( unsigned int a = 0; a < input.size(); ++a )
00126     {
00127         inmap[ input[ a ].Name_ ] = a;
00128     }
00129 
00130     for ( unsigned int b = 0; b < output.size(); ++b )
00131     {
00132         output[ b ].intVector_.clear();
00133         output[ b ].floatVector_.clear();
00134         outmap[ output[ b ].Name_ ] = b;
00135     }
00136 
00137     for ( unsigned int c = 0; c < output.size(); ++c )
00138     {
00139         // for every output that has a match in the input, just copy it over
00140         Mapping::iterator in = inmap.find( output[ c ].Name_ );
00141         if ( in != inmap.end() )
00142         {
00143             // copy over existing indices, position, or whatever
00144             output[ c ] = input[ (*in).second ];
00145         }
00146     }
00147 
00148     if ( inmap.find( "indices" ) == inmap.end() )
00149     {
00150         SetLastError( "Missing indices from input" );
00151         return false;
00152     }
00153     if ( outmap.find( "indices" ) == outmap.end() )
00154     {
00155         SetLastError( "Missing indices from output" );
00156         return false;
00157     }
00158 
00159     // Go through all required outputs & generate as necessary
00160     if ( inmap.find( "position" ) == inmap.end() )
00161     {
00162         SetLastError( "Missing position from input" );
00163         return false;
00164     }
00165     if ( outmap.find( "position" ) == outmap.end() )
00166     {
00167         SetLastError( "Missing position from output" );
00168         return false;
00169     }
00170 
00171     Mapping::iterator pos = outmap.find( "position" );
00172     VertexAttribute::FloatVector& positions = output[ (*pos).second ].floatVector_;
00173     vec3* pPositions = (vec3*)( &( positions[ 0 ] ) );
00174 
00175     std::set< unsigned int > EmptySet;
00176 
00177     for ( unsigned int i = 0; i < positions.size(); i += 3 )
00178     {
00179         IdenticalVertices_.push_back( EmptySet );
00180     }
00181 
00182     // initialize all attributes
00183     for ( unsigned int att = 0; att < output.size(); ++att )
00184     {
00185         if ( output[ att ].Name_ != "indices" )
00186         {
00187             if ( output[ att ].floatVector_.size() == 0 )
00188             {
00189                 output[ att ].floatVector_ = positions;
00190             }
00191         }
00192     }
00193 
00194     Mapping::iterator ind = outmap.find( "indices" );
00195     VertexAttribute::IntVector& indices = output[ (*ind).second ].intVector_;
00196     int* pIndices = (int*)( &( indices[ 0 ] ) );
00197 
00198     vec3* pNormals = 0;
00199     //vec3* pBiNormals = 0;
00200     //vec3* pTangents = 0;
00201     vec3* pTex0 = 0;
00202 
00203     bool bNeedNormals = false;
00204     bool bNeedTexCoords = false;
00205     bool bComputeTangentSpace = false;
00206 
00207     // see if texture coords are needed
00208     if ( outmap.find( "tex0" ) != outmap.end() )
00209     {
00210         bNeedTexCoords = true;
00211     }
00212 
00213     // see if tangent or binormal are needed
00214     if ( ( outmap.find( "binormal" ) != outmap.end() ) || 
00215          ( outmap.find( "tangent" ) != outmap.end() ) )
00216     {
00217         bComputeTangentSpace = true;
00218     }
00219 
00220     // see if normals are needed
00221     if ( outmap.find( "normal" ) != outmap.end() )
00222     {
00223         bNeedNormals = true;
00224     }
00225 
00226     // Compute normals.
00227     Mapping::iterator want = outmap.find( "normal" );
00228     bool have_normals = ( inmap.find( "normal" ) != inmap.end() ) ? true : false;
00229 
00230     if ( bNeedNormals || bComputeTangentSpace )
00231     {
00232         // see if normals are provided
00233         if ( !have_normals )
00234         {
00235             // create normals
00236             if ( want == outmap.end() )
00237             {
00238                 VertexAttribute norAtt;
00239                 norAtt.Name_ = "normal";
00240                 output.push_back( norAtt );
00241 
00242                 outmap[ "normal" ] = output.size() - 1;
00243                 want = outmap.find( "normal" );
00244             }
00245 
00246             // just initialize array so it's the correct size
00247             output[ (*want).second ].floatVector_ = positions;
00248 
00249             //VertexAttribute::FloatVector& normals = output[ (*want).second ].floatVector_;
00250 
00251             // zero out normals
00252             for ( unsigned n = 0; n < positions.size(); ++n )
00253             {
00254                 output[ (*want).second ].floatVector_[ n ] = nv_zero;
00255             }
00256 
00257             pNormals = (vec3*)( &( output[ (*want).second ].floatVector_[0] ) );
00258 
00259             // calculate face normals for each face
00260             //  & add its normal to vertex normal total
00261             for ( unsigned int t = 0; t < indices.size(); t += 3 )
00262             {
00263                 vec3 edge0;
00264                 vec3 edge1;
00265 
00266                 edge0 = pPositions[ indices[ t + 1 ] ] - pPositions[ indices[ t + 0 ] ];
00267                 edge1 = pPositions[ indices[ t + 2 ] ] - pPositions[ indices[ t + 0 ] ];
00268 
00269                 edge0.normalize();
00270                 edge1.normalize();
00271             
00272                 vec3 faceNormal = edge0 ^ edge1;
00273 
00274                 if ( _WeightNormalsByFaceSize == DontWeightNormalsByFaceSize )
00275                 {
00276                     // Renormalize face normal, so it's not weighted by face size
00277                     faceNormal.normalize();
00278                 }
00279                 else
00280                 {
00281                     // Leave it as-is, to weight by face size naturally by the cross product result
00282                 }
00283 
00284                 pNormals[ indices[ t + 0 ] ] += faceNormal;
00285                 pNormals[ indices[ t + 1 ] ] += faceNormal;
00286                 pNormals[ indices[ t + 2 ] ] += faceNormal;
00287             }
00288 
00289             // Renormalize each vertex normal
00290             for ( unsigned int v = 0; v < output[ (*want).second ].floatVector_.size() / 3; ++v )
00291                 pNormals[v].normalize();
00292         }
00293     }
00294 
00295     // Compute texture coordinates.
00296     if ( bNeedTexCoords || bComputeTangentSpace )
00297     {
00298         if ( outmap.find("tex0") == outmap.end() )
00299         {
00300             VertexAttribute texCoordAtt;
00301             texCoordAtt.Name_ = "tex0";
00302             output.push_back( texCoordAtt );
00303             outmap[ "tex0" ] = output.size() - 1;
00304         }
00305         want = outmap.find("tex0");
00306         Mapping::iterator have = inmap.find( "tex0" );
00307         bool have_texcoords = (have != inmap.end());
00308 
00309         // see if texcoords are provided
00310         if ( have_texcoords )
00311             output[ (*want).second ].floatVector_ = input[ (*have).second ].floatVector_;
00312         else {
00313             // just initialize array so it's the correct size
00314             output[ (*want).second ].floatVector_ = positions;
00315 
00316             pTex0 = (vec3*)( &(output[ (*want).second ].floatVector_[ 0 ]) );
00317 
00318             // Generate cylindrical coordinates
00319 
00320             // Find min and max positions for object bounding box
00321 
00322             vec3 maxPosition( -FLT_MAX, -FLT_MAX, -FLT_MAX  );
00323             vec3 minPosition(  FLT_MAX,   FLT_MAX,    FLT_MAX );
00324 
00325             // there are 1/3 as many vectors as floats
00326             const unsigned int theCount = static_cast<unsigned int>(positions.size() / 3.0f);
00327 
00328             for ( unsigned int i = 0; i < theCount; ++i )
00329             {
00330                 maxPosition.x = nv_max( maxPosition.x, pPositions[ i ].x );
00331                 maxPosition.y = nv_max( maxPosition.y, pPositions[ i ].y );
00332                 maxPosition.z = nv_max( maxPosition.z, pPositions[ i ].z );
00333 
00334                 minPosition.x = nv_min( minPosition.x, pPositions[ i ].x );
00335                 minPosition.y = nv_min( minPosition.y, pPositions[ i ].y );
00336                 minPosition.z = nv_min( minPosition.z, pPositions[ i ].z );
00337             }
00338 
00339             // Find major, minor and other axis for cylindrical texgen
00340 
00341             vec3 delta = maxPosition - minPosition;
00342 
00343             delta.x = (float)fabs( delta.x );
00344             delta.y = (float)fabs( delta.y );
00345             delta.z = (float)fabs( delta.z );
00346 
00347             bool maxx,maxy,maxz;
00348             maxx = maxy = maxz = false;
00349             bool minz,miny,minx;
00350             minx = miny = minz = false;
00351 
00352             float deltaMajor = 0.0;
00353 
00354             if ( ( delta.x >= delta.y ) && ( delta.x >= delta.z ) )
00355             {
00356                 maxx = true;
00357                 deltaMajor = delta.x;
00358                 if ( delta.y > delta.z )
00359                 {
00360                     minz = true;
00361                 }
00362                 else
00363                 {
00364                     miny = true;
00365                 }
00366             }
00367             else
00368             if ( ( delta.z >= delta.y ) && ( delta.z >= delta.x ) )
00369             {
00370                 maxz = true;
00371                 deltaMajor = delta.z;
00372                 if ( delta.y > delta.x )
00373                 {
00374                     minx = true;
00375                 }
00376                 else
00377                 {
00378                     miny = true;
00379                 }
00380             }
00381             else
00382             if ( ( delta.y >= delta.z ) && ( delta.y >= delta.x ) )
00383             {
00384                 maxy = true;
00385                 deltaMajor = delta.y;
00386                 if ( delta.x > delta.z )
00387                 {
00388                     minz = true;
00389                 }
00390                 else
00391                 {
00392                     minx = true;
00393                 }
00394             }
00395 
00396             for ( unsigned int p = 0; p < theCount; ++p )
00397             {
00398                 // Find position relative to center of bounding box
00399 
00400                 vec3 texCoords = ( ( maxPosition + minPosition ) / 2.0f ) - pPositions[ p ];
00401                 
00402                 float Major = 0.0, Minor = 0.0, Other = nv_zero;
00403 
00404                 if ( maxx )
00405                 {
00406                     Major = texCoords.x;
00407                     if ( miny )
00408                     {
00409                         Minor = texCoords.y;
00410                         Other = texCoords.z;
00411                     } else {
00412                         Minor = texCoords.z;
00413                         Other = texCoords.y;
00414                     }
00415                 }
00416                 else
00417                 if ( maxy )
00418                 {
00419                     Major = texCoords.y;
00420                     if ( minx )
00421                     {
00422                         Minor = texCoords.x;
00423                         Other = texCoords.z;
00424                     } else {
00425                         Minor = texCoords.z;
00426                         Other = texCoords.x;
00427                     }
00428                 }
00429                 else
00430                 if ( maxz )
00431                 {
00432                     Major = texCoords.z;
00433                     if ( miny )
00434                     {
00435                         Minor = texCoords.y;
00436                         Other = texCoords.x;
00437                     } else {
00438                         Minor = texCoords.x;
00439                         Other = texCoords.y;
00440                     }
00441                 }
00442 
00443                 float longitude = nv_zero;
00444 
00445                 // Prevent zero or near-zero from being passed into atan2
00446                 if ( fabs( Other ) < 0.0001f )
00447                 {
00448                     if ( Other >= nv_zero )
00449                     {
00450                         Other = 0.0001f;
00451                     } else {
00452                         Other = -0.0001f;
00453                     }
00454                 }
00455 
00456                 // perform cylindrical mapping onto object, and remap from -pi,pi to -1,1
00457 
00458                 longitude = (float)(( atan2( Minor, Other ) ) / 3.141592654);
00459 
00460                 texCoords.x = 0.5f * longitude + 0.5f;
00461                 texCoords.y = (Major/deltaMajor) + 0.5f;
00462 
00463                 texCoords.x = nv_max( texCoords.x, nv_zero );
00464                 texCoords.y = nv_max( texCoords.y, nv_zero );
00465 
00466                 texCoords.x = nv_min( texCoords.x, 1.0f );
00467                 texCoords.y = nv_min( texCoords.y, 1.0f );
00468 
00469                 pTex0[ p ].x = texCoords.x-0.25f;
00470                 if ( pTex0[ p ].x < nv_zero ) pTex0[ p ].x += 1.0;
00471                 pTex0[ p ].y = 1.0f-texCoords.y;
00472                 pTex0[ p ].z = 1.0f;
00473             }
00474         }
00475 
00476         if ( _FixCylindricalTexGen == FixCylindricalTexGen )
00477         {
00478             Mapping::iterator texIter = outmap.find( "tex0" );
00479 
00480             VertexAttribute::FloatVector& texcoords = ( output[ (*texIter).second ].floatVector_ );
00481 
00482             const unsigned int theSize = indices.size();
00483             
00484             for ( unsigned int f = 0; f < theSize; f += 3 )
00485             {
00486                 for ( int v = 0; v < 3; ++v )
00487                 {
00488                     int start = f + v;
00489                     int end = start + 1;
00490 
00491                     if ( v == 2 )
00492                     {
00493                         end = f;
00494                     }
00495 
00496                     float dS = texcoords[ indices[ end ] * 3 + 0 ] - texcoords[ indices[ start ] * 3 + 0 ];
00497 
00498                     float newS = nv_zero;
00499 
00500                     bool bDoS = false;
00501 
00502                     unsigned int theOneToChange = start;
00503 
00504                     if ( fabs( dS ) >= 0.5f )
00505                     {
00506                         bDoS = true;
00507                         if ( texcoords[ indices[ start ] * 3 + 0 ] < texcoords[ indices[ end ] * 3 + 0 ] )
00508                         {
00509                             newS = texcoords[ indices[ start ]* 3 + 0 ] + 1.0f;
00510                         }
00511                         else
00512                         {
00513                             theOneToChange = end;
00514                             newS = texcoords[ indices[ end ] * 3 + 0 ] + 1.0f;
00515                         }
00516                     }
00517 
00518                     if ( bDoS == true )
00519                     {
00520                         unsigned int theNewIndex = texcoords.size() / 3;
00521                         // Duplicate every part of the vertex
00522                         for ( unsigned int att = 0; att < output.size(); ++att )
00523                         {
00524                             // No new indices are created, just vertex attributes
00525                             if ( output[ att ].Name_ != "indices" )
00526                             {
00527                                 if ( output[ att ].Name_ == "tex0" ) 
00528                                 {
00529                                     output[ att ].floatVector_.push_back( newS ); // y
00530                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // x
00531                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z
00532                                 }
00533                                 else
00534                                 {
00535                                     // *3 b/c we are looking up 3vectors in an array of floats
00536                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x
00537                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // y
00538                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z
00539                                 }
00540                             }
00541                         }
00542 
00543                         IdenticalVertices_.push_back( EmptySet );
00544 
00545                         IdenticalVertices_[ indices[ theOneToChange ] ].insert( theNewIndex );
00546                         IdenticalVertices_[ theNewIndex ].insert( indices[ theOneToChange ] );
00547 
00548                         // point to where the new vertices will go
00549                         indices[ theOneToChange ] = theNewIndex;
00550                     }
00551 
00552                 } // for v
00553 
00554                 {
00555 
00556                 for ( int v = 0; v < 3; ++v )
00557                 {
00558                     int start = f + v;
00559                     int end = start + 1;
00560 
00561                     if ( v == 2 )
00562                     {
00563                         end = f;
00564                     }
00565 
00566                     float dT = texcoords[ indices[ end ] * 3 + 1 ] - texcoords[ indices[ start ] * 3 + 1 ];
00567 
00568                     float newT = nv_zero;
00569 
00570                     bool bDoT = false;
00571 
00572                     unsigned int theOneToChange = start;
00573 
00574                     if ( fabs( dT ) >= 0.5f )
00575                     {
00576                         bDoT = true;
00577                         if ( texcoords[ indices[ start ] * 3 + 1 ] < texcoords[ indices[ end ] * 3 + 1 ] )
00578                         {
00579                             newT = texcoords[ indices[ start ] * 3 + 1 ] + 1.0f;
00580                         }
00581                         else
00582                         {
00583                             theOneToChange = end;
00584                             newT = texcoords[ indices[ end ] * 3 + 1 ] + 1.0f;
00585                         }
00586                     }
00587 
00588                     if ( bDoT == true )
00589                     {
00590                         unsigned int theNewIndex = texcoords.size() / 3;
00591                         // Duplicate every part of the vertex
00592                         for ( unsigned int att = 0; att < output.size(); ++att )
00593                         {
00594                             // No new indices are created, just vertex attributes
00595                             if ( output[ att ].Name_ != "indices" )
00596                             {
00597                                 if ( output[ att ].Name_ == "tex0" ) 
00598                                 {
00599                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x
00600                                     output[ att ].floatVector_.push_back( newT ); // y
00601                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z
00602                                 }
00603                                 else
00604                                 {
00605                                     // *3 b/c we are looking up 3vectors in an array of floats
00606                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x
00607                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // y
00608                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z
00609                                 }
00610                             }
00611                         }
00612 
00613                         IdenticalVertices_.push_back( EmptySet );
00614 
00615                         IdenticalVertices_[ theNewIndex ].insert( indices[ theOneToChange ] );
00616                         IdenticalVertices_[ indices[ theOneToChange ] ].insert( theNewIndex );
00617 
00618                         // point to where the new vertices will go
00619                         indices[ theOneToChange ] = theNewIndex;
00620                     }
00621                 }
00622 
00623                 } // for v
00624 
00625             } // for f
00626         } // if fix texgen
00627         if (pTextureMatrix) {
00628             const mat4 M(   pTextureMatrix[0],  pTextureMatrix[1],  pTextureMatrix[2],  pTextureMatrix[3],
00629                             pTextureMatrix[4],  pTextureMatrix[5],  pTextureMatrix[6],  pTextureMatrix[7],
00630                             pTextureMatrix[8],  pTextureMatrix[9],  pTextureMatrix[10], pTextureMatrix[11],
00631                             pTextureMatrix[12], pTextureMatrix[13], pTextureMatrix[14], pTextureMatrix[15]);
00632             Mapping::iterator texIter = outmap.find("tex0");
00633             VertexAttribute::FloatVector& texcoords = output[(*texIter).second].floatVector_;
00634 
00635             // now apply matrix
00636             for (unsigned int v = 0; v < texcoords.size(); v += 3) {
00637                 vec3& V = *reinterpret_cast<vec3*>(&texcoords[v]);
00638                 V = V * M;
00639             }
00640         }
00641 
00642     }
00643 
00644     if ( bComputeTangentSpace )
00645     {
00646         Mapping::iterator texIter = outmap.find( "tex0" );
00647 
00648         vec3* tex = (vec3*)&( output[ (*texIter).second ].floatVector_[ 0 ] );
00649 
00650         typedef std::vector< vec3 > VecVector;
00651 
00652         // create tangents
00653         want = outmap.find( "tangent" );
00654         if ( want == outmap.end() )
00655         {
00656             VertexAttribute tanAtt;
00657             tanAtt.Name_ = "tangent";
00658             output.push_back( tanAtt );
00659             outmap[ "tangent" ] = output.size() - 1;
00660             want = outmap.find( "tangent" );
00661         }
00662         // just initialize array so it's the correct size
00663         output[ (*want).second ].floatVector_ = positions;
00664 
00665         // create binormals
00666         want = outmap.find( "binormal" );
00667         if ( want == outmap.end() )
00668         {
00669             VertexAttribute binAtt;
00670             binAtt.Name_ = "binormal";
00671             output.push_back( binAtt );
00672             outmap[ "binormal" ] = output.size() - 1;
00673             want = outmap.find( "binormal" );
00674         }
00675         // just initialize array so it's the correct size
00676         output[ (*want).second ].floatVector_ = positions;
00677 
00678         // Create a vector of s,t and sxt for each face of the model
00679         VecVector sVector;
00680         VecVector tVector;
00681         VecVector sxtVector;
00682 
00683         const unsigned int theSize = indices.size();
00684         // for each face, calculate its S,T & SxT vector, & store its edges
00685         for ( unsigned int f = 0; f < theSize; f += 3 )
00686         {
00687             vec3 edge0;
00688             vec3 edge1;
00689 
00690             vec3 s;
00691             vec3 t;
00692 
00693             // grap position & tex coords again in case they were reallocated
00694             pPositions = (vec3*)( &( positions[ 0 ] ) );
00695             tex = (vec3*)&( output[ (*texIter).second ].floatVector_[ 0 ] );
00696 
00697             // create an edge out of x, s and t
00698             edge0.x = pPositions[ indices[ f + 1 ] ].x - pPositions[ indices[ f ] ].x;
00699             edge0.y = tex[ indices[ f + 1 ] ].x - tex[ indices[ f ] ].x;
00700             edge0.z = tex[ indices[ f + 1 ] ].y - tex[ indices[ f ] ].y;
00701 
00702             // create an edge out of x, s and t
00703             edge1.x = pPositions[ indices[ f + 2 ] ].x - pPositions[ indices[ f ] ].x;
00704             edge1.y = tex[ indices[ f + 2 ] ].x - tex[ indices[ f ] ].x;
00705             edge1.z = tex[ indices[ f + 2 ] ].y - tex[ indices[ f ] ].y;
00706 
00707             vec3 sxt = edge0 ^ edge1;
00708 
00709             float a = sxt.x;
00710             float b = sxt.y;
00711             float c = sxt.z;
00712 
00713             float ds_dx = nv_zero;
00714             if ( fabs( a ) > nv_eps )
00715             {
00716                 ds_dx = - b / a;
00717             }
00718 
00719             float dt_dx = nv_zero;
00720             if ( fabs( a ) > nv_eps )
00721             {
00722                 dt_dx = - c / a;
00723             }
00724 
00725             // create an edge out of y, s and t
00726             edge0.x = pPositions[ indices[ f + 1 ] ].y - pPositions[ indices[ f ] ].y;
00727             // create an edge out of y, s and t
00728             edge1.x = pPositions[ indices[ f + 2 ] ].y - pPositions[ indices[ f ] ].y;
00729 
00730             sxt = edge0 ^ edge1;
00731 
00732             a = sxt.x;
00733             b = sxt.y;
00734             c = sxt.z;
00735 
00736             float ds_dy = nv_zero;
00737             if ( fabs( a ) > nv_eps )
00738             {
00739                 ds_dy = -b / a;
00740             }
00741 
00742             float dt_dy = nv_zero;
00743             if ( fabs( a ) > nv_eps )
00744             {
00745                 dt_dy = -c / a;
00746             }
00747 
00748             // create an edge out of z, s and t
00749             edge0.x = pPositions[ indices[ f + 1 ] ].z - pPositions[ indices[ f ] ].z;
00750             // create an edge out of z, s and t
00751             edge1.x = pPositions[ indices[ f + 2 ] ].z - pPositions[ indices[ f ] ].z;
00752 
00753             sxt = edge0 ^ edge1;
00754 
00755             a = sxt.x;
00756             b = sxt.y;
00757             c = sxt.z;
00758 
00759             float ds_dz = nv_zero;
00760             if ( fabs( a ) > nv_eps )
00761             {
00762                 ds_dz = -b / a;
00763             }
00764 
00765             float dt_dz = nv_zero;
00766             if ( fabs( a ) > nv_eps )
00767             {
00768                 dt_dz = -c / a;
00769             }
00770 
00771             // generate coordinate frame from the gradients
00772             s = vec3( ds_dx, ds_dy, ds_dz );
00773             t = vec3( dt_dx, dt_dy, dt_dz );
00774 
00775             s.normalize();
00776             t.normalize();
00777             sxt = s ^ t;
00778             sxt.normalize();
00779 
00780             // save vectors for this face
00781             sVector.push_back( s );
00782             tVector.push_back( t );
00783             sxtVector.push_back( sxt );
00784 
00785             if ( _FixTangents == FixTangents )
00786             {
00787                 // Look for each edge of the triangle in the edge map, in order to find 
00788                 //  a neighboring face along the edge
00789 
00790                 for ( int e = 0; e < 3; ++e )
00791                 {
00792                     Edge edge;
00793 
00794                     int start = f + e;
00795                     int end = start + 1;
00796 
00797                     if ( e == 2 )
00798                     {
00799                         end = f;
00800                     }
00801                     // order vertex indices ( low, high )
00802                     edge.v0 = (unsigned int)nv_min( (nv_scalar)indices[ start ], (nv_scalar)indices[ end ] );
00803                     edge.v1 = (unsigned int)nv_max( (nv_scalar)indices[ start ], (nv_scalar)indices[ end ] );
00804 
00805                     EdgeSet Edges;
00806 
00807                     EdgeSet::iterator iter = Edges.find( edge );
00808 
00809                     // if we are the only triangle with this edge...
00810                     if ( iter == Edges.end() )
00811                     {
00812                         // ...then add us to the set of edges
00813                         edge.face = f / 3;
00814                         Edges.insert( edge );
00815                     }
00816                     else
00817                     {
00818                         // otherwise, check our neighbor's s,t & sxt vectors vs our own
00819                         const float sAgreement = dot(s, sVector[(*iter).face]);
00820                         const float tAgreement = dot(t, tVector[(*iter).face]);
00821                         const float sxtAgreement = dot(sxt, sxtVector[(*iter).face]);
00822 
00823                         // Check Radian angle split limit
00824                         const float epsilon = (float)cos( bSmoothCreaseAngleRadians );
00825 
00826                         //  if the discontinuity in s, t, or sxt is greater than some epsilon,
00827                         //   duplicate the vertex so it won't smooth with its neighbor anymore
00828 
00829                         if ( ( fabs(   sAgreement ) < epsilon ) ||
00830                              ( fabs(   tAgreement ) < epsilon ) ||
00831                              ( fabs( sxtAgreement ) < epsilon ) )
00832                         {
00833                             // Duplicate two vertices of this edge for this triangle only.
00834                             //  This way the faces won't smooth with each other, thus
00835                             //  preventing the tangent basis from becoming degenerate
00836 
00837                             //  divide by 3 b/c vector is of floats and not vectors
00838                             const unsigned int theNewIndex = positions.size() / 3;
00839 
00840                             // Duplicate every part of the vertex
00841                             for ( unsigned int att = 0; att < output.size(); ++att )
00842                             {
00843                                 // No new indices are created, just vertex attributes
00844                                 if ( output[ att ].Name_ != "indices" )
00845                                 {
00846                                     // *3 b/c we are looking up 3vectors in an array of floats
00847                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 0 ] ); // x
00848                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 1 ] ); // y
00849                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 2 ] ); // z
00850 
00851                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 0 ] ); // x
00852                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 1 ] ); // y
00853                                     output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 2 ] ); // z
00854                                 }
00855                             }
00856 
00857                             IdenticalVertices_.push_back( EmptySet );
00858                             IdenticalVertices_.push_back( EmptySet );
00859 
00860                             // point to where the new vertices will go
00861                             indices[ start ] = theNewIndex;
00862                             indices[ end ] =   theNewIndex + 1;
00863 
00864                         }
00865 
00866                         // Now that the vertices are duplicated, smoothing won't occur over this edge,
00867                         //  because the two faces will sum their tangent basis vectors into separate indices 
00868                     }
00869                 }
00870             } // if fixtangents
00871         }
00872 
00873         // Allocate std::vector & Zero out average basis for tangent space smoothing
00874         VecVector avgS;
00875         VecVector avgT;
00876 
00877         for ( unsigned int p = 0; p < positions.size(); p += 3 )
00878         {
00879             avgS.push_back( vec3_null ); // do S
00880             avgT.push_back( vec3_null ); // now t
00881         }
00882 
00883         //  go through faces and add up the bases for each vertex 
00884         const int theFaceCount = indices.size() / 3;
00885 
00886         for ( unsigned int face = 0; face < (unsigned int)theFaceCount; ++face )
00887         {
00888             // sum bases, so we smooth the tangent space across edges
00889             avgS[ pIndices[ face * 3 ] ] +=   sVector[ face ];
00890             avgT[ pIndices[ face * 3 ] ] +=   tVector[ face ];
00891 
00892             avgS[ pIndices[ face * 3 + 1 ] ] +=   sVector[ face ];
00893             avgT[ pIndices[ face * 3 + 1 ] ] +=   tVector[ face ];
00894 
00895             avgS[ pIndices[ face * 3 + 2 ] ] +=   sVector[ face ];
00896             avgT[ pIndices[ face * 3 + 2 ] ] +=   tVector[ face ];
00897         }
00898 
00899         if ( _FixCylindricalTexGen == FixCylindricalTexGen )
00900         {
00901             for ( unsigned int v = 0; v < IdenticalVertices_.size(); ++v )
00902             {
00903                 // go through each vertex & sum up it's true neighbors
00904                 for ( std::set< unsigned int >::iterator iter = IdenticalVertices_[ v ].begin();
00905                       iter != IdenticalVertices_[ v ].end();
00906                       ++iter )
00907                 {
00908                     avgS[ v ] += avgS[ *iter ];
00909                     avgT[ v ] += avgT[ *iter ];
00910                 }
00911             }
00912         }
00913 
00914         Mapping::iterator tangent = outmap.find( "tangent" );
00915         Mapping::iterator binormal = outmap.find( "binormal" );
00916 
00917         // now renormalize
00918         for ( unsigned int b = 0; b < positions.size(); b += 3 ) 
00919         {
00920             *reinterpret_cast<vec3*>(&output[(*tangent).second].floatVector_[b]) = normalize(avgS[b / 3]);  // s
00921             *reinterpret_cast<vec3*>(&output[(*binormal).second].floatVector_[b]) = normalize(avgT[b / 3]);  // T
00922         }
00923     }
00924 
00925     // At this point, tex coords, normals, binormals and tangents should be generated if necessary,
00926     //  and other attributes are simply copied as available
00927 
00928     return true;
00929 }
00930 

Generated on Thu Apr 6 15:25:39 2006 for rcssserver3d by  doxygen 1.4.4