コード例 #1
0
ファイル: Mesh.cpp プロジェクト: ElliotWood/max_nif_plugin
NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp, bool exportStrips)
{
	NiTriBasedGeomRef shape;
	NiTriBasedGeomDataRef data;

   //if (Exporter::mFixNormals) {
   //   FixNormals(grp.faces, grp.verts, grp.vnorms);
   //}

	if (exportStrips) {
      shape = new NiTriStrips();
      data = new NiTriStripsData(grp.faces, !mUseAlternateStripper);
	} else {
      shape = new NiTriShape();
      data = new NiTriShapeData(grp.faces);
	}

   if ( IsFallout3() || IsSkyrim() )
      shape->SetFlags( 14 );

   data->SetVertices(grp.verts);
   data->SetNormals(grp.vnorms);
   data->SetVertexIndices(grp.vidx);
   data->SetUVSetMap(grp.uvMapping);

   int nUVs = grp.uvs.size();
   if ( IsFallout3() || IsSkyrim() )
      nUVs = min(1, nUVs);
   data->SetUVSetCount(nUVs);
   for (int i =0;i<nUVs; ++i) {
	   data->SetUVSet(i, grp.uvs[i]);
   }

   //if (IsSkyrim() && grp.vcolors.size() == 0)
   //   grp.vcolors.resize(grp.verts.size(), Color4(1.0f,1.0f,1.0f,1.0f));

	if (mVertexColors && grp.vcolors.size() > 0)
	{
		bool allWhite = true;
		Color4 white(1.0f, 1.0f, 1.0f, 1.0f);
		for (int i=0,n=grp.vcolors.size();i<n; ++i) {
			if (white != grp.vcolors[i]) {
				allWhite = false; 
				break;
			}
		}
		if (!allWhite)
			data->SetVertexColors(grp.vcolors);
	}

	data->SetConsistencyFlags(CT_STATIC);
	shape->SetData(data);

   if (Exporter::mTangentAndBinormalExtraData && (Exporter::mNifVersionInt > VER_4_2_2_0))
   {
      // enable traditional tangents and binormals for non-oblivion meshes
      if ( !IsOblivion() && (Exporter::mNifVersionInt >= VER_10_0_1_0) )
         data->SetTspaceFlag( 0x01 );
	   shape->UpdateTangentSpace(Exporter::mTangentAndBinormalMethod);
   }

	parent->AddChild(DynamicCast<NiAVObject>(shape));

   NiAVObjectRef av(DynamicCast<NiAVObject>(shape));
   makeMaterial(av, mtl);
   shape->SetActiveMaterial(0);

	return shape;
}
コード例 #2
0
ファイル: Mesh.cpp プロジェクト: ElliotWood/max_nif_plugin
bool Exporter::makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t)
{
   if (!mExportSkin)
      return false;

   if (grp.verts.empty())
      return false;

   //get the skin modifier
   Modifier *mod = GetSkin(node);
   if (!mod)
      return false;

   ISkin *skin = (ISkin *) mod->GetInterface(I_SKIN);
   if (!skin)
      return false;

   ISkinContextData *skinData = skin->GetContextInterface(node);
   if (!skinData)
      return false;

   if (grp.strips.empty())
      strippify(grp);

   // Create new call back to finish export
   SkinInstance* si = new SkinInstance(this);
   mPostExportCallbacks.push_back(si);

   skin->GetSkinInitTM(node, si->bone_init_tm, false);
   skin->GetSkinInitTM(node, si->node_init_tm, true);

   si->shape = shape;

   // Get bone references (may not actually exist in proper structure at this time)
   int totalBones = skin->GetNumBones();
   si->boneWeights.resize(totalBones);
   si->boneList.resize(totalBones);
   for (int i=0; i<totalBones; ++i) {
      si->boneList[i] = getNode(skin->GetBone(i));
   }

   vector<int>& vidx = grp.vidx;
   int nv = vidx.size();
   for (int i=0; i<nv; ++i)
   {
      int vi = vidx[i];
      int nbones = skinData->GetNumAssignedBones(vi);
      for (int j=0; j<nbones; ++j)
      {
         SkinWeight sw;
         sw.index = i;
         sw.weight = skinData->GetBoneWeight(vi,j);
         int boneIndex = skinData->GetAssignedBone(vi,j);

         SkinInstance::SkinWeightList& weights = si->boneWeights[boneIndex];
         weights.push_back(sw);
      }         
   }

   // remove unused bones
   vector<NiNodeRef>::iterator bitr = si->boneList.begin();
   SkinInstance::BoneWeightList::iterator switr = si->boneWeights.begin();
   for (int i=0; i<totalBones; ++i) {
      vector<SkinWeight> &weights = (*switr);
      if (weights.empty())
      {
         bitr = si->boneList.erase(bitr);
         switr = si->boneWeights.erase(switr);
      }
      else
      {
         ++bitr, ++switr;
      }      
   }

   // Check for dismemberment
   if (IsFallout3() || IsSkyrim()) {
      Modifier *dismemberSkinMod = GetBSDismemberSkin(node);
      if (dismemberSkinMod)
      {
         if (IBSDismemberSkinModifier *disSkin = (IBSDismemberSkinModifier *) dismemberSkinMod->GetInterface(I_BSDISMEMBERSKINMODIFIER)){
            Tab<IBSDismemberSkinModifierData*> modData = disSkin->GetModifierData();
            if (modData.Count() >= 1) {
               IBSDismemberSkinModifierData* bsdsmd = modData[0];
               si->SkinInstConstructor = BSDismemberSkinInstance::Create;
               Tab<BSDSPartitionData> &flags = bsdsmd->GetPartitionFlags();
               GenericNamedSelSetList &fselSet = bsdsmd->GetFaceSelList();

               FaceMap fmap;
               NiTriBasedGeomDataRef data = DynamicCast<NiTriBasedGeomData>(shape->GetData());
               vector<Triangle> tris = data->GetTriangles();
               for (int i=0; i<tris.size(); ++i) {
                  Triangle tri = tris[i];
                  fmap[ rotate(tri) ] = i;
               }
               // Build up list of partitions and face to partition map
               si->partitions.resize(flags.Count());
               si->facePartList.resize( grp.faces.size(), -1 );
               for (int i=0; i<flags.Count(); ++i) {
                  BodyPartList& bp = si->partitions[i];
                  bp.bodyPart = (BSDismemberBodyPartType)flags[i].bodyPart;
                  bp.partFlag = (BSPartFlag)(flags[i].partFlag | PF_START_NET_BONESET);

                  BitArray& fSelect = fselSet[i];
                  for (int j=0; j<fSelect.GetSize(); ++j){
                     if ( fSelect[j] ) {
                        Triangle tri = grp.faces[grp.fidx[j]];
                        FaceMap::iterator fitr = fmap.find( rotate(tri) );
                        if (fitr != fmap.end())
                           si->facePartList[ (*fitr).second ] = i;
                     }
                  }
               }
            }
         }
      }
   }


   return true;
}
コード例 #3
0
bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triGeom, NiTriBasedGeomDataRef triGeomData, vector<Triangle>& tris)
{
   Mesh& mesh = o->GetMesh();
   INode *tnode = node->GetINode();

   Matrix44 baseTM = (importBones) ? triGeom->GetLocalTransform() : triGeom->GetWorldTransform();
   node->SetTransform(0,TOMATRIX3(baseTM));  

   // Vertex info
   {
      int nVertices = triGeomData->GetVertexCount();
      vector<Vector3> vertices = triGeomData->GetVertices();
      mesh.setNumVerts(nVertices);
      for (int i=0; i < nVertices; ++i){
         Vector3 &v = vertices[i];
         mesh.verts[i].Set(v.x, v.y, v.z);
      }
   }
   // uv texture info
   {
      int nUVSet = triGeomData->GetUVSetCount();
      mesh.setNumMaps(nUVSet + 1, TRUE);
      int n = 0, j = 0;
      for (int j=0; j<nUVSet; j++){
         vector<TexCoord> texCoords = triGeomData->GetUVSet(j);
         n = texCoords.size();
         if (j == 0)
         {
            mesh.setNumTVerts(n, TRUE);
            for (int i=0; i<n; ++i) {
               TexCoord& texCoord = texCoords[i];
               mesh.tVerts[i].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
            }
         }
         mesh.setMapSupport (j + 1, TRUE);
         mesh.setNumMapVerts(j + 1, n, TRUE);
         if ( UVVert *tVerts = mesh.mapVerts(j+1) ) {
            for (int i=0; i<n; ++i) {
               TexCoord& texCoord = texCoords[i];
               tVerts[i].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
            }
         }
      }
   }
   // Triangles and texture vertices
   SetTriangles(mesh, tris);
   SetNormals(mesh, tris, triGeomData->GetNormals() );

   vector<Color4> cv = triGeomData->GetColors();
   ImportVertexColor(tnode, o, tris, cv, 0);

   if (Mtl* m = ImportMaterialAndTextures(node, triGeom))
   {
      gi->GetMaterialLibrary().Add(m);
      node->GetINode()->SetMtl(m);
   }

   if (removeDegenerateFaces)
      mesh.RemoveDegenerateFaces();
   if (removeIllegalFaces)
      mesh.RemoveIllegalFaces();
   if (enableSkinSupport)
      ImportSkin(node, triGeom);
   if (weldVertices)
	   WeldVertices(mesh);

   i->AddNodeToScene(node);   

   INode *inode = node->GetINode();
   inode->EvalWorldState(0);

   // attach child
   if (INode *parent = GetNode(triGeom->GetParent()))
      parent->AttachChild(inode, 1);

   inode->Hide(triGeom->GetVisibility() ? FALSE : TRUE);

   if (enableAutoSmooth){
      mesh.AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE);
   }

   RegisterNode(triGeom, inode);
   return true;
}
コード例 #4
0
bool NifImporter::ImportMultipleGeometry(NiNodeRef parent, vector<NiTriBasedGeomRef>& glist)
{
   bool ok = true;
   if (glist.empty()) return false;

   ImpNode *node = i->CreateNode();
   if(!node) return false;

   INode *inode = node->GetINode();
   TriObject *triObject = CreateNewTriObject();
   node->Reference(triObject);

   string name = parent->GetName();
   node->SetName(wide(name).c_str());

   // Texture
   Mesh& mesh = triObject->GetMesh();

   vector< pair<int, int> > vert_range, tri_range;
   vector<Triangle> tris;
   vector<Vector3> verts;
   int submats = glist.size();

   // Build list of vertices and triangles.  Optional components like normals will be handled later.
   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr) {
      NiTriBasedGeomDataRef triGeomData = StaticCast<NiTriBasedGeomData>((*itr)->GetData());

      // Get verts and collapse local transform into them
      int nVertices = triGeomData->GetVertexCount();
      vector<Vector3> subverts = triGeomData->GetVertices();
      Matrix44 transform = (*itr)->GetLocalTransform();
      //Apply the transformations
      if (transform != Matrix44::IDENTITY) {
         for ( unsigned int i = 0; i < subverts.size(); ++i )
            subverts[i] = transform * subverts[i];
      }
      vert_range.push_back( pair<int,int>( verts.size(), verts.size() + subverts.size()) );
      verts.insert(verts.end(), subverts.begin(), subverts.end());

      vector<Triangle> subtris = triGeomData->GetTriangles();
      for (vector<Triangle>::iterator itr = subtris.begin(), end = subtris.end(); itr != end; ++itr) {
         (*itr).v1 += nVertices, (*itr).v2 += nVertices, (*itr).v3 += nVertices;
      }
      tri_range.push_back( pair<int,int>( tris.size(), tris.size() + subtris.size()) );
      tris.insert(tris.end(), subtris.begin(), subtris.end());
   }

   // Transform up-to-parent
   Matrix44 baseTM = (importBones) ? Matrix44::IDENTITY : parent->GetWorldTransform();
   node->SetTransform(0,TOMATRIX3(baseTM));  

   // Set vertices and triangles
   mesh.setNumVerts(verts.size());
   mesh.setNumTVerts(verts.size(), TRUE);
   for (int i=0, n=verts.size(); i < n; ++i){
      Vector3 &v = verts[i];
      mesh.verts[i].Set(v.x, v.y, v.z);
   }
   mesh.setNumFaces(tris.size());
   mesh.setNumTVFaces(tris.size());
   for (int submat=0; submat<submats; ++submat) {
      int t_start = tri_range[submat].first, t_end = tri_range[submat].second;
      for (int i=t_start; i<t_end; ++i) {
         Triangle& t = tris[i];
         Face& f = mesh.faces[i];
         f.setVerts(t.v1, t.v2, t.v3);
         f.Show();
         f.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS);
         f.setMatID(-1);
         TVFace& tf = mesh.tvFace[i];
         tf.setTVerts(t.v1, t.v2, t.v3);
      }
   }
   mesh.buildNormals();
   bool bSpecNorms = false;

   MultiMtl *mtl = NULL;
   int igeom = 0;
   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr, ++igeom) 
   {
      NiTriBasedGeomDataRef triGeomData = StaticCast<NiTriBasedGeomData>((*itr)->GetData());

      int v_start = vert_range[igeom].first, v_end = vert_range[igeom].second;
      int t_start = tri_range[igeom].first, t_end = tri_range[igeom].second;

      // Normals
      vector<Vector3> subnorms = triGeomData->GetNormals();
      Matrix44 rotation = (*itr)->GetLocalTransform().GetRotation();
      if (rotation != Matrix44::IDENTITY) {
         for ( unsigned int i = 0; i < subnorms.size(); ++i )
            subnorms[i] = rotation * subnorms[i];
      }
      if (!subnorms.empty())
      {
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 5
         // Initialize normals if necessary
         if (!bSpecNorms) {
            bSpecNorms = true;
            mesh.SpecifyNormals();
            MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
            if (NULL != specNorms) {
               specNorms->BuildNormals();
               //specNorms->ClearAndFree();
               //specNorms->SetNumFaces(tris.size());
               //specNorms->SetNumNormals(n.size());
            }
         }
         MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
         if (NULL != specNorms)
         {
            Point3* norms = specNorms->GetNormalArray();
            for (int i=0, n=subnorms.size(); i<n; i++){
               Vector3& v = subnorms[i];
               norms[i+v_start] = Point3(v.x, v.y, v.z);
            }
            //MeshNormalFace* pFaces = specNorms->GetFaceArray();
            //for (int i=0; i<tris.size(); i++){
            //   Triangle& tri = tris[i];
            //   MeshNormalFace& face = pFaces[i+t_start];
            //   face.SpecifyNormalID(0, tri.v1);
            //   face.SpecifyNormalID(1, tri.v2);
            //   face.SpecifyNormalID(2, tri.v3);
            //}
#if VERSION_3DSMAX > ((7000<<16)+(15<<8)+0) // Version 7+
			specNorms->SetAllExplicit(true);
#endif
            specNorms->CheckNormals();
         }
#endif
      }
      // uv texture info
      if (triGeomData->GetUVSetCount() > 0) {
         vector<TexCoord> texCoords = triGeomData->GetUVSet(0);
         for (int i=0, n = texCoords.size(); i<n; ++i) {
            TexCoord& texCoord = texCoords[i];
            mesh.tVerts[i+v_start].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
         }
      }
      vector<Color4> cv = triGeomData->GetColors();
      ImportVertexColor(inode, triObject, tris, cv, v_start);

      if ( StdMat2* submtl = ImportMaterialAndTextures(node, (*itr)) )
      {
         if (mtl == NULL) {
            mtl = NewDefaultMultiMtl();
            gi->GetMaterialLibrary().Add(mtl);
            inode->SetMtl(mtl);
         }
         // SubMatIDs do not have to be contiguous so we just use the offset
         mtl->SetSubMtlAndName(igeom, submtl, submtl->GetName());
         for (int i=t_start; i<t_end; ++i)
            mesh.faces[i].setMatID(igeom);
      }
      if (enableSkinSupport)
         ImportSkin(node, (*itr));
   }

   this->i->AddNodeToScene(node);   

   inode = node->GetINode();
   inode->EvalWorldState(0);

   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr) 
   {
      // attach child
      if (INode *parent = GetNode((*itr)->GetParent()))
         parent->AttachChild(inode, 1);
      inode->Hide((*itr)->GetVisibility() ? FALSE : TRUE);
   }
   if (removeDegenerateFaces)
      mesh.RemoveDegenerateFaces();
   if (removeIllegalFaces)
      mesh.RemoveIllegalFaces();
   if (weldVertices)
	   WeldVertices(mesh);
   if (enableAutoSmooth)
      mesh.AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE);
   return ok;
}
コード例 #5
0
ファイル: GenMopp.cpp プロジェクト: figment/nifcmd
static hkpSimpleMeshShape * ConstructHKMesh( NiTriBasedGeomRef shape )
{
	NiTriBasedGeomDataRef data = shape->GetData();
	return ConstructHKMesh(data->GetVertices(), data->GetTriangles());
}
コード例 #6
0
NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex ) {
   NiSkinInstanceRef skinInst = shape->GetSkinInstance();
   if ( skinInst == NULL ) {
      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinInstance found." );
   }
   NiSkinDataRef skinData = skinInst->GetSkinData();
   if ( skinData == NULL ) {
      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinData found." );
   }
   NiTriBasedGeomDataRef geomData = DynamicCast<NiTriBasedGeomData>(shape->GetData() );
   if ( geomData == NULL ) {
      throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." );
   }

      // read in the weights from NiSkinData
   vector<Vector3> verts = geomData->GetVertices();
   vector< BoneWeightList > weights;
   if (verts.empty()){
      throw runtime_error( "Attempted to generate a skin partition on a mesh with no vertices." );
   }

   Triangles triangles = geomData->GetTriangles();
   if (triangles.empty()) {
      throw runtime_error( "Attempted to generate a skin partition on a mesh with no triangles." );
   }

   weights.resize( verts.size() );
   int numBones = skinData->GetBoneCount();
   for ( int bone = 0; bone < numBones; bone++ )
   {
      vector<SkinWeight> vertexWeights = skinData->GetBoneWeights(bone);
      for (int r = 0; r < int(vertexWeights.size()); ++r ){
         int vertex = vertexWeights[r].index;
         float weight = vertexWeights[r].weight;
         if ( vertex >= int(weights.size()) )
            throw runtime_error( "bad NiSkinData - vertex count does not match" );
         weights[vertex].insert( weights[vertex].end(), BoneWeight(bone, weight) );
      }
   }

   // count min and max bones per vertex
   int minBones, maxBones;
   minBones = maxBones = weights[0].size();
   for(vector< BoneWeightList >::iterator itr = weights.begin(); itr != weights.end(); ++itr ){
      int n = (*itr).size();
      minBones = min(n, minBones);
      maxBones = max(n, maxBones);
   }

   if ( minBones <= 0 )
      throw runtime_error( "bad NiSkinData - some vertices have no weights at all" );

   // reduce vertex influences if necessary
   if ( maxBones > maxBonesPerVertex )
   {
      int c = 0;
      for ( vector< BoneWeightList >::iterator it = weights.begin(); it != weights.end(); ++it )
      {
         BoneWeightList & lst = *it;
         if ( int(lst.size()) > maxBonesPerVertex )
            c++;

         while ( int(lst.size()) > maxBonesPerVertex ) {
            int j = 0;
            float weight = lst.front().second;
            for ( int i = 0; i < int(lst.size()); i++ )
            {
               if ( lst[i].second < weight )
                  j = i;
            }
            BoneWeightList::iterator jit = lst.begin() + j;
            lst.erase( jit );
         }

         float totalWeight = 0;
         for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) {
            totalWeight += (*bw).second;
         }
         for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) {
            (*bw).second /= totalWeight;
         }
      }
      //qWarning() << "reduced" << c << "vertices to" << maxBonesPerVertex << "bone influences (maximum number of bones per vertex was" << maxBones << ")";
   }

   maxBones = maxBonesPerVertex;

   // reduces bone weights so that the triangles fit into the partitions

   typedef multimap<int,int> matchmap;
   typedef pair<matchmap::iterator, matchmap::iterator> matchrange;
   matchmap match;
   bool doMatch = true;

   BoneList tribones;
   int cnt = 0;
   for (Triangles::iterator itr = triangles.begin(); itr != triangles.end(); ++itr) {
      Triangle& tri = (*itr);
      do
      {
         tribones.clear();
         for ( int c = 0; c < 3; c++ ) {
            BoneWeightList& bwl = weights[tri[c]];
            for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) {
               if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) )
                  tribones.insert(tribones.end(), (*bw).first );
            }
         }

         if ( int(tribones.size()) > maxBonesPerPartition )
         {
            // sum up the weights for each bone
            // bones with weight == 1 can't be removed

            map<int, float> sum;
            vector<int> nono;

            for ( int t = 0; t < 3; t++ ) {
               BoneWeightList& bwl = weights[tri[t]];
               if ( bwl.size() == 1 )
                  nono.insert(nono.end(), bwl.front().first );

               for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) {
                  sum[ (*bw).first ] += (*bw).second;
               }                 
            }

            // select the bone to remove

            float minWeight = 5.0;
            int minBone = -1;

            for (map<int, float>::iterator sitr = sum.begin(); sitr != sum.end(); ++sitr) {
               int b = (*sitr).first;
               if ( (find(nono.begin(), nono.end(), b) == nono.end()) && sum[b] < minWeight) {
                  minWeight = sum[b];
                  minBone = b;
               }
            }

            if ( minBone < 0 )	// this shouldn't never happen
               throw runtime_error( "internal error 0x01" );

            // do a vertex match detect
            if ( doMatch ) {
               for ( size_t a = 0; a < verts.size(); a++ ) {
                  match.insert(matchmap::value_type(a, a));
                  for ( size_t b = a + 1; b < verts.size(); b++ ) {
                     if ( verts[a] == verts[b] && weights[a] == weights[b] ) {
                        match.insert(matchmap::value_type(a, b));
                        match.insert(matchmap::value_type(b, a));
                     }
                  }
               }
            }

            // now remove that bone from all vertices of this triangle and from all matching vertices too
            for ( int t = 0; t < 3; t++ ) {
               bool rem = false;

               matchrange range = match.equal_range(tri[t]);
               for (matchmap::iterator itr = range.first; itr != range.second; ++itr) {
                  int v = (*itr).second;

                  BoneWeightList & bws = weights[ v ];
                  BoneWeightList::iterator it = bws.begin();
                  while ( it != bws.end() ) {
                     BoneWeight & bw = *it;
                     if ( bw.first == minBone ) {
                        it = bws.erase(it);
                        rem = true;
                     } else {
                        ++it;
                     }
                  }

                  float totalWeight = 0;

                  for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
                     totalWeight += (*bw).second;
                  }

                  if ( totalWeight == 0 )
                     throw runtime_error( "internal error 0x02" );

                  // normalize
                  for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
                     (*bw).second /= totalWeight;
                  }
               }
               if ( rem )
                  cnt++;
            }
         }
      } while ( int(tribones.size()) > maxBonesPerPartition );
   }
   //if ( cnt > 0 )
   //   qWarning() << "removed" << cnt << "bone influences";

   PartitionList& parts = skinPartitionBlocks;
   // split the triangles into partitions
   while ( ! triangles.empty() ) {

      SkinPartition part;
      Triangles::iterator it = triangles.begin();
      while ( it != triangles.end() ) {
         Triangle & tri = *it;

         BoneList tribones;
         for ( int c = 0; c < 3; c++ ) {
            BoneWeightList& bws = weights[tri[c]];
            for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
               if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) )
                  tribones.push_back( (*bw).first );
            }
         }

         if ( part.bones.empty() || containsBones( part.bones, tribones ) ) {
            mergeBones( part.bones, tribones );
            part.triangles.push_back( tri );
            it = triangles.erase(it);
         } else {
            ++it;
         }
      }

      parts.push_back( part );
   }

   //qWarning() << parts.size() << "small partitions";

   // merge partitions

   bool merged;
   do
   {
      merged = false;
      // Working backwards through this list minimizes numbers of swaps
      //for ( int p2 = int(parts.size()-1); p2 >= 0  && ! merged; --p2 )
      //{
      //   Partition& part2 = parts[p2];
      //   for ( int p1 = int(p2-1); p1 >= 0 && ! merged; --p1 )
      //   {
      //      Partition& part1 = parts[p1];
      for ( int p1 = 0; p1 < int(parts.size()) && ! merged; p1++ )
      {
         Partition& part1 = parts[p1];
         for ( int p2 = p1+1; p2 < int(parts.size()) && ! merged; p2++ )
         {
            Partition& part2 = parts[p2];
            BoneList mergedBones = part1.bones;
            mergeBones( mergedBones, part2.bones );
            if ( int(mergedBones.size()) <= maxBonesPerPartition )
            {
               PartitionList::iterator p2i = parts.begin() + p2;
               part1.bones = mergedBones;
               part1.triangles.insert(part1.triangles.end(), (*p2i).triangles.begin(), (*p2i).triangles.end());
               parts.erase(p2i);
               merged = true;
            }
         }
      }
   }
   while ( merged );

   //qWarning() << parts.size() << "partitions";

   // start writing NiSkinPartition

   for ( int p = 0; p < int(parts.size()); p++ )
   {
      Partition& part = parts[p];
      BoneList& bones = part.bones;
      sort( bones.begin(), bones.end() );

      Triangles& triangles = part.triangles;

      vector<unsigned short>& vertices = part.vertexMap;
      for( Triangles::iterator tri = triangles.begin(); tri !=  triangles.end(); ++tri) {
         for ( int t = 0; t < 3; t++ ) {
            if ( vertices.end() == find(vertices.begin(), vertices.end(), (*tri)[t] ) )
               vertices.push_back( (*tri)[t] );
         }
      }
      sort( vertices.begin(), vertices.end() );
      part.numVertices = vertices.size();
      part.hasVertexMap = true;

      // map the vertices

      for ( int tri = 0; tri < int(triangles.size()); tri++ ) {
         for ( int t = 0; t < 3; t++ ) {
            triangles[tri][t] = indexOf(vertices.begin(), vertices.end(), triangles[tri][t]);
         }
      }

      SetWeightsPerVertex(p, maxBones);
      EnableVertexWeights(p, true);
      EnableVertexBoneIndices(p, true);

      // strippify the triangles
      NiTriStripsDataRef data = new NiTriStripsData(triangles, true);
      int nstrips = data->GetStripCount();
      SetStripCount( p, nstrips );
      for ( int i=0; i<nstrips; ++i ) {
         SetStrip(p, i, data->GetStrip(i));
      }

      //// Special case for pre-stripped data
      //unsigned short *data = new unsigned short[triangles.size() * 3 * 2];
      //for (size_t i=0; i< triangles.size(); i++) {
      //   data[i * 3 + 0] = triangles[i][0];
      //   data[i * 3 + 1] = triangles[i][1];
      //   data[i * 3 + 2] = triangles[i][2];
      //}
      //PrimitiveGroup * groups = 0;
      //unsigned short numGroups = 0;

      //// GF 3+
      //SetCacheSize(CACHESIZE_GEFORCE3);
      //// don't generate hundreds of strips
      //SetStitchStrips(true);
      //GenerateStrips(data, triangles.size()*3, &groups, &numGroups);
      //delete [] data;
      //if (groups) {
      //   SetStripCount(p, numGroups);
      //   for (int g=0; g<numGroups; g++) {
      //      if (groups[g].type == PT_STRIP) {
      //         vector<Niflib::unsigned short> strip(groups[g].numIndices);
      //         for (size_t s=0; s<groups[g].numIndices; s++)
      //            strip[s] = groups[g].indices[s];
      //         SetStrip(p, g, strip);
      //      }
      //   }
      //   delete [] groups;
      //}

      // fill in vertex weights and bones
      for (size_t v = 0; v < vertices.size(); ++v) {
         BoneWeightList& bwl = weights[vertices[v]];
         for ( int b = 0; b < maxBones; b++ ) {
            part.boneIndices[v][b] = (int(bwl.size()) > b) ? indexOf(bones.begin(), bones.end(), bwl[b].first) : 0 ;
            part.vertexWeights[v][b] = (int(bwl.size()) > b ? bwl[b].second : 0.0f);
         }
      }
   }
}
コード例 #7
0
NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) {
   NiSkinInstanceRef skinInst = shape->GetSkinInstance();
   if ( skinInst == NULL ) {
      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinInstance found." );
   }
   NiSkinDataRef skinData = skinInst->GetSkinData();
   if ( skinData == NULL ) {
      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinData found." );
   }
   NiTriBasedGeomDataRef geomData = DynamicCast<NiTriBasedGeomData>( shape->GetData() );
   if ( geomData == NULL ) {
      throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." );
   }

   int nWeightsPerVertex = 4;
   vector<WeightList> vertexWeights;
   BoneList boneMap;
   vector<unsigned short> vertexMap;
   Strips strips;
   vector<BoneList> boneIndexList;
   Triangles triangles;

   int totalBones = skinInst->GetBoneCount();
   boneMap.resize(totalBones);

   int nv = geomData->GetVertexCount();
   vertexMap.resize(nv);
   vertexWeights.resize(nv);
   boneIndexList.resize(nv);

   for (int i=0; i<totalBones; ++i) {
      boneMap[i] = i;

      vector<SkinWeight> skinWeights = skinData->GetBoneWeights(i);
      for (vector<SkinWeight>::const_iterator skinWeight = skinWeights.begin(); skinWeight != skinWeights.end(); ++skinWeight) {
         WeightList& vertexWeight = vertexWeights[skinWeight->index];
         BoneList& boneIndex = boneIndexList[skinWeight->index];

         vertexWeight.push_back(skinWeight->weight);
         boneIndex.push_back(i);

         // Adjust upper limit on number of weights per vertex if necessary.
         int nWeights = vertexWeight.size();
         if (nWeights > nWeightsPerVertex)
            nWeightsPerVertex = nWeights;
      }
   }
   if (nWeightsPerVertex == 0) {
      throw runtime_error( "Attempted to generate a skin partition on a mesh with no weights specified." );
   }
   for (int i=0; i<nv; ++i) {
      vertexMap[i] = i;

      WeightList& vertexWeight = vertexWeights[i];
      BoneList& boneIndex = boneIndexList[i];
      vertexWeight.reserve(nWeightsPerVertex);
      boneIndex.reserve(nWeightsPerVertex);
      for (int j = nWeightsPerVertex - vertexWeight.size(); j>0; --j) {
         vertexWeight.push_back(0.0f);
         boneIndex.push_back(0);
      }
   }

   SetNumPartitions(1);
   SetWeightsPerVertex(0, nWeightsPerVertex);
   SetBoneMap(0, boneMap);
   SetNumVertices(0, (unsigned short)(vertexMap.size()) );
   SetVertexMap(0, vertexMap);
   EnableVertexWeights(0, true);
   EnableVertexBoneIndices(0, true);
   for (int i=0; i<nv; ++i) {
      SetVertexWeights(0, i, vertexWeights[i]);
      SetVertexBoneIndices(0, i, boneIndexList[i]);
   }

   // Special case for pre-stripped data
   if (NiTriStripsDataRef stripData = DynamicCast<NiTriStripsData>(geomData)) {
      unsigned short nstrips = stripData->GetStripCount();
      SetStripCount(0, nstrips);
      for (int i=0; i<int(nstrips); ++i) {
         SetStrip(0, i, stripData->GetStrip(i));
      }
   } else {

      Triangles triangles = geomData->GetTriangles();
      SetTriangles(0, triangles);

      unsigned short *data = new unsigned short[triangles.size() * 3 * 2];
      for (size_t i=0; i< triangles.size(); i++) {
         data[i * 3 + 0] = triangles[i][0];
         data[i * 3 + 1] = triangles[i][1];
         data[i * 3 + 2] = triangles[i][2];
      }
      PrimitiveGroup * groups = 0;
      unsigned short numGroups = 0;

      // GF 3+
      SetCacheSize(CACHESIZE_GEFORCE3);
      // don't generate hundreds of strips
      SetStitchStrips(true);
      GenerateStrips(data, triangles.size()*3, &groups, &numGroups);

      delete [] data;

      if (groups) {
         SetStripCount(0, numGroups);
         for (int g=0; g<numGroups; g++) {
            if (groups[g].type == PT_STRIP) {
               vector<unsigned short> strip(groups[g].numIndices);
               for ( unsigned int s = 0; s<groups[g].numIndices; s++ )
                  strip[s] = groups[g].indices[s];
               SetStrip(0, g, strip);
            }
         }
         delete [] groups;
      }
   }
  
}