Example #1
0
Exporter::Result SkinInstance::execute()
{
   shape->BindSkinWith(boneList, SkinInstConstructor);
   unsigned int bone = 0;
   for (BoneWeightList::iterator bitr = boneWeights.begin(); bitr != boneWeights.end(); ++bitr, ++bone) {
      shape->SetBoneWeights(bone, (*bitr));
   }
   int* faceMap = NULL;
   if (partitions.size() > 0) {
      BSDismemberSkinInstanceRef dismem = DynamicCast<BSDismemberSkinInstance>(shape->GetSkinInstance());
      if (dismem != NULL)
         dismem->SetPartitions(partitions);
      faceMap = &facePartList[0];
   }
   if (Exporter::mNifVersionInt > VER_4_0_0_2)
   {
      if (Exporter::mMultiplePartitions)
         shape->GenHardwareSkinInfo(Exporter::mBonesPerPartition, Exporter::mBonesPerVertex, Exporter::mTriPartStrips, faceMap);
      else
         shape->GenHardwareSkinInfo(0, 0, Exporter::mTriPartStrips);
   }

   return Exporter::Ok;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t)
{
	ObjectState os = node->EvalWorldState(t);

	bool local = !mFlattenHierarchy;

	TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
	if (!tri)
		return Skip;

	Mesh *copymesh = NULL;
	Mesh *mesh = &tri->GetMesh();

	Matrix3 mtx(true), rtx(true);
	if (Exporter::mCollapseTransforms)
	{
		mtx = GetNodeLocalTM(node, t);
		mtx.NoTrans();
		Quat q(mtx);
		q.MakeMatrix(rtx);
		mesh = copymesh = new Mesh(*mesh);
		{
			int n = mesh->getNumVerts();
			for ( unsigned int i = 0; i < n; ++i ) {
				Point3& vert = mesh->getVert(i);
				vert = mtx * vert;
			}
			mesh->checkNormals(TRUE);
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+
			MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals ();
			if (NULL != specNorms) {
				specNorms->CheckNormals();
				for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) {
					Point3& norm = specNorms->Normal(i);
					norm = (rtx * norm).Normalize();
				}
			}
#endif
		}
	}
	// Note that calling setVCDisplayData will clear things like normals so we set this up first
	vector<Color4> vertColors;
	if (mVertexColors)
	{
		bool hasvc = false;
		if (mesh->mapSupport(MAP_ALPHA))
		{
			mesh->setVCDisplayData(MAP_ALPHA);         int n = mesh->getNumVertCol();
			if (n > vertColors.size())
				vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f));
			VertColor *vertCol = mesh->vertColArray;
			if (vertCol) {
				for (int i=0; i<n; ++i) {
					VertColor c = vertCol[ i ];
					float a = (c.x + c.y + c.z) / 3.0f;
					vertColors[i].a = a;
					hasvc |= (a != 1.0f);
				}
			}
		}
		if (mesh->mapSupport(0))
		{
			mesh->setVCDisplayData(0);
			VertColor *vertCol = mesh->vertColArray;
			int n = mesh->getNumVertCol();
			if (n > vertColors.size())
				vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f));
			if (vertCol) {
				for (int i=0; i<n; ++i) {
					VertColor col = vertCol[ i ];
					vertColors[i] = Color4(col.x, col.y, col.z, vertColors[i].a);
					hasvc |= (col.x != 1.0f || col.y != 1.0f || col.z != 1.0f);
				}
			}
		}
		if (!hasvc) vertColors.clear();
	}

#if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5
	mesh->checkNormals(TRUE);
#else
	MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals ();
	if (NULL != specNorms) {
		specNorms->CheckNormals();
		if (specNorms->GetNumNormals() == 0)
			mesh->checkNormals(TRUE);
	} else {
		mesh->checkNormals(TRUE);
	}
#endif

	Result result = Ok;

	Modifier* geomMorpherMod = GetMorpherModifier(node);
	bool noSplit = FALSE;
//	bool noSplit = (NULL != geomMorpherMod);

	while (1)
	{
		FaceGroups grps;
		if (!splitMesh(node, *mesh, grps, t, vertColors, noSplit))
		{
			result = Error;
			break;
		}
		bool exportStrips = mTriStrips && (Exporter::mNifVersionInt > VER_4_2_2_0);

		Matrix44 tm = Matrix44::IDENTITY;
		if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) {
			tm = TOMATRIX4(getObjectTransform(node, t, false) * Inverse(getNodeTransform(node, t, false)));
		} else {
			Matrix33 rot; Vector3 trans;
			objectTransform(rot, trans, node, t, local);
			tm = Matrix44(trans, rot, 1.0f);
		}
		tm = TOMATRIX4(Inverse(mtx)) * tm;

		TSTR basename = node->NodeName();
		TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s";

		int i=1;
		FaceGroups::iterator grp;
		for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i)
		{
			string name = FormatString(format, basename.data(), i);
			NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips);
			if (shape == NULL)
			{
				result = Error;
				break;
			}

			if (node->IsHidden())
				shape->SetVisibility(false);

			shape->SetName(name);
			shape->SetLocalTransform(tm);

			if (Exporter::mZeroTransforms) {
				shape->ApplyTransforms();
			}

			makeSkin(shape, node, grp->second, t);

			if (geomMorpherMod) {
				vector<Vector3> verts = shape->GetData()->GetVertices();
				exportGeomMorpherControl(geomMorpherMod, verts, shape->GetData()->GetVertexIndices(), shape);
				shape->GetData()->SetConsistencyFlags(CT_VOLATILE);
			}

		}

		break;
	}

	if (tri != os.obj)
		tri->DeleteMe();

	if (copymesh)
		delete copymesh;

	return result;
}
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;
}
bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom, int v_start/*=0*/)
{
   bool ok = true;
   NiSkinInstanceRef nifSkin = triGeom->GetSkinInstance();
   if (!nifSkin) 
      return false;

   INode *tnode = node->GetINode();

   NiSkinDataRef data = nifSkin->GetSkinData();
   NiSkinPartitionRef part = nifSkin->GetSkinPartition();

   vector<NiNodeRef> nifBones = nifSkin->GetBones();

   //create a skin modifier and add it
   Modifier *skinMod = GetOrCreateSkin(tnode);
   TriObject *triObject = GetTriObject(tnode->GetObjectRef());
   Mesh& m = triObject->GetMesh();

   //get the skin interface
   if (ISkin *skin = (ISkin *) skinMod->GetInterface(I_SKIN)){
      ISkinImportData* iskinImport = (ISkinImportData*) skinMod->GetInterface(I_SKINIMPORTDATA);

      // Set the num weights to 4.  Yes its in the nif but Shon doesn't like to expose those values 
      //   and the value always seems to be 4 anyway.  I'd also this be more dynamic than hard coded numbers
      //   but I cant figure out the correct values to pass the scripting engine from here so I'm giving up.
      int numWeightsPerVertex = 4;
#if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+
      IParamBlock2 *params = skinMod->GetParamBlockByID(2/*advanced*/);
      params->SetValue(0x7/*bone_Limit*/, 0, numWeightsPerVertex);
#endif

      // Can get some truly bizarre animations without this in MAX with Civ4 Leaderheads
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+
      BOOL ignore = TRUE;
      params->SetValue(0xE/*ignoreBoneScale*/, 0, ignore);
#endif

      //RefTargetHandle advanced = skinMod->GetReference(3);
      //setMAXScriptValue(advanced, "bone_Limit", 0, numWeightsPerVertex);

      Matrix3 geom = TOMATRIX3(triGeom->GetLocalTransform());
      Matrix3 m3 = TOMATRIX3(data->GetOverallTransform());
      Matrix3 im3 = Inverse(m3);
      Matrix3 nm3 = im3 * geom;
      iskinImport->SetSkinTm(tnode, nm3, nm3); // ???
      // Create Bone List
      Tab<INode*> bones;
      for (size_t i=0; i<nifBones.size(); ++i){
         NiNodeRef bone = nifBones[i];
         if (INode *boneRef = FindNode(bone)) {
            bones.Append(1, &boneRef);
            iskinImport->AddBoneEx(boneRef, TRUE);

            //// Set Bone Transform
            Matrix3 b3 = TOMATRIX3(data->GetBoneTransform(i));
            Matrix3 ib3 = Inverse(b3);
            ib3 *= geom;
            iskinImport->SetBoneTm(boneRef, ib3, ib3);
         }
      }
      if (bones.Count() != data->GetBoneCount())
         return false;

      ObjectState os = tnode->EvalWorldState(0);

      // Need to get a list of bones and weights for each vertex.
      vector<VertexHolder> vertexHolders;
      vertexHolders.resize(m.numVerts);
      for (int i=0, n=data->GetBoneCount();i<n; ++i){
         if (INode *boneRef = bones[i]){
            vector<SkinWeight> weights = data->GetBoneWeights(i);
            for (vector<SkinWeight>::iterator itr=weights.begin(), end=weights.end(); itr != end; ++itr){
               VertexHolder& h = vertexHolders[itr->index];
               h.vertIndex = itr->index;
               ++h.count;
               h.weights.Append(1, &itr->weight);
               h.boneNodeList.Append(1, &boneRef);
            }
         }
      }

      tnode->EvalWorldState(0);
      skinMod->DisableModInViews();
      skinMod->EnableModInViews();
#if VERSION_3DSMAX < ((5000<<16)+(15<<8)+0) // Version 4
      gi->SetCommandPanelTaskMode(TASK_MODE_MODIFY);
      gi->SelectNode(tnode);
#endif
      // Assign the weights 
      for (vector<VertexHolder>::iterator itr=vertexHolders.begin(), end=vertexHolders.end(); itr != end; ++itr){
         VertexHolder& h = (*itr);
         if (h.count){
            float sum = 0.0f;
			for (int i = 0; i < h.count; ++i)
				sum += h.weights[i];
            ASSERT(fabs(sum-1.0f) < 0.001f);
            BOOL add = iskinImport->AddWeights(tnode, h.vertIndex, h.boneNodeList, h.weights);
            add = add;		//	What was the purpose of this?
         }
      }
      //	This is a kludge to get skin transforms to update and avoid jumping around after modifying the transforms.
      //	Initially they show up incorrectly but magically fix up if you go to the modifier roll up.
      //	There is still an outstanding issue with skeleton and GetObjectTMBeforeWSM.
      skinMod->DisableModInViews();
      skinMod->EnableModInViews();


      // If BSDismembermentSkinInstance, ...
      if ( BSDismemberSkinInstanceRef bsdsi = DynamicCast<BSDismemberSkinInstance>(nifSkin) )
      {
         Modifier *dismemberSkinMod = GetOrCreateBSDismemberSkin(tnode);
         if (IBSDismemberSkinModifier *disSkin = (IBSDismemberSkinModifier *) dismemberSkinMod->GetInterface(I_BSDISMEMBERSKINMODIFIER)){
            //	Evaluate node ensure the modifier data is created
            //	ObjectState os = tnode->EvalWorldState(0);

            FaceMap faceMap;
            int nfaces = m.getNumFaces();
            for ( int i=0; i<nfaces; ++i ){
               Face f = m.faces[i];
               faceMap[ rotate(f) ] = i;
            }

            Tab<IBSDismemberSkinModifierData*> modData = disSkin->GetModifierData();
            for (int i=0; i<modData.Count(); ++i) {
               IBSDismemberSkinModifierData* bsdsmd = modData[i];

               Tab<BSDSPartitionData> &flags = bsdsmd->GetPartitionFlags();
               vector<BodyPartList> partitions = bsdsi->GetPartitions();
               if (partitions.empty())
                  continue;

               //bsdsmd->SetActivePartition( partitions.size() - 1 );				// Old Code

			   for (unsigned int j = 0; j < (partitions.size() - 1); ++j){
				   bsdsmd->AddPartition();
			   }

               for (unsigned int j=0; j < partitions.size(); ++j ) {
				   flags[j].bodyPart = (DismemberBodyPartType)partitions[j].bodyPart;
				   flags[j].partFlag = partitions[j].partFlag;
               }

               for (int j=0; j < part->GetNumPartitions(); ++j) {
                  bsdsmd->SetActivePartition( j );
                  dismemberSkinMod->SelectAll(3); // ensures bitarrays are properly synced to mesh
                  dismemberSkinMod->ClearSelection(3);
                  vector<Triangle> triangles = part->GetTriangles(j);
                  vector<unsigned short> map = part->GetVertexMap(j);
                  GenericNamedSelSetList& fselSet = bsdsmd->GetFaceSelList();
                  if ( BitArray* fsel = fselSet.GetSetByIndex(j) )
                  {
                     for (vector<Triangle>::iterator itrtri = triangles.begin(); itrtri != triangles.end(); ++itrtri) {
                        Face f;
						f.setVerts( map[(*itrtri).v1], map[(*itrtri).v2], map[(*itrtri).v3] );
                        FaceMap::iterator fitr = faceMap.find( rotate(f) );
                        if (fitr != faceMap.end())
                           fsel->Set((*fitr).second);
                     }
                  }
               }
               bsdsmd->SetActivePartition( 0 );
               disSkin->LocalDataChanged();
            }
         }
      }
   }
   return ok;
}
/*---------------------------------------------------------------------------*/
unsigned int NifCollisionUtility::getGeometryFromShapeData(vector<Vector3>& vertices, vector<Triangle>& triangles, NiTriBasedGeomRef pShape, vector<hkGeometry>& geometryMap, vector<Matrix44>& transformAry)
{
	hkGeometry						tmpGeo;
	hkArray<hkVector4>&				vertAry (tmpGeo.m_vertices);
	hkArray<hkGeometry::Triangle>&	triAry  (tmpGeo.m_triangles);
	Vector3							tVector;
	float							factor  (0.0143f);
	unsigned int					material(_defaultMaterial);

	//@TODO:  modify factor depending on _nifVersion if necessary

	//  add local transformation to list
	transformAry.push_back(pShape->GetLocalTransform());

	//  clear arrays
	vertAry.clear();
	triAry.clear();

	//  get vertices
	for (unsigned int idx(0); idx < vertices.size(); ++idx)
	{
		//  get vertex
		tVector = vertices[idx];

		//  transform vertex to global coordinates
		for (int t((int) (transformAry.size())-1); t >= 0; --t)
		{
			tVector = transformAry[t] * tVector;
		}

		//  scale final vertex
		tVector *= factor;

		//  add vertex to tmp. array
		vertAry.pushBack(hkVector4(tVector.x, tVector.y, tVector.z));

	}  //  for (unsigned int idx(0); idx < vertices.size(); ++idx)

	//  map material to geometry/triangles
	switch (_mtHandling)
	{
		case NCU_MT_SINGLE:				//  one material for all
		{
			material = _mtMapping[-1];
			break;
		}

		case NCU_MT_MATMAP:				//  material defined by node id
		{
			material = _mtMapping[pShape->internal_block_number];
			break;
		}

		case NCU_MT_NITRISHAPE_NAME:	//  material defined by node name
		{
			material = _materialList.getMaterialCode(pShape->GetName());
			break;
		}
	}

	//  get triangles
	for (unsigned int idx(0); idx < triangles.size(); ++idx)
	{
		hkGeometry::Triangle	tTri;

		tTri.set(triangles[idx].v1, triangles[idx].v2, triangles[idx].v3, material);
		triAry.pushBack(tTri);
	}

	//  add geometry to result array
	geometryMap.push_back(tmpGeo);

	//  remove local transformation from array
	transformAry.pop_back();

	return geometryMap.size();
}