//------------------------------
	bool SceneGraphCreator::recursivelyCloneINode( ImpNode* parentImportNode, INode* nodeToClone )
	{
		ImpNode* newImportNode = getMaxImportInterface()->CreateNode();
		getMaxImportInterface()->AddNodeToScene(newImportNode);

		INode* newNode = newImportNode->GetINode();

		Object* object = nodeToClone->GetObjectRef();
		newImportNode->Reference(object);
		newNode->SetTMController(nodeToClone->GetTMController());
		newImportNode->SetName(nodeToClone->GetName());
		//used to assign material
		addClonedINodeOriginalINodePair(newNode, nodeToClone);

		INode* parentNode = parentImportNode->GetINode();
		parentNode->AttachChild(newNode, TRUE);

		/* If the node to clone references an object, the cloned one must references the same object.*/
		COLLADAFW::UniqueId id = getUniqueIdByObjectINode(nodeToClone);
		if ( id.isValid() )
		{
			addUniqueIdObjectINodePair(id, newNode);
			addObjectINodeUniqueIdPair(newNode, id);
		}

		// Clone the children 
		for ( int i = 0, count = nodeToClone->NumberOfChildren(); i < count; ++i)
			recursivelyCloneINode(newImportNode, nodeToClone->GetChildNode(i));

		return true;
	}
	//------------------------------
	bool SceneGraphCreator::create()
	{
		if ( !mVisualScene )
			return false;

		INode* rootNode = getMaxInterface()->GetRootNode();

//why does this not work: setting rotation on root node
// 		Matrix3 maxTransformationMatrix;
// 		Matrix4ToMaxMatrix3(maxTransformationMatrix, mUpAxisRotation);
// 		rootNode->SetNodeTM(0, maxTransformationMatrix);
// 
// 		Matrix3 x = rootNode->GetNodeTM(0);

		if( COLLADABU::Math::Matrix4::IDENTITY != mUpAxisRotation )
		{
			ImpNode* upAxisCorrectionNode = getMaxImportInterface()->CreateNode();
			Matrix3 maxTransformationMatrix;
			Matrix4ToMaxMatrix3( maxTransformationMatrix, mUpAxisRotation );
			upAxisCorrectionNode->SetName(__T("upaxis"));
			upAxisCorrectionNode->SetTransform(0, maxTransformationMatrix);
			INode* iNode = upAxisCorrectionNode->GetINode();
			upAxisCorrectionNode->Reference( getDummyObject() );
			rootNode->AttachChild(iNode, FALSE);
			importNodes(mVisualScene->getRootNodes(), iNode);
		}
		else
			importNodes(mVisualScene->getRootNodes(), rootNode);

		return true;
	}
Пример #3
0
// PROCESSBIPNODERECURSE
// When we find a Biped-controlled node in our hierarchy, we need to find one non-biped
// child and promote it to the place of the biped node in the hierarchy. The siblings
// of the promoted node will become its children, as will the original children from the
// biped node.
void ProcessBipedNodeRecurse(INode *bipNode, INode *parent, Interface *theInterface)
{
    int numChildren = bipNode->NumberOfChildren();
    char *bipName = bipNode ? bipNode->GetName() : nil;
    INode *replacement = nil;

    for (int i = 0; i < numChildren; i++)
    {
        INode *child = bipNode->GetChildNode(i);
        char *childName = child ? child->GetName() : nil;

        if( ! HasBipController(child) )
        {
            replacement = child;                    // this child is going to be our replacement for this bipnode

            // sample the animation (into global space)
            plSampleVec *samples = SampleNodeMotion(replacement, bipNode, 1, theInterface);

            // detach from the parent (this blows away the animation)
            replacement->Detach(0);

            // attach the node to the biped's parent.
            parent->AttachChild(replacement);   

            ReapplyAnimation(child, samples);
            FreeMotionSamples(samples);

            // we only need one replacement for the bip node
            break;
        }
    }
    
    if(replacement)
    {
        // reparent the siblings to the newly promoted replacement node
        numChildren = bipNode->NumberOfChildren();
        for (int i = 0; i < numChildren; i++)
        {
            INode *child = bipNode->GetChildNode(i);

            if( HasBipController(child) )
            {
                ProcessBipedNodeRecurse(child, replacement, theInterface);
            } else {
                child->Detach(0);                   // remove the (non-bip) child from the bip node
                replacement->AttachChild(child);    // attach it to the non-bip parent

                ProcessNonBipedNodeRecurse(child, replacement, theInterface);
            }
        }
    } else {
        // this is an error condition: we've got a bip node that has no non-bip child for us to promote
        char buf[256];
        sprintf(buf, "Couldn't find non-bip node to transfer motion to for bip node %s\n", bipNode->GetName());
        hsStatusMessage(buf);
    }
}
		bool SceneGraphCreator::importInstances( const COLLADAFW::PointerArray<Instance>& instanceArray, ImpNode* parentImportNode )
	{
		for ( size_t i = 0, count = instanceArray.getCount(); i < count; ++i)
		{
			Instance* instance = instanceArray[i];

			ImpNode* newImportNode = getMaxImportInterface()->CreateNode();
			INode* newNode = newImportNode->GetINode();
			const COLLADAFW::UniqueId& uniqueId = instance->getInstanciatedObjectId();

			Object* object = getObjectByUniqueId(uniqueId);
			if ( object )
			{
				newImportNode->Reference(object);
			}
			else
			{
				newImportNode->Reference( getDummyObject() );
			}
			const COLLADAFW::UniqueId& instanceUniqueId = instance->getInstanciatedObjectId();
			// Store mapping between unique ids and nodes referencing the corresponding object.
			// Used to clone nodes
			addObjectINodeUniqueIdPair(newNode, instanceUniqueId);
			// Used to resolve instancing of objects
			addUniqueIdObjectINodePair(instanceUniqueId, newNode);

			INode* parentNode = parentImportNode->GetINode();
			parentNode->AttachChild(newNode, FALSE);

			// post process the creation
			if ( postProcess )
				(this->*postProcess)(newNode, instance);
		}

		return true;
	}
Пример #5
0
void WMOGroupImpl::buildMaxData()
{
	// Group Header Node
	INode* groupHeadNode = createGroupHeaderNode();
	groupHeadNode->SetGroupHead(TRUE);
	groupHeadNode->SetGroupMember(FALSE);

	// Geoset
	// 一个Render Batch构造一个Node, 并且加入到组中

	for (int i = 0; i < m_batchCount; ++i)
	{
		WMORenderBatch& renderBatch = m_batchData[i];

		m_wmoImporter->m_logStream << "Model Geoset " << i << " Vertex Info: " 
			<< renderBatch.vertexStart << " -- " << renderBatch.vertexEnd << endl;
		m_wmoImporter->m_logStream << "Model Geoset " << i << " Index Info: " 
			<< renderBatch.indexStart << " -- " << renderBatch.indexCount << endl;

		// Triangle Mesh Object
		// 基本的三角形模型对象
		TriObject* triObject = CreateNewTriObject();

		// 创建Node, 并且设为Group Header Node的子节点
		ImpNode* tmpImpNode = m_wmoImporter->m_impInterface->CreateNode();
		tmpImpNode->Reference(triObject);

		m_wmoImporter->m_impInterface->AddNodeToScene(tmpImpNode);
		INode* realINode = tmpImpNode->GetINode();
		realINode->SetGroupHead(FALSE);
		realINode->SetGroupMember(TRUE);
		groupHeadNode->AttachChild(realINode);

		m_geosetNodeList.push_back(realINode);

		TCHAR nodeName[256];
		sprintf(nodeName, "%s_part_%03d", m_groupName.c_str(), i);
		realINode->SetName(nodeName);

		// mesh
		unsigned short vertexCount = renderBatch.vertexEnd - renderBatch.vertexStart + 1;
		unsigned int trigangleCount = renderBatch.indexCount / 3;

		Mesh& mesh = triObject->GetMesh();
		mesh.setNumVerts(vertexCount);
		mesh.setNumTVerts(vertexCount, TRUE);

		mesh.setNumFaces(trigangleCount);
		mesh.setNumTVFaces(trigangleCount);

		// 顶点坐标和UV
		for (int i = 0; i < vertexCount; ++i)
		{
			mesh.verts[i] = *(Point3*)(&(m_vertexData[renderBatch.vertexStart + i]));

			// UV坐标反转
			mesh.tVerts[i].x = m_textureCoords[renderBatch.vertexStart + i].x;
			mesh.tVerts[i].y = 1.0f - m_textureCoords[renderBatch.vertexStart + i].y;
		}

		// 三角形
		for (unsigned int i = 0; i < trigangleCount; ++i)
		{
			Face& face = mesh.faces[i];
			int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart;
			int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart;
			int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart;

			face.setVerts(index1, index2, index3);
			face.Show();
			face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS);

			TVFace& tface = mesh.tvFace[i];
			tface.setTVerts(index1, index2, index3);
		}

		// 法线
		mesh.SpecifyNormals();
		MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
		if (specNorms)
		{
			specNorms->ClearAndFree();
			specNorms->SetNumFaces(trigangleCount);
			specNorms->SetNumNormals(vertexCount);

			Point3* norms = specNorms->GetNormalArray();
			for (int i = 0; i < vertexCount; ++i)
			{
				norms[i] = *(Point3*)(&m_normalData[renderBatch.vertexStart + i]);
			}

			MeshNormalFace* pFaces = specNorms->GetFaceArray();
			for (unsigned int i = 0; i < trigangleCount; ++i)
			{
				int index1 = m_indexData[renderBatch.indexStart + i*3] - renderBatch.vertexStart;
				int index2 = m_indexData[renderBatch.indexStart + i*3+1] - renderBatch.vertexStart;
				int index3 = m_indexData[renderBatch.indexStart + i*3+2] - renderBatch.vertexStart;

				pFaces[i].SpecifyNormalID(0, index1);
				pFaces[i].SpecifyNormalID(1, index2);
				pFaces[i].SpecifyNormalID(2, index3);
			}

			specNorms->SetAllExplicit(true);
			specNorms->CheckNormals();
		}

		// 删除重复的和无效的面
		mesh.RemoveDegenerateFaces();
		mesh.RemoveIllegalFaces();

		realINode->SetMtl(m_wmoImporter->m_materialList[renderBatch.texture]);
		//realINode->BackCull(FALSE);			// 取消背面裁减 不是所有的Node都要取消背面裁减
		realINode->EvalWorldState(0);
	}
}
int importAlembicScene(AbcArchiveCache *pArchiveCache,
                       AbcObjectCache *pRootObjectCache,
                       alembic_importoptions &options, std::string &file,
                       progressUpdate &progress,
                       std::map<std::string, bool> &nodeFullPaths)
{
  std::vector<stackElement> sceneStack;
  sceneStack.reserve(200);
  for (size_t j = 0; j < pRootObjectCache->childIdentifiers.size(); j++) {
    sceneStack.push_back(stackElement(
        &(pArchiveCache->find(pRootObjectCache->childIdentifiers[j])->second)));
  }

  while (!sceneStack.empty()) {
    stackElement sElement = sceneStack.back();
    sceneStack.pop_back();
    Abc::IObject &iObj = sElement.pObjectCache->obj;
    INode *pParentMaxNode = sElement.pParentMaxNode;

    if (!iObj.valid()) {
      return alembic_failure;
    }

    const std::string fullname = iObj.getFullName();
    const std::string pname = (pParentMaxNode)
                                  ? EC_MCHAR_to_UTF8(pParentMaxNode->GetName())
                                  : std::string("");
    const std::string name = iObj.getName();

    ESS_LOG_INFO("Importing " << fullname);

    bool bCreateDummyNode = false;
    int mergedGeomNodeIndex = -1;
    AbcObjectCache *pMergedObjectCache = NULL;
    getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateDummyNode,
                 mergedGeomNodeIndex, &pMergedObjectCache);

    INode *pMaxNode =
        NULL;  // the newly create node, which may be a merged node
    INode *pExistingNode = NULL;
    int keepTM = 1;  // I don't remember why this needed to be set in some
    // cases.

    bool bCreateNode = true;

    if (!nodeFullPaths.empty()) {
      if (mergedGeomNodeIndex != -1) {
        AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
        bCreateNode = nodeFullPaths.find(mergedGeomChild.getFullName()) !=
                      nodeFullPaths.end();
      }
      else {
        bCreateNode = nodeFullPaths.find(fullname) != nodeFullPaths.end();
      }
    }

    if (bCreateNode) {
      // if we are about to merge a camera with its parent transform, force it
      // to create a dummy node instead if the camera's
      // transform also has children. This is done to prevent the camera
      // correction matrix from being applied to the other children
      if (!bCreateDummyNode && pMergedObjectCache &&
          sElement.pObjectCache->childIdentifiers.size() > 1 &&
          AbcG::ICamera::matches(pMergedObjectCache->obj.getMetaData())) {
        bCreateDummyNode = true;
        mergedGeomNodeIndex = -1;
      }

      if (bCreateDummyNode) {
        std::string importName = removeXfoSuffix(iObj.getName());

        pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
        if (options.attachToExisting && pExistingNode) {
          pMaxNode = pExistingNode;

          // see if a controller already exists, and then delete it

          int ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL,
                                        file, options);
          if (ret != 0) {
            return ret;
          }
        }  // only create node if either attachToExisting is false or it is true
        // and the object does not already exist
        else {
          int ret =
              AlembicImport_DummyNode(iObj, options, &pMaxNode, importName);
          if (ret != 0) {
            return ret;
          }

          ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file,
                                    options);
          if (ret != 0) {
            return ret;
          }
        }
      }
      else {
        if (mergedGeomNodeIndex !=
            -1) {  // we are merging, so look at the child geometry node
          AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
          std::string importName =
              removeXfoSuffix(iObj.getName());  // mergedGeomChild.getName());
          pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
          if (options.attachToExisting && pExistingNode) {
            pMaxNode = pExistingNode;
          }  // only create node if either attachToExisting is false or it is
          // true and the object does not already exist

          int ret =
              createAlembicObject(mergedGeomChild, &pMaxNode, options, file);
          if (ret != 0) {
            return ret;
          }
          if (pMaxNode != NULL) {
            ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj,
                                      &mergedGeomChild, file, options);
            if (ret != 0) {
              return ret;
            }
          }
        }
        else {  // geometry node(s) under a dummy node (in pParentMaxNode)
          pExistingNode = GetChildNodeFromName(iObj.getName(), pParentMaxNode);
          if (options.attachToExisting && pExistingNode) {
            pMaxNode = pExistingNode;
          }  // only create node if either attachToExisting is false or it is
          // true and the object does not already exist

          int ret = createAlembicObject(iObj, &pMaxNode, options, file);
          if (ret != 0) {
            return ret;
          }

          // since the transform is the identity, should position relative to
          // parent
          keepTM = 0;

          if (AbcG::ICamera::matches(iObj.getMetaData())) {
            // apply camera adjustment matrix to the identity
            Matrix3 rotation(TRUE);
            rotation.RotateX(HALFPI);
            TimeValue zero(0);
            pMaxNode->SetNodeTM(zero, rotation);
          }

          // import identity matrix, since more than goemetry node share the
          // same transform
          // Should we just list MAX put a default position/scale/rotation
          // controller on?

          //	int ret = AlembicImport_XForm(pMaxNode, *piParentObj, file,
          // options);
        }

        if (options.failOnUnsupported) {
          if (!pMaxNode) {
            return alembic_failure;
          }
        }
      }
    }

    if (pMaxNode && pParentMaxNode && !pExistingNode) {
      pParentMaxNode->AttachChild(pMaxNode, keepTM);
    }

    progress.increment();
    progress.update();

    if (pMaxNode) {
      for (size_t j = 0; j < sElement.pObjectCache->childIdentifiers.size();
           j++) {
        AbcObjectCache *pChildObjectCache =
            &(pArchiveCache->find(sElement.pObjectCache->childIdentifiers[j])
                  ->second);
        if (NodeCategory::get(pChildObjectCache->obj) ==
            NodeCategory::UNSUPPORTED) {
          continue;  // skip over unsupported types
        }

        // I assume that geometry nodes are always leaf nodes. Thus, if we
        // merged a geometry node will its parent transform, we don't
        // need to push it to the stack.
        // A geometry node can't be combined with its transform node, the
        // transform node has other tranform nodes as children. These
        // nodes must be pushed.
        if (mergedGeomNodeIndex != j) {
          sceneStack.push_back(stackElement(pChildObjectCache, pMaxNode));
        }
      }
    }
  }

  return alembic_success;
}
Пример #7
0
void NifImporter::ImportBones(NiNodeRef node, bool recurse)
{
   try 
   {
      if (uncontrolledDummies)
         BuildControllerRefList(node, ctrlCount);

      string name = node->GetName();

      vector<NiAVObjectRef> children = node->GetChildren();
      vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children);

      NiAVObject::CollisionType cType = node->GetCollisionMode();
      if (children.empty() && name == "Bounding Box")
         return;

      // Do all node manipulations here
      NiNodeRef parent = node->GetParent();
      string parentname = (parent ? parent->GetName() : "");
      Matrix44 m4 = node->GetWorldTransform();

      // Check for Prn strings and change parent if necessary
      if (supportPrnStrings) {
         list<NiStringExtraDataRef> strings = DynamicCast<NiStringExtraData>(node->GetExtraData());
         for (list<NiStringExtraDataRef>::iterator itr = strings.begin(); itr != strings.end(); ++itr){
            if (strmatch((*itr)->GetName(), "Prn")) {
               parentname = (*itr)->GetData();
               if (INode *pn = gi->GetINodeByName(parentname.c_str())){
                  // Apparently Heads tend to need to be rotated 90 degrees on import for 
                  if (!rotate90Degrees.empty() && wildmatch(rotate90Degrees, parentname)) {
                     m4 *= TOMATRIX4(RotateYMatrix(TORAD(90)));
                  }
                  m4 *= TOMATRIX4(pn->GetObjTMAfterWSM(0, NULL));
               }
            }
         }
      }

      float len = node->GetLocalTranslation().Magnitude();

      // Remove NonAccum nodes and merge into primary bone
      if (mergeNonAccum && wildmatch("* NonAccum", name) && parent)
      {
         string realname = name.substr(0, name.length() - 9);
         if (strmatch(realname, parent->GetName()))
         {
            Matrix44 tm = parent->GetLocalTransform() * node->GetLocalTransform();
            name = realname;
            len += tm.GetTranslation().Magnitude();
			parent = parent->GetParent();
         }
      }

      PosRotScale prs = prsDefault;
      Vector3 pos; Matrix33 rot; float scale;
      m4.Decompose(pos, rot, scale);

      Matrix3 im = TOMATRIX3(m4);
      Point3 p = im.GetTrans();
      Quat q(im);
      //q.Normalize();
      Vector3 ppos;
      Point3 zAxis(0,0,0);
      bool hasChildren = !children.empty();
      if (hasChildren) {
         float len = 0.0f;
         for (vector<NiAVObjectRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) {
            len += GetObjectLength(*itr);
         }
         len /= float(children.size());
         ppos = pos + Vector3(len, 0.0f, 0.0f); // just really need magnitude as rotation will take care of positioning
      }
      else if (parent)
      {
         ppos = pos + Vector3(len/3.0f, 0.0f, 0.0f);
      }
      Point3 pp(ppos.x, ppos.y, ppos.z);

      Point3 qp = TORAD(TOEULER(im));


      INode *bone = NULL;
	  if (!doNotReuseExistingBones) // Games like BC3 reuse the same bone names
	  {
		  bone = FindNode(node);
		  if (bone == NULL) 
			  bone = gi->GetINodeByName(name.c_str());
	  }
      if (bone)
      {
         // Is there a better way of "Affect Pivot Only" behaviors?
         INode *pinode = bone->GetParentNode();
         if (pinode)
            bone->Detach(0,1);
         PosRotScaleNode(bone, p, q, scale, prs);
         if (pinode)
            pinode->AttachChild(bone, 1);
      }
      else
      {
         bool isDummy = ( (uncontrolledDummies && !HasControllerRef(ctrlCount, name))
                     || (!dummyNodeMatches.empty() && wildmatch(dummyNodeMatches, name))
                     || (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TYPE))
                      );
         if (wildmatch("Camera*", name)) {
            if (enableCameras) {
               if (bone = CreateCamera(name)) {
                  PosRotScaleNode(bone, p, q, scale, prs);
                  bone->Hide(node->GetVisibility() ? FALSE : TRUE);
               }
            }
         }else if (isDummy && createNubsForBones)
            bone = CreateHelper(name, p);
         else if (bone = CreateBone(name, p, pp, zAxis))
         {
            PosRotScaleNode(bone, p, q, scale, prs);
            bone->Hide(node->GetVisibility() ? FALSE : TRUE);
         }
         if (bone)
         {
            if (!parentname.empty())
            {
               if (mergeNonAccum && wildmatch("* NonAccum", parentname)) {
                  parentname = parentname.substr(0, parentname.length() - 9);
               }
               if (INode *pn = gi->GetINodeByName(parentname.c_str()))
                  pn->AttachChild(bone, 1);
            }
			RegisterNode(node, bone);
         }
      }
      // Import UPB
      if (bone) ImportUPB(bone, node);

      // Import Havok Collision Data surrounding node,  
	  //   unfortunately this causes double import of collision so I'm disabling it for now.
	  if (enableCollision && node->GetParent()) {
		ImportCollision(node);
	  }

      if (bone && recurse)
      {
         ImportBones(childNodes);
      }
   }
   catch( exception & e ) 
   {
      e=e;
   }
   catch( ... ) 
   {
   }
}
Пример #8
0
// 1. 加载模型顶点数据
void M2Importer::importGeomObject()
{
	// Group Header Node
	INode* groupHeadNode = createGroupHeaderNode();
	groupHeadNode->SetGroupHead(TRUE);
	groupHeadNode->SetGroupMember(FALSE);

	if (m_modelHeader->nameLength > 1)
	{
		TCHAR* modelName = (TCHAR*)(m_m2FileData + m_modelHeader->nameOfs);
		groupHeadNode->SetName(modelName);
		m_logStream << "ModelName: " << modelName << endl;
	}
	else
		groupHeadNode->SetName("GeomGroup");


	// Geoset
	// 一个Geoset构造一个Node, 并且加入到组中

	unsigned short* verDataIndex = (unsigned short*)(m_m2FileData + m_modelView->ofsIndex);
	unsigned short* triData = (unsigned short*)(m_m2FileData + m_modelView->ofsTris);

	m_geosetNodeList.reserve(m_modelView->nSub);
	m_materialList.reserve(m_modelView->nSub);
	for (unsigned int i = 0; i < m_modelView->nSub; ++i)
		m_materialList.push_back(0);

	for (unsigned int i = 0; i < m_modelView->nSub; ++i)
	{
		ModelGeoset& geosetData = m_modelGeoset[i];

		// Triangle Mesh Object
		// 基本的三角形模型对象
		TriObject* triObject = CreateNewTriObject();

		// 创建Node, 并且设为Group Header Node的子节点
		ImpNode* tmpImpNode = m_impInterface->CreateNode();
		tmpImpNode->Reference(triObject);
		//tmpImpNode->SetPivot(*(Point3*)&(geosetData.v));

		m_impInterface->AddNodeToScene(tmpImpNode);
		INode* realINode = tmpImpNode->GetINode();
		realINode->SetGroupHead(FALSE);
		realINode->SetGroupMember(TRUE);
		groupHeadNode->AttachChild(realINode);

		m_geosetNodeList.push_back(realINode);

		TCHAR nodeName[256];
		sprintf(nodeName, "GeosetPart_%d", i);
		realINode->SetName(nodeName);

		// mesh
		Mesh& mesh = triObject->GetMesh();
		mesh.setNumVerts(geosetData.vcount);
		mesh.setNumTVerts(geosetData.vcount, TRUE);

		unsigned int triangeCount = geosetData.icount / 3;
		mesh.setNumFaces(triangeCount);
		mesh.setNumTVFaces(triangeCount);

		m_logStream << "Model Geoset " << i << " Vertex Count: " << geosetData.vcount << endl;
		m_logStream << "Model Geoset " << i << " Index Count: " << triangeCount << endl;

		// 顶点坐标和UV
		for (unsigned int i = 0; i < geosetData.vcount; ++i)
		{
			ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ];

			mesh.verts[i] = *(Point3*)(&vertexData.pos);

			// UV坐标反转
			mesh.tVerts[i].x = vertexData.texcoords.x;
			mesh.tVerts[i].y = 1.0f - vertexData.texcoords.y;
		}

		// 三角形
		for (unsigned int i = 0; i < triangeCount; ++i)
		{
			Face& face = mesh.faces[i];
			face.setVerts(triData[geosetData.istart + i*3] - m_indexCount, 
						  triData[geosetData.istart + i*3+1] - m_indexCount, 
						  triData[geosetData.istart + i*3+2] - m_indexCount);
			face.Show();
			face.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS);

			TVFace& tface = mesh.tvFace[i];
			tface.setTVerts(triData[geosetData.istart + i*3] - m_indexCount, 
							triData[geosetData.istart + i*3+1] - m_indexCount, 
							triData[geosetData.istart + i*3+2] - m_indexCount);
		}

		// 法线
		mesh.SpecifyNormals();
		MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
		if (specNorms)
		{
			specNorms->ClearAndFree();
			specNorms->SetNumFaces(triangeCount);
			specNorms->SetNumNormals(geosetData.vcount);

			Point3* norms = specNorms->GetNormalArray();
			for (unsigned int i = 0; i < geosetData.vcount; ++i)
			{
				ModelVertex& vertexData = m_globalVertices[ verDataIndex[geosetData.vstart + i] ];
				norms[i] = *(Point3*)(&vertexData.normal);
			}

			MeshNormalFace* pFaces = specNorms->GetFaceArray();
			for (unsigned int i = 0; i < triangeCount; ++i)
			{
				pFaces[i].SpecifyNormalID(0, triData[geosetData.istart + i*3] - m_indexCount);
				pFaces[i].SpecifyNormalID(1, triData[geosetData.istart + i*3+1] - m_indexCount);
				pFaces[i].SpecifyNormalID(2, triData[geosetData.istart + i*3+2] - m_indexCount);
			}

			specNorms->SetAllExplicit(true);
			specNorms->CheckNormals();
		}

		// 删除重复的和无效的面
		mesh.RemoveDegenerateFaces();
		mesh.RemoveIllegalFaces();

		//realINode->BackCull(FALSE);			// 取消背面裁减 双面绘制与取消背面裁减一起设置
		realINode->EvalWorldState(0);

		// 索引值修正
		m_indexCount += geosetData.vcount;
	}

	// 加载材质
	unsigned short* texLookupData = (unsigned short*)(m_m2FileData + m_modelHeader->ofsTexLookup);
	ModelTextureDef* texUnitDefData = (ModelTextureDef*)(m_m2FileData + m_modelHeader->ofsTextures);
	ModelTexUnit* texUnitData = (ModelTexUnit*)(m_m2FileData + m_modelView->ofsTex);

	for (unsigned int i = 0; i < m_modelView->nTex; ++i)
	{
		ModelTexUnit& texUnit = texUnitData[i];
		unsigned short textureID = texLookupData[texUnit.textureid];
		ModelTextureDef& texDef = texUnitDefData[textureID];

		string textureName;

		if (texDef.type == 0)
			textureName = (LPCSTR)(m_m2FileData + texDef.nameOfs);
		else
			textureName = getReplacableTexture(texDef.type);

		StdMat2* material = m_materialList[texUnit.op];
		if (!material)
			material = createMaterial();

		// 根据混合属性决定加在第几层
		material->SetSubTexmap(ID_DI, createTexture(textureName.c_str()));
		material->EnableMap(ID_DI, TRUE);
		//material->SetTwoSided(TRUE);		// 双面 设置了此标志的才打开

		m_maxInterface->GetMaterialLibrary().Add(material);
		m_geosetNodeList[texUnit.op]->SetMtl(material);
	}

	m_maxInterface->RedrawViews(m_maxInterface->GetTime());
}
Пример #9
0
// 2. 加载骨骼数据
void M2Importer::importBoneObject()
{
	// Bone Group Header Node
	INode* groupHeadNode = createGroupHeaderNode();
	groupHeadNode->SetGroupHead(TRUE);
	groupHeadNode->SetGroupMember(FALSE);

	if (m_modelHeader->nameLength > 1)
	{
		TCHAR* modelName = (TCHAR*)(m_m2FileData + m_modelHeader->nameOfs);
		TCHAR boneGroupName[256];
		sprintf(boneGroupName, "%s_bone", modelName);
		groupHeadNode->SetName(boneGroupName);
	}
	else
		groupHeadNode->SetName("BoneGroup");


	// Bone
	// 一个Bone构造一个Node, 并且加入到组中

	ModelBoneDef* boneData = (ModelBoneDef*)(m_m2FileData + m_modelHeader->ofsBones);

	m_boneNodeList.reserve(m_modelHeader->nBones);
	for (unsigned int i = 0; i < m_modelHeader->nBones; ++i)
	{
		ModelBoneDef& boneDef = boneData[i];

		// create bone node
		HelperObject* obj = (HelperObject*)CreateInstance(HELPER_CLASS_ID, Class_ID(BONE_CLASS_ID, 0));

		ImpNode* node = m_impInterface->CreateNode();

		TCHAR boneName[256];
		sprintf(boneName, "bone_%02d", i);
		node->SetName(boneName);

		node->SetPivot(*(Point3*)&(boneDef.pivot));
		node->Reference(obj);

		m_impInterface->AddNodeToScene(node);

		// 设置变换矩阵
		Matrix3 tm;
		tm.IdentityMatrix();
		tm.SetTrans(*(Point3*)&(boneDef.pivot));
		node->SetTransform(0, tm);

		// 添加到组
		INode* realINode = node->GetINode();
		realINode->SetGroupHead(FALSE);
		realINode->SetGroupMember(TRUE);
		groupHeadNode->AttachChild(realINode);

		// 设置Bone父子关系
		realINode->ShowBone(2);
		m_boneNodeList.push_back(realINode);
		if (boneDef.parent != -1)
		{
			INode* parentNode = m_boneNodeList[boneDef.parent];
			parentNode->AttachChild(realINode);
		}

		realINode->EvalWorldState(0);
	}

	// 导入每根骨骼的关键桢数据
	for (unsigned int i = 0; i < m_modelHeader->nBones; ++i)
	{
		ModelBoneDef& boneDef = boneData[i];
		INode* realINode = m_boneNodeList[i];

		Control* tmControl = realINode->GetTMController();

		// Position
		if (boneDef.translation.nKeys)
		{
			// 设置动画控制器为线性控制器
			Control* posControl = createPositionController();
			tmControl->SetPositionController(posControl);

			unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.translation.ofsTimes);
			Point3* keyData = (Point3*)(m_m2FileData + boneDef.translation.ofsKeys);

			// 设置动画时间范围
			bool animRangeChanged = false;
			Interval animRange = m_maxInterface->GetAnimRange();
			for (unsigned int j = 0; j < boneDef.translation.nKeys; ++j)
			{
				if (timeData[j] < animRange.Start())
				{
					animRange.SetStart(timeData[j]);
					animRangeChanged = true;
				}
				else if (timeData[j] > animRange.End())
				{
					animRange.SetEnd(timeData[j]);
					animRangeChanged = true;
				}
			}
			if (animRangeChanged)
				m_maxInterface->SetAnimRange(animRange);

			// 设置动画关键桢数据
			Control* xControl = posControl->GetXController();
			IKeyControl* xKeyControl = GetKeyControlInterface(xControl);
			xKeyControl->SetNumKeys(boneDef.translation.nKeys);

			Control* yControl = posControl->GetYController();
			IKeyControl* yKeyControl = GetKeyControlInterface(yControl);
			yKeyControl->SetNumKeys(boneDef.translation.nKeys);

			Control* zControl = posControl->GetZController();
			IKeyControl* zKeyControl = GetKeyControlInterface(zControl);
			zKeyControl->SetNumKeys(boneDef.translation.nKeys);

			for (unsigned int j = 0; j < boneDef.translation.nKeys; ++j)
			{
				// X
				AnyKey bufX;
				ILinFloatKey* keyX = reinterpret_cast<ILinFloatKey*>((IKey*)bufX);
				keyX->time = timeData[j];
				keyX->val = keyData[j].x;
				xKeyControl->AppendKey(keyX);

				// Y
				AnyKey bufY;
				ILinFloatKey* keyY = reinterpret_cast<ILinFloatKey*>((IKey*)bufY);
				keyY->time = timeData[j];
				keyY->val = keyData[j].y;
				yKeyControl->AppendKey(keyY);

				// Z
				AnyKey bufZ;
				ILinFloatKey* keyZ = reinterpret_cast<ILinFloatKey*>((IKey*)bufZ);
				keyZ->time = timeData[j];
				keyZ->val = keyData[j].z;
				zKeyControl->AppendKey(keyZ);
			}
		}
/*
		// Rotation
		if (boneDef.rotation.nKeys)
		{
			Control* rotControl = createRotationController();
			tmControl->SetRotationController(rotControl);

			unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.rotation.ofsTimes);
			Quat* keyData = (Quat*)(m_m2FileData + boneDef.rotation.ofsKeys);

			// 设置动画时间范围
			bool animRangeChanged = false;
			Interval animRange = m_maxInterface->GetAnimRange();
			for (unsigned int j = 0; j < boneDef.rotation.nKeys; ++j)
			{
				if (timeData[j] < animRange.Start())
				{
					animRange.SetStart(timeData[j]);
					animRangeChanged = true;
				}
				else if (timeData[j] > animRange.End())
				{
					animRange.SetEnd(timeData[j]);
					animRangeChanged = true;
				}
			}
			if (animRangeChanged)
				m_maxInterface->SetAnimRange(animRange);

			// 设置动画关键桢数据
			IKeyControl* keyControl = GetKeyControlInterface(rotControl);
			keyControl->SetNumKeys(boneDef.rotation.nKeys);

			for (unsigned int j = 0; j < boneDef.rotation.nKeys; ++j)
			{
				AnyKey buf;
				ILinRotKey* key = reinterpret_cast<ILinRotKey*>((IKey*)buf);
				key->time = timeData[j];
				key->val = keyData[j];
				keyControl->AppendKey(key);
			}
		}
*/
		// Scaling
		if (boneDef.scaling.nKeys)
		{
			Control* scaControl = createScaleController();
			tmControl->SetScaleController(scaControl);

			unsigned int* timeData = (unsigned int*)(m_m2FileData + boneDef.scaling.ofsTimes);
			Point3* keyData = (Point3*)(m_m2FileData + boneDef.scaling.ofsKeys);

			// 设置动画时间范围
			bool animRangeChanged = false;
			Interval animRange = m_maxInterface->GetAnimRange();
			for (unsigned int j = 0; j < boneDef.scaling.nKeys; ++j)
			{
				if (timeData[j] < animRange.Start())
				{
					animRange.SetStart(timeData[j]);
					animRangeChanged = true;
				}
				else if (timeData[j] > animRange.End())
				{
					animRange.SetEnd(timeData[j]);
					animRangeChanged = true;
				}
			}
			if (animRangeChanged)
				m_maxInterface->SetAnimRange(animRange);

			// 设置动画关键桢数据
			IKeyControl* keyControl = GetKeyControlInterface(scaControl);
			keyControl->SetNumKeys(boneDef.scaling.nKeys);

			for (unsigned int j = 0; j < boneDef.scaling.nKeys; ++j)
			{
				AnyKey buf;
				ILinScaleKey* key = reinterpret_cast<ILinScaleKey*>((IKey*)buf);
				key->time = timeData[j];
				key->val = ScaleValue(keyData[j]);
				keyControl->AppendKey(key);
			}
		}
	}
}