void MSConnectivityScore::add_edges_to_set(NNGraph &G, EdgeSet &edge_set) const { boost::property_map<NNGraph, boost::vertex_name_t>::type vertex_id = boost::get(boost::vertex_name, G); NNGraph ng(num_vertices(G)); Ints vertex_id_to_n(restraint_.particle_matrix_.size(), -1); for (unsigned int i = 0; i < num_vertices(ng); ++i) { unsigned int id = boost::get(vertex_id, i); vertex_id_to_n[id] = i; } for (EdgeSet::iterator p = edge_set.begin(); p != edge_set.end(); ++p) { unsigned int i_from = vertex_id_to_n[(*p).first]; unsigned int i_to = vertex_id_to_n[(*p).second]; add_edge(i_from, i_to, ng); } Ints components(num_vertices(ng)); int ncomp = boost::connected_components(ng, &components[0]); if (ncomp == 1) return; Vector<std::pair<unsigned int, unsigned int> > candidates; NNGraph::edge_iterator e, end; for (boost::tie(e, end) = edges(G); e != end; ++e) { unsigned int src = boost::get(vertex_id, source(*e, G)); unsigned int dst = boost::get(vertex_id, target(*e, G)); if (src > dst) std::swap(src, dst); std::pair<unsigned int, unsigned int> candidate = std::make_pair(src, dst); if (edge_set.find(candidate) == edge_set.end()) candidates.push_back(candidate); } std::sort(candidates.begin(), candidates.end(), EdgeScoreComparator(restraint_)); unsigned int idx = 0; while (ncomp > 1 && idx < candidates.size()) { unsigned int i_from = vertex_id_to_n[candidates[idx].first]; unsigned int i_to = vertex_id_to_n[candidates[idx].second]; if (components[i_from] != components[i_to]) { int old_comp = components[i_to]; for (unsigned int i = 0; i < components.size(); ++i) if (components[i] == old_comp) components[i] = components[i_from]; --ncomp; edge_set.insert(candidates[idx]); } ++idx; } BOOST_ASSERT(ncomp == 1); }
bool NVMeshMender::MungeD3DX( const NVMeshMender::VAVector& input, NVMeshMender::VAVector& output, const float bSmoothCreaseAngleRadians, const float* pTextureMatrix, const Option _FixTangents, const Option _FixCylindricalTexGen, const Option _WeightNormalsByFaceSize ) { typedef std::map< std::string, unsigned int > Mapping; typedef std::set< Edge > EdgeSet; typedef std::vector< std::set< unsigned int > > IdenticalVertices; IdenticalVertices IdenticalVertices_; Mapping inmap; Mapping outmap; for ( unsigned int a = 0; a < input.size(); ++a ) { inmap[ input[ a ].Name_ ] = a; } for ( unsigned int b = 0; b < output.size(); ++b ) { output[ b ].intVector_.clear(); output[ b ].floatVector_.clear(); outmap[ output[ b ].Name_ ] = b; } for ( unsigned int c = 0; c < output.size(); ++c ) { // for every output that has a match in the input, just copy it over Mapping::iterator in = inmap.find( output[ c ].Name_ ); if ( in != inmap.end() ) { // copy over existing indices, position, or whatever output[ c ] = input[ (*in).second ]; } } Mapping::iterator want = outmap.find( "indices" ); Mapping::iterator have = inmap.find( "indices" ); if ( have == inmap.end() ) { SetLastError( "Missing indices from input" ); return false; } if ( want == outmap.end() ) { SetLastError( "Missing indices from output" ); return false; } // Go through all required outputs & generate as necessary want = outmap.find( "position" ); have = inmap.find( "position" ); if ( have == inmap.end() ) { SetLastError( "Missing position from input" ); return false; } if ( want == outmap.end() ) { SetLastError( "Missing position from output" ); return false; } Mapping::iterator pos = outmap.find( "position" ); VertexAttribute::FloatVector& positions = output[ (*pos).second ].floatVector_; D3DXVECTOR3* pPositions = (D3DXVECTOR3*)( &( positions[ 0 ] ) ); std::set< unsigned int > EmptySet; for ( unsigned int i = 0; i < positions.size(); i += 3 ) { IdenticalVertices_.push_back( EmptySet ); } // initialize all attributes for ( unsigned int att = 0; att < output.size(); ++att ) { if ( output[ att ].Name_ != "indices" ) { if ( output[ att ].floatVector_.size() == 0 ) { output[ att ].floatVector_ = positions; } } } Mapping::iterator ind = outmap.find( "indices" ); VertexAttribute::IntVector& indices = output[ (*ind).second ].intVector_; int* pIndices = (int*)( &( indices[ 0 ] ) ); D3DXVECTOR3* pNormals = 0; D3DXVECTOR3* pBiNormals = 0; D3DXVECTOR3* pTangents = 0; D3DXVECTOR3* pTex0 = 0; bool bNeedNormals = false; bool bNeedTexCoords = false; bool bComputeTangentSpace = false; // see if texture coords are needed if ( outmap.find( "tex0" ) != outmap.end() ) { bNeedTexCoords = true; } // see if tangent or binormal are needed if ( ( outmap.find( "binormal" ) != outmap.end() ) || ( outmap.find( "tangent" ) != outmap.end() ) ) { bComputeTangentSpace = true; } // see if normals are needed if ( outmap.find( "normal" ) != outmap.end() ) { bNeedNormals = true; } // Compute normals. want = outmap.find( "normal" ); have = inmap.find( "normal" ); bool have_normals = ( inmap.find( "normal" ) != inmap.end() ) ? true : false; if ( bNeedNormals || bComputeTangentSpace ) { // see if normals are provided if ( !have_normals ) { // create normals if ( want == outmap.end() ) { VertexAttribute norAtt; norAtt.Name_ = "normal"; output.push_back( norAtt ); outmap[ "normal" ] = output.size() - 1; want = outmap.find( "normal" ); } // just initialize array so it's the correct size output[ (*want).second ].floatVector_ = positions; VertexAttribute::FloatVector& normals = output[ (*want).second ].floatVector_; // zero out normals for ( unsigned n = 0; n < positions.size(); ++n ) { output[ (*want).second ].floatVector_[ n ] = 0.0f; } pNormals = (D3DXVECTOR3*)( &( output[ (*want).second ].floatVector_[0] ) ); // calculate face normals for each face // & add its normal to vertex normal total for ( unsigned int t = 0; t < indices.size(); t += 3 ) { D3DXVECTOR3 edge0, nedge0; D3DXVECTOR3 edge1, nedge1; edge0 = pPositions[ indices[ t + 1 ] ] - pPositions[ indices[ t + 0 ] ]; edge1 = pPositions[ indices[ t + 2 ] ] - pPositions[ indices[ t + 0 ] ]; D3DXVec3Normalize(&nedge0, &edge0); D3DXVec3Normalize(&nedge1, &edge1); D3DXVECTOR3 faceNormal; D3DXVec3Cross( &faceNormal, &nedge0, &nedge1 ); if ( _WeightNormalsByFaceSize == DontWeightNormalsByFaceSize ) { // Renormalize face normal, so it's not weighted by face size D3DXVec3Normalize( &faceNormal, &faceNormal ); } else { // Leave it as-is, to weight by face size naturally by the cross product result } pNormals[ indices[ t + 0 ] ] += faceNormal; pNormals[ indices[ t + 1 ] ] += faceNormal; pNormals[ indices[ t + 2 ] ] += faceNormal; } // Renormalize each vertex normal for ( unsigned int v = 0; v < output[ (*want).second ].floatVector_.size() / 3; ++v ) { D3DXVec3Normalize( &( pNormals[ v ] ), &( pNormals[ v ] ) ); } } } // Compute texture coordinates. if ( bNeedTexCoords || bComputeTangentSpace ) { have = inmap.find( "tex0" ); want = outmap.find("tex0"); bool have_texcoords = (inmap.find( "tex0" ) != inmap.end()) ? true : false; // see if texcoords are provided if ( !have_texcoords ) { // compute texcoords. if ( want == outmap.end() ) { VertexAttribute texCoordAtt; texCoordAtt.Name_ = "tex0"; output.push_back( texCoordAtt ); outmap[ "tex0" ] = output.size() - 1; want = outmap.find( "tex0" ); } // just initialize array so it's the correct size output[ (*want).second ].floatVector_ = positions; pTex0 = (D3DXVECTOR3*)( &(output[ (*want).second ].floatVector_[ 0 ]) ); // Generate cylindrical coordinates // Find min and max positions for object bounding box D3DXVECTOR3 maxPosition( -FLT_MAX, -FLT_MAX, -FLT_MAX ); D3DXVECTOR3 minPosition( FLT_MAX, FLT_MAX, FLT_MAX ); // there are 1/3 as many vectors as floats const unsigned int theCount = static_cast<unsigned int>(positions.size() / 3.0f); for ( unsigned int i = 0; i < theCount; ++i ) { #ifndef __GNUC__ maxPosition.x = max( maxPosition.x, pPositions[ i ].x ); maxPosition.y = max( maxPosition.y, pPositions[ i ].y ); maxPosition.z = max( maxPosition.z, pPositions[ i ].z ); minPosition.x = min( minPosition.x, pPositions[ i ].x ); minPosition.y = min( minPosition.y, pPositions[ i ].y ); minPosition.z = min( minPosition.z, pPositions[ i ].z ); #endif } // Find major, minor and other axis for cylindrical texgen D3DXVECTOR3 delta = maxPosition - minPosition; delta.x = (float)fabs( delta.x ); delta.y = (float)fabs( delta.y ); delta.z = (float)fabs( delta.z ); bool maxx,maxy,maxz; maxx = maxy = maxz = false; bool minz,miny,minx; minx = miny = minz = false; float deltaMajor; if ( ( delta.x >= delta.y ) && ( delta.x >= delta.z ) ) { maxx = true; deltaMajor = delta.x; if ( delta.y > delta.z ) { minz = true; } else { miny = true; } } else if ( ( delta.z >= delta.y ) && ( delta.z >= delta.x ) ) { maxz = true; deltaMajor = delta.z; if ( delta.y > delta.x ) { minx = true; } else { miny = true; } } else if ( ( delta.y >= delta.z ) && ( delta.y >= delta.x ) ) { maxy = true; deltaMajor = delta.y; if ( delta.x > delta.z ) { minz = true; } else { minx = true; } } for ( unsigned int p = 0; p < theCount; ++p ) { // Find position relative to center of bounding box D3DXVECTOR3 texCoords = ( ( maxPosition + minPosition ) / 2.0f ) - pPositions[ p ]; float Major, Minor, Other = 0.0f; if ( maxx ) { Major = texCoords.x; if ( miny ) { Minor = texCoords.y; Other = texCoords.z; } else { Minor = texCoords.z; Other = texCoords.y; } } else if ( maxy ) { Major = texCoords.y; if ( minx ) { Minor = texCoords.x; Other = texCoords.z; } else { Minor = texCoords.z; Other = texCoords.x; } } else if ( maxz ) { Major = texCoords.z; if ( miny ) { Minor = texCoords.y; Other = texCoords.x; } else { Minor = texCoords.x; Other = texCoords.y; } } float longitude = 0.0f; // Prevent zero or near-zero from being passed into atan2 if ( fabs( Other ) < 0.0001f ) { if ( Other >= 0.0f ) { Other = 0.0001f; } else { Other = -0.0001f; } } // perform cylindrical mapping onto object, and remap from -pi,pi to -1,1 longitude = (float)(( atan2( Minor, Other ) ) / 3.141592654); texCoords.x = 0.5f * longitude + 0.5f; texCoords.y = (Major/deltaMajor) + 0.5f; #ifndef __GNUC__ texCoords.x = max( texCoords.x, 0.0f ); texCoords.y = max( texCoords.y, 0.0f ); texCoords.x = min( texCoords.x, 1.0f ); texCoords.y = min( texCoords.y, 1.0f ); #endif pTex0[ p ].x = texCoords.x-0.25f; if ( pTex0[ p ].x < 0.0f ) pTex0[ p ].x += 1.0; pTex0[ p ].y = 1.0f-texCoords.y; pTex0[ p ].z = 1.0f; } } if ( _FixCylindricalTexGen == FixCylindricalTexGen ) { Mapping::iterator texIter = outmap.find( "tex0" ); VertexAttribute::FloatVector& texcoords = ( output[ (*texIter).second ].floatVector_ ); const unsigned int theSize = indices.size(); for ( unsigned int f = 0; f < theSize; f += 3 ) { for ( int v = 0; v < 3; ++v ) { int start = f + v; int end = start + 1; if ( v == 2 ) { end = f; } float dS = texcoords[ indices[ end ] * 3 + 0 ] - texcoords[ indices[ start ] * 3 + 0 ]; float newS = 0.0f; bool bDoS = false; unsigned int theOneToChange = start; if ( fabs( dS ) >= 0.5f ) { bDoS = true; if ( texcoords[ indices[ start ] * 3 + 0 ] < texcoords[ indices[ end ] * 3 + 0 ] ) { newS = texcoords[ indices[ start ]* 3 + 0 ] + 1.0f; } else { theOneToChange = end; newS = texcoords[ indices[ end ] * 3 + 0 ] + 1.0f; } } if ( bDoS == true ) { unsigned int theNewIndex = texcoords.size() / 3; // Duplicate every part of the vertex for ( unsigned int att = 0; att < output.size(); ++att ) { // No new indices are created, just vertex attributes if ( output[ att ].Name_ != "indices" ) { if ( output[ att ].Name_ == "tex0" ) { output[ att ].floatVector_.push_back( newS ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // x output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z } else { // *3 b/c we are looking up 3vectors in an array of floats output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z } } } IdenticalVertices_.push_back( EmptySet ); IdenticalVertices_[ indices[ theOneToChange ] ].insert( theNewIndex ); IdenticalVertices_[ theNewIndex ].insert( indices[ theOneToChange ] ); // point to where the new vertices will go indices[ theOneToChange ] = theNewIndex; } } // for v { for ( int v = 0; v < 3; ++v ) { int start = f + v; int end = start + 1; if ( v == 2 ) { end = f; } float dT = texcoords[ indices[ end ] * 3 + 1 ] - texcoords[ indices[ start ] * 3 + 1 ]; float newT = 0.0f; bool bDoT = false; unsigned int theOneToChange = start; if ( fabs( dT ) >= 0.5f ) { bDoT = true; if ( texcoords[ indices[ start ] * 3 + 1 ] < texcoords[ indices[ end ] * 3 + 1 ] ) { newT = texcoords[ indices[ start ] * 3 + 1 ] + 1.0f; } else { theOneToChange = end; newT = texcoords[ indices[ end ] * 3 + 1 ] + 1.0f; } } if ( bDoT == true ) { unsigned int theNewIndex = texcoords.size() / 3; // Duplicate every part of the vertex for ( unsigned int att = 0; att < output.size(); ++att ) { // No new indices are created, just vertex attributes if ( output[ att ].Name_ != "indices" ) { if ( output[ att ].Name_ == "tex0" ) { output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x output[ att ].floatVector_.push_back( newT ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z } else { // *3 b/c we are looking up 3vectors in an array of floats output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 0 ] ); // x output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 1 ] ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ theOneToChange ] * 3 + 2 ] ); // z } } } IdenticalVertices_.push_back( EmptySet ); IdenticalVertices_[ theNewIndex ].insert( indices[ theOneToChange ] ); IdenticalVertices_[ indices[ theOneToChange ] ].insert( theNewIndex ); // point to where the new vertices will go indices[ theOneToChange ] = theNewIndex; } } } // for v } // for f } // if fix texgen D3DXMATRIX theMatrix( 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,2); D3DXVECTOR3 v(1, 2, 3); D3DXVec3TransformCoord( &v, &v, &theMatrix); if ( pTextureMatrix ) { Mapping::iterator texIter = outmap.find( "tex0" ); VertexAttribute::FloatVector& texcoords = ( output[ (*texIter).second ].floatVector_ ); // now apply matrix for ( unsigned int v = 0; v < texcoords.size(); v += 3 ) { D3DXVECTOR3* pVector = (D3DXVECTOR3*)( &( texcoords[ v ] ) ); D3DXMATRIX theMatrix( pTextureMatrix[ 0 ], pTextureMatrix[ 1 ], pTextureMatrix[ 2 ], pTextureMatrix[ 3 ], pTextureMatrix[ 4 ], pTextureMatrix[ 5 ], pTextureMatrix[ 6 ], pTextureMatrix[ 7 ], pTextureMatrix[ 8 ], pTextureMatrix[ 9 ], pTextureMatrix[ 10], pTextureMatrix[ 11], pTextureMatrix[ 12], pTextureMatrix[ 13], pTextureMatrix[ 14], pTextureMatrix[ 15] ); D3DXVec3TransformCoord( pVector, pVector, (D3DXMATRIX*)(pTextureMatrix)); } } } if ( bComputeTangentSpace ) { Mapping::iterator texIter = outmap.find( "tex0" ); D3DXVECTOR3* tex = (D3DXVECTOR3*)&( output[ (*texIter).second ].floatVector_[ 0 ] ); typedef std::vector< D3DXVECTOR3 > VecVector; // create tangents want = outmap.find( "tangent" ); if ( want == outmap.end() ) { VertexAttribute tanAtt; tanAtt.Name_ = "tangent"; output.push_back( tanAtt ); outmap[ "tangent" ] = output.size() - 1; want = outmap.find( "tangent" ); } // just initialize array so it's the correct size output[ (*want).second ].floatVector_ = positions; // create binormals want = outmap.find( "binormal" ); if ( want == outmap.end() ) { VertexAttribute binAtt; binAtt.Name_ = "binormal"; output.push_back( binAtt ); outmap[ "binormal" ] = output.size() - 1; want = outmap.find( "binormal" ); } // just initialize array so it's the correct size output[ (*want).second ].floatVector_ = positions; // Create a vector of s,t and sxt for each face of the model VecVector sVector; VecVector tVector; VecVector sxtVector; EdgeSet Edges; const unsigned int theSize = indices.size(); // for each face, calculate its S,T & SxT vector, & store its edges for ( unsigned int f = 0; f < theSize; f += 3 ) { D3DXVECTOR3 edge0; D3DXVECTOR3 edge1; D3DXVECTOR3 s; D3DXVECTOR3 t; // grap position & tex coords again in case they were reallocated pPositions = (D3DXVECTOR3*)( &( positions[ 0 ] ) ); tex = (D3DXVECTOR3*)&( output[ (*texIter).second ].floatVector_[ 0 ] ); // create an edge out of x, s and t edge0.x = pPositions[ indices[ f + 1 ] ].x - pPositions[ indices[ f ] ].x; edge0.y = tex[ indices[ f + 1 ] ].x - tex[ indices[ f ] ].x; edge0.z = tex[ indices[ f + 1 ] ].y - tex[ indices[ f ] ].y; // create an edge out of x, s and t edge1.x = pPositions[ indices[ f + 2 ] ].x - pPositions[ indices[ f ] ].x; edge1.y = tex[ indices[ f + 2 ] ].x - tex[ indices[ f ] ].x; edge1.z = tex[ indices[ f + 2 ] ].y - tex[ indices[ f ] ].y; D3DXVECTOR3 sxt; D3DXVec3Cross( &sxt, &edge0, &edge1 ); float a = sxt.x; float b = sxt.y; float c = sxt.z; float ds_dx = 0.0f; if ( fabs( a ) > 0.000001f ) { ds_dx = - b / a; } float dt_dx = 0.0f; if ( fabs( a ) > 0.000001f ) { dt_dx = - c / a; } // create an edge out of y, s and t edge0.x = pPositions[ indices[ f + 1 ] ].y - pPositions[ indices[ f ] ].y; edge0.y = tex[ indices[ f + 1 ] ].x - tex[ indices[ f ] ].x; edge0.z = tex[ indices[ f + 1 ] ].y - tex[ indices[ f ] ].y; // create an edge out of y, s and t edge1.x = pPositions[ indices[ f + 2 ] ].y - pPositions[ indices[ f ] ].y; edge1.y = tex[ indices[ f + 2 ] ].x - tex[ indices[ f ] ].x; edge1.z = tex[ indices[ f + 2 ] ].y - tex[ indices[ f ] ].y; D3DXVec3Cross( &sxt, &edge0, &edge1 ); a = sxt.x; b = sxt.y; c = sxt.z; float ds_dy = 0.0f; if ( fabs( a ) > 0.000001f ) { ds_dy = -b / a; } float dt_dy = 0.0f; if ( fabs( a ) > 0.000001f ) { dt_dy = -c / a; } // create an edge out of z, s and t edge0.x = pPositions[ indices[ f + 1 ] ].z - pPositions[ indices[ f ] ].z; edge0.y = tex[ indices[ f + 1 ] ].x - tex[ indices[ f ] ].x; edge0.z = tex[ indices[ f + 1 ] ].y - tex[ indices[ f ] ].y; // create an edge out of z, s and t edge1.x = pPositions[ indices[ f + 2 ] ].z - pPositions[ indices[ f ] ].z; edge1.y = tex[ indices[ f + 2 ] ].x - tex[ indices[ f ] ].x; edge1.z = tex[ indices[ f + 2 ] ].y - tex[ indices[ f ] ].y; D3DXVec3Cross( &sxt, &edge0, &edge1 ); a = sxt.x; b = sxt.y; c = sxt.z; float ds_dz = 0.0f; if ( fabs( a ) > 0.000001f ) { ds_dz = -b / a; } float dt_dz = 0.0f; if ( fabs( a ) > 0.000001f ) { dt_dz = -c / a; } // generate coordinate frame from the gradients s = D3DXVECTOR3( ds_dx, ds_dy, ds_dz ); t = D3DXVECTOR3( dt_dx, dt_dy, dt_dz ); D3DXVec3Normalize(&s, &s); D3DXVec3Normalize(&t, &t); D3DXVec3Cross( &sxt, &s, &t ); D3DXVec3Normalize( &sxt, &sxt ); // save vectors for this face sVector.push_back( s ); tVector.push_back( t ); sxtVector.push_back( sxt ); if ( _FixTangents == FixTangents ) { // Look for each edge of the triangle in the edge map, in order to find // a neighboring face along the edge for ( int e = 0; e < 3; ++e ) { Edge edge; int start = f + e; int end = start + 1; if ( e == 2 ) { end = f; } #ifndef __GNUC__ // order vertex indices ( low, high ) edge.v0 = min( indices[ start ], indices[ end ] ); edge.v1 = max( indices[ start ], indices[ end ] ); #endif EdgeSet::iterator iter = Edges.find( edge ); // if we are the only triangle with this edge... if ( iter == Edges.end() ) { // ...then add us to the set of edges edge.face = f / 3; Edges.insert( edge ); } else { // otherwise, check our neighbor's s,t & sxt vectors vs our own const float sAgreement = D3DXVec3Dot( &s, &(sVector[ (*iter).face ]) ); const float tAgreement = D3DXVec3Dot( &t, &(tVector[ (*iter).face ]) ); const float sxtAgreement = D3DXVec3Dot( &sxt, &(sxtVector[ (*iter).face ]) ); // Check Radian angle split limit const float epsilon = (float)cos( bSmoothCreaseAngleRadians ); // if the discontinuity in s, t, or sxt is greater than some epsilon, // duplicate the vertex so it won't smooth with its neighbor anymore if ( ( fabs( sAgreement ) < epsilon ) || ( fabs( tAgreement ) < epsilon ) || ( fabs( sxtAgreement ) < epsilon ) ) { // Duplicate two vertices of this edge for this triangle only. // This way the faces won't smooth with each other, thus // preventing the tangent basis from becoming degenerate // divide by 3 b/c vector is of floats and not vectors const unsigned int theNewIndex = positions.size() / 3; // Duplicate every part of the vertex for ( unsigned int att = 0; att < output.size(); ++att ) { // No new indices are created, just vertex attributes if ( output[ att ].Name_ != "indices" ) { // *3 b/c we are looking up 3vectors in an array of floats output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 0 ] ); // x output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 1 ] ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ start ] * 3 + 2 ] ); // z output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 0 ] ); // x output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 1 ] ); // y output[ att ].floatVector_.push_back( output[ att ].floatVector_[ indices[ end ] * 3 + 2 ] ); // z } } IdenticalVertices_.push_back( EmptySet ); IdenticalVertices_.push_back( EmptySet ); // point to where the new vertices will go indices[ start ] = theNewIndex; indices[ end ] = theNewIndex + 1; } // Now that the vertices are duplicated, smoothing won't occur over this edge, // because the two faces will sum their tangent basis vectors into separate indices } } } // if fixtangents } // Allocate std::vector & Zero out average basis for tangent space smoothing VecVector avgS; VecVector avgT; for ( unsigned int p = 0; p < positions.size(); p += 3 ) { avgS.push_back( D3DXVECTOR3( 0.0f, 0.0f, 0.0f ) ); // do S avgT.push_back( D3DXVECTOR3( 0.0f, 0.0f, 0.0f ) ); // now t } // go through faces and add up the bases for each vertex const int theFaceCount = indices.size() / 3; for ( unsigned int face = 0; face < (unsigned int)theFaceCount; ++face ) { // sum bases, so we smooth the tangent space across edges avgS[ pIndices[ face * 3 ] ] += sVector[ face ]; avgT[ pIndices[ face * 3 ] ] += tVector[ face ]; avgS[ pIndices[ face * 3 + 1 ] ] += sVector[ face ]; avgT[ pIndices[ face * 3 + 1 ] ] += tVector[ face ]; avgS[ pIndices[ face * 3 + 2 ] ] += sVector[ face ]; avgT[ pIndices[ face * 3 + 2 ] ] += tVector[ face ]; } if ( _FixCylindricalTexGen == FixCylindricalTexGen ) { for ( unsigned int v = 0; v < IdenticalVertices_.size(); ++v ) { // go through each vertex & sum up it's true neighbors for ( std::set< unsigned int >::iterator iter = IdenticalVertices_[ v ].begin(); iter != IdenticalVertices_[ v ].end(); ++iter ) { avgS[ v ] += avgS[ *iter ]; avgT[ v ] += avgT[ *iter ]; } } } Mapping::iterator tangent = outmap.find( "tangent" ); Mapping::iterator binormal = outmap.find( "binormal" ); // now renormalize for ( unsigned int b = 0; b < positions.size(); b += 3 ) { D3DXVECTOR3* vecTangent = (D3DXVECTOR3*)&output[ (*tangent).second ].floatVector_[ b ]; D3DXVECTOR3* vecBinormals = (D3DXVECTOR3*)&output[ (*binormal).second ].floatVector_[ b ]; D3DXVec3Normalize( vecTangent, &avgS[ b / 3 ] ); // s D3DXVec3Normalize( vecBinormals, &avgT[ b / 3 ] ); // T } } // At this point, tex coords, normals, binormals and tangents should be generated if necessary, // and other attributes are simply copied as available return true; }
void Mesh::subdivideToRadius(Number radius, int subdivisions) { typedef std::map<std::pair<int,int>, int> EdgeSet; for (int s = 0; s < subdivisions; s++) { EdgeSet dividedEdges; //Take a copy of the number of face indices at the BEGINNING, so we don't go on forever for (int i = 0, n = indices.size(); i < n; i += 3) { int vi0 = indices[i]; int vi1 = indices[i+1]; int vi2 = indices[i+2]; Vertex* v0 = vertices[vi0]; Vertex* v1 = vertices[vi1]; Vertex* v2 = vertices[vi2]; //Midpoints Vector3 vm01 = ((*v0) + (*v1)) * 0.5f; Vector3 vm12 = ((*v1) + (*v2)) * 0.5f; Vector3 vm20 = ((*v2) + (*v0)) * 0.5f; //Normalize so they're pushed outwards to the sphere vm01 = vm01 * (radius / vm01.length()); vm12 = vm12 * (radius / vm12.length()); vm20 = vm20 * (radius / vm20.length()); std::pair<int,int> key01 = vi0 < vi1 ? std::pair<int,int>(vi0, vi1) : std::pair<int,int>(vi1, vi0), key12 = vi1 < vi2 ? std::pair<int,int>(vi1, vi2) : std::pair<int,int>(vi2, vi1), key20 = vi2 < vi0 ? std::pair<int,int>(vi2, vi0) : std::pair<int,int>(vi0, vi2); EdgeSet::iterator it01 = dividedEdges.find(key01); int vmi01; if (it01 != dividedEdges.end()) { vmi01 = it01->second; } else { vmi01 = vertices.size(); addVertex(vm01.x, vm01.y, vm01.z); dividedEdges[key01] = vmi01; } EdgeSet::iterator it12 = dividedEdges.find(key12); int vmi12; if (it12 != dividedEdges.end()) { vmi12 = it12->second; } else { vmi12 = vertices.size(); addVertex(vm12.x, vm12.y, vm12.z); dividedEdges[key12] = vmi12; } EdgeSet::iterator it20 = dividedEdges.find(key20); int vmi20; if (it20 != dividedEdges.end()) { vmi20 = it20->second; } else { vmi20 = vertices.size(); addVertex(vm20.x, vm20.y, vm20.z); dividedEdges[key20] = vmi20; } addIndexedFace(vi0, vmi01, vmi20); addIndexedFace(vi1, vmi12, vmi01); addIndexedFace(vi2, vmi20, vmi12); //Recycle the original face to be the new central face indices[i] = vmi01; indices[i+1] = vmi12; indices[i+2] = vmi20; } } }