Beispiel #1
0
ColMesh* RBExport::GetColMesh( INode* node )
{
    ObjectState os      = node->EvalWorldState( m_CurTime );
    Object*     pObject = os.obj;
    if (!pObject) 
    {
        Warn( "Could not evaluate object state. Collision mesh %s was skipped.", node->GetName() );
        return NULL;
    }

    Matrix3 nodeTM          = node->GetNodeTM( m_CurTime );
    Matrix3 nodeTMAfterWSM  = node->GetObjTMAfterWSM( m_CurTime );
    Matrix3 mOffs           = nodeTMAfterWSM*Inverse( nodeTM );

    //  triangulate
    TriObject* pTriObj = NULL;
    if (pObject->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID, 0 ) )) 
    { 
        pTriObj = (TriObject*)pObject->ConvertToType( m_CurTime, Class_ID( TRIOBJ_CLASS_ID, 0 ) );
    }
    bool bReleaseTriObj = (pTriObj != pObject);
    if (!pTriObj) 
    {
        Warn( "Could not triangulate mesh in node. Collision mesh %s was skipped.", node->GetName() );
        return NULL;
    }

    //  ensure, that vertex winding direction in polygon is CCW
    Matrix3 objTM = node->GetObjTMAfterWSM( m_CurTime );
    bool bNegScale = (DotProd( CrossProd( objTM.GetRow(0), objTM.GetRow(1) ), objTM.GetRow(2) ) >= 0.0);

    int vx[3];
    vx[0] = bNegScale ? 2 : 0;
    vx[1] = bNegScale ? 1 : 1;
    vx[2] = bNegScale ? 0 : 2;

    Mesh& mesh = pTriObj->GetMesh();

    //  some cosmetics
    mesh.RemoveDegenerateFaces();
    mesh.RemoveIllegalFaces();
    
    //  create collision mesh
    ColMesh* pMesh = new ColMesh();
    
    int numPri  = mesh.getNumFaces();
    int numVert = mesh.numVerts;

    //  copy vertices
    for (int i = 0; i < numVert; i++)
    {
        Point3 pt   = mesh.verts[i];
        pt = mOffs.PointTransform( pt );
        pt = c_FlipTM.PointTransform( pt );
        pMesh->AddVertex( Vec3( pt.x, pt.y, pt.z ) );
    }

    //  loop on mesh faces
    for (int i = 0; i < numPri; i++)
    {
        Face& face = mesh.faces[i];
        pMesh->AddPoly( face.v[vx[0]], face.v[vx[1]], face.v[vx[2]] );
    }

    Msg( LogType_Stats, "Physics collision trimesh has %d vertices and %d faces.", numVert, numPri );

    return pMesh;
} // RBExport::GetColMesh
Beispiel #2
0
//-----------------------------------------------------------------------------
BOOL CExporter::Capture()
{
	VERIFY				(m_Style!=eExportUndef);
	Modifier*			pPhysique;
	IPhysiqueExport*	pExport;
	IPhyContextExport*	pContext;
	Object*				pObject;

	Matrix3				matMesh;
	Matrix3				matZero;

	if (!m_MeshNode){
		ERR("Select mesh and try again.");
		m_bHasError=TRUE; 
		return FALSE;
	}

	
	pObject				= m_MeshNode->GetObjectRef();
	if (!IsExportableMesh(m_MeshNode,pObject)){
		ERR("Can't receive node references.");
		m_bHasError=TRUE; 
		return FALSE;
	}

	// Get export interface
	pPhysique			= FindPhysiqueModifier(m_MeshNode);
	if (!pPhysique){
		ERR("Can't find Physique modifier.");
		m_bHasError=TRUE; 
		return FALSE;
	}
	pExport		= (IPhysiqueExport *)pPhysique->GetInterface(I_PHYINTERFACE);
	if (!pExport){
		ERR("Can't find Physique interface.");
		m_bHasError=TRUE; 
		return FALSE;
	}

	// Get mesh initial transform (used to mult by the bone matrices)
	int rval = CGINTM(m_MeshNode,pExport->GetInitNodeTM(m_MeshNode, matMesh));
	matZero.Zero();
	if (rval || matMesh.Equals(matZero, 0.0)){
		ERR("Old CS version. Can't export mesh");
		matMesh.IdentityMatrix();
	}

	// Add hierrarhy parts that has no effect on vertices, 
	// but required for hierrarhy stability

	if (eExportMotion==m_Style){
		if (m_AllBones.empty()){
			ERR("Invalid skin object. Bone not found.");
			return FALSE;
		}

		EConsole.ProgressStart((float)m_AllBones.size(),"..Capturing bones");
		for (DWORD i=0; i<m_AllBones.size(); i++){
			AddBone(m_AllBones[i], matMesh, pExport);
			EConsole.ProgressInc();
		}
		EConsole.ProgressEnd();
	}

	bool bRes = TRUE;
	if (eExportSkin==m_Style){
		// For a given Object's INode get a
		// ModContext Interface from the Physique Export Interface:
		pContext = (IPhyContextExport *)pExport->GetContextInterface(m_MeshNode);
		if (!pContext){
			ERR("Can't find Physique context interface.");
			return FALSE;
		}

		// convert to rigid with blending
		pContext->ConvertToRigid(TRUE);
		pContext->AllowBlending	(TRUE);

		// process vertices
		int	numVertices = pContext->GetNumberVertices();
		EConsole.ProgressStart(float(numVertices),"..Capturing vertices");
		for (int iVertex = 0; iVertex < numVertices; iVertex++ ){
			IPhyVertexExport *pVertexExport = (IPhyVertexExport *)pContext->GetVertexInterface(iVertex);
			R_ASSERT(pVertexExport);

			// What kind of vertices are these?
			int iVertexType = pVertexExport->GetVertexType();

			IPhyRigidVertex* pRigidVertex=(IPhyRigidVertex*)pContext->GetVertexInterface(iVertex);
			R_ASSERT					(pRigidVertex);
			switch (iVertexType){
			case RIGID_TYPE:{			
				INode* node				= pRigidVertex->GetNode(); 
				R_ASSERT				(node);
				LPCSTR nm				= node->GetName();
				// get bone and create vertex
				CVertexDef* pVertex		= AddVertex();
				int boneId				= AddBone(node,matMesh,pExport);
				if(BONE_NONE==boneId){
					ERR					("Invalid bone: ",node->GetName());
					bRes				= FALSE;
				}else pVertex->Append	(boneId,1.f);
							}break;
			case RIGID_BLENDED_TYPE:{
				IPhyBlendedRigidVertex*	pBlendedRigidVertex=(IPhyBlendedRigidVertex*)pRigidVertex;
				int cnt					= pBlendedRigidVertex->GetNumberNodes();
				CVertexDef* pVertex		= AddVertex();
				for (int i=0; i<cnt; i++){
					INode* node			= pBlendedRigidVertex->GetNode(i); 
					R_ASSERT			(node);
					LPCSTR nm			= node->GetName();
					// get bone and create vertex
					int boneId			= AddBone(node,matMesh,pExport);
					if(BONE_NONE==boneId){
						ERR				("Invalid bone: ",node->GetName());
						bRes			= FALSE;
					}else pVertex->Append(boneId,pBlendedRigidVertex->GetWeight(i));
				}
									}break;
			}

			// release vertex
			pContext->ReleaseVertexInterface( pRigidVertex );

			EConsole.ProgressInc();

			if (!bRes) break;
		}
		EConsole.ProgressEnd();

		if (!bRes) return FALSE;

		static int remap[3];
		if (U.m_SkinFlipFaces){
			remap[0] = 0;
			remap[1] = 1;
			remap[2] = 2;
		}else{
			remap[0] = 0;
			remap[1] = 2;
			remap[2] = 1;
		}

		// Process mesh
		// Get object from node. Abort if no object.
		Log("..Transforming mesh");
		BOOL		bDeleteTriObject;
		R_ASSERT	(pObject);
		TriObject *	pTriObject	= GetTriObjectFromObjRef(pObject, &bDeleteTriObject);
		if (!pTriObject){
			ERR("Can't create tri object.");
			return FALSE;
		}
		Mesh&		M = pTriObject->mesh;

		// Vertices
		{
			// check match with
			int iNumVert = M.getNumVerts();
			if (!(iNumVert==numVertices && iNumVert==m_Vertices.size()))
			{
				ERR("Non attached vertices found.");
				if (bDeleteTriObject)	delete(pTriObject);
				return FALSE;
			}

			// transform vertices
			for (int i=0; i<iNumVert; i++){
				Point3 P = M.getVert(i);
				Point3 T = matMesh.PointTransform(P);
				T *= m_fGlobalScale;
				m_Vertices[i]->SetPosition(T);
			}
		}

		Log("..Parsing materials");
		// Parse Materials
		m_MtlMain = m_MeshNode->GetMtl();
		R_ASSERT(m_MtlMain);

		DWORD cSubMaterials=m_MtlMain->NumSubMtls();
		if (cSubMaterials < 1) {
			// Count the material itself as a submaterial.
			cSubMaterials = 1;
		}

		// build normals
		M.buildRenderNormals();

		Log("..Converting vertices");
		// our Faces and Vertices
		{
			for (int i=0; i<M.getNumFaces(); i++){
				Face*	gF	= M.faces  + i;
				TVFace*	tF	= M.tvFace + i;

				int m_id = gF->getMatID();
				if (cSubMaterials == 1){
					m_id = 0;
				}else{
					// SDK recommends mod'ing the material ID by the valid # of materials, 
					// as sometimes a material number that's too high is returned.
					m_id %= cSubMaterials;
				}

				st_FACE* nF		= xr_new<st_FACE>();
				nF->m_id		= m_id;
				nF->sm_group	= gF->getSmGroup();
				for (int VVV=0; VVV<3; VVV++){
					int vert_id = gF->v[remap[VVV]];

					CVertexDef	&D	= *(m_Vertices[vert_id]);
					Point3		&UV	= M.tVerts[tF->t[remap[VVV]]];

					st_VERT		v;
					v.Set		(D);
					v.P.set		(D.P); 
					v.SetUV		(UV.x,1-UV.y);
//					v.sm_group	= U.m_SkinSuppressSmoothGroup?0:gF->getSmGroup(); // smooth group
					nF->v[VVV]	= AddVert(v);
				}
				m_ExpFaces.push_back(nF);
			}
		}
		if (bDeleteTriObject)	delete(pTriObject);
	}
	UpdateParenting();

	return bRes;
};
Beispiel #3
0
//  Here we process mesh geometry for given node.
//  Vertices for the geometry from the all meshes of the scene are allocated in 
//  one big vertex pool. One vertex can occur several times in this pool, because
//  we add 3 new vertices for every face.
//  After all meshes in the scene are processed, this pool is collapsed to remove
//  duplicate vertices.
void RBExport::ProcessMesh( INode* node )
{
    if (!node->Renderable() || node->IsNodeHidden())
    {
        return;
    }
    
    ObjectState os      = node->EvalWorldState( m_CurTime );
    Object*     pObject = os.obj;
    if (!pObject) 
    {
        Warn( "Could not evaluate object state in node <%s>. Mesh was skipped.", node->GetName() );
        return;
    }
    Matrix3 nodeTM          = node->GetNodeTM( m_CurTime );
    Matrix3 nodeTMAfterWSM  = node->GetObjTMAfterWSM( m_CurTime );
    Matrix3 mOffs           = nodeTMAfterWSM*Inverse( nodeTM );

    //  triangulate
    TriObject* pTriObj = 0;
    if (pObject->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID, 0 ) )) 
    { 
        pTriObj = (TriObject*)pObject->ConvertToType( m_CurTime, Class_ID( TRIOBJ_CLASS_ID, 0 ) );
    }
    bool bReleaseTriObj = (pTriObj != pObject);
    if (!pTriObj) 
    {
        Warn( "Could not triangulate mesh in node <%s>. Node was skipped", node->GetName() );
        return;
    }

    if (!MeshModStackIsValid( node ))
    {
        Warn( "Modifier stack for node %s should be collapsed or contain only Skin modifier.", 
                node->GetName() );
    }

    //  ensure, that vertex winding direction in polygon is CCW
    Matrix3 objTM = node->GetObjTMAfterWSM( m_CurTime );
    bool bNegScale = (DotProd( CrossProd( objTM.GetRow(0), objTM.GetRow(1) ), objTM.GetRow(2) ) >= 0.0);

    int vx[3];
    if (bNegScale) 
    {
        vx[0] = 0; 
        vx[1] = 1; 
        vx[2] = 2; 
    } 
    else 
    { 
        vx[0] = 2; 
        vx[1] = 1; 
        vx[2] = 0; 
    }

    Mesh& mesh = pTriObj->GetMesh();

    bool bHasTexCoord    = (mesh.numTVerts != 0);
    bool bHasVertexColor = (mesh.numCVerts != 0) && m_pConfig->m_bExportVertexColors;
    bool bHasNormal      = m_pConfig->m_bExportNormals; 
    bool bHasSkin        = ProcessSkin( node );

    //  some cosmetics
    BOOL res = mesh.RemoveDegenerateFaces();
    if (res) 
    {
        Spam( "Degenerate faces were fixed." );
    }

    res = mesh.RemoveIllegalFaces();
    if (res) 
    {
        Spam( "Degenerate indices were fixed." );
    }
    
    ExpNode* pExpNode = GetExportedNode( node );
    if (!pExpNode)
    {
        return;
    }

    int numPri     = mesh.getNumFaces();
    int numVert    = mesh.numVerts;

    //  initialize helper array for building vertices' 0-circles
    VertexPtrArray vertexEntry;
    vertexEntry.resize( numVert );
    memset( &vertexEntry[0], 0, sizeof( ExpVertex* )*numVert );

    Spam( "Original mesh has %d vertices and %d faces.", numVert, numPri );
    bool bHasVoidFaces = false;

    //  loop on mesh faces
    for (int i = 0; i < numPri; i++)
    {
        Face& face = mesh.faces[i];

        //  calculate face normal
        const Point3& v0 = mesh.verts[face.v[vx[0]]]; 
        const Point3& v1 = mesh.verts[face.v[vx[1]]]; 
        const Point3& v2 = mesh.verts[face.v[vx[2]]]; 
        Point3 normal = -Normalize( (v1 - v0)^(v2 - v1) ); 
        normal = mOffs.VectorTransform( normal );
        normal = c_FlipTM.VectorTransform( normal );

        //  loop on face vertices
        ExpVertex* pFaceVertex[3];
        for (int j = 0; j < 3; j++)
        {
            ExpVertex v;
            v.mtlID  = pExpNode->GetMaterialIdx( face.getMatID() );            
            v.nodeID = pExpNode->m_Index;

            if (v.mtlID < 0)
            {
                bHasVoidFaces = true;
            }
            
            //  extract vertex position and apply world-space modifier to it
            int vIdx    = face.v[vx[j]];
            Point3 pt   = mesh.verts[vIdx];
            pt = mOffs.PointTransform( pt );
            pt = c_FlipTM.PointTransform( pt );
            
            v.index = vIdx;
            v.pos   = Vec3( pt.x, pt.y, pt.z );
            //v.pos *= m_WorldScale;

            //  extract skinning info
            if (bHasSkin)
            {
                GetSkinInfo( v );
            }

            //  assign normal
            if (bHasNormal)
            {
                v.normal  = Vec3( normal.x, normal.y, normal.z );
                v.smGroup = face.smGroup;
            }
            
            //  extract vertex colors
            if (bHasVertexColor)    
            {
                const VertColor& vcol = mesh.vertCol[mesh.vcFace[i].t[vx[j]]];
                v.color = ColorToDWORD( Color( vcol.x, vcol.y, vcol.z ) );
            }

            //  extract texture coordinates
            if (bHasTexCoord)   
            {
                const Point3& texCoord = mesh.tVerts[mesh.tvFace[i].t[vx[j]]];
                v.uv.x = texCoord.x;
                v.uv.y = 1.0f - texCoord.y;

                //  second texture coordinate channel
                if (mesh.getNumMaps() > 1 && mesh.mapSupport( 2 ))
                {
                    UVVert* pUVVert = mesh.mapVerts( 2 );
                    TVFace* pTVFace = mesh.mapFaces( 2 );
                    if (pUVVert && pTVFace)
                    {
                        const Point3& tc2 = pUVVert[pTVFace[i].t[vx[j]]];
                        v.uv2.x = tc2.x;
                        v.uv2.y = 1.0f - tc2.y;
                    }
                }
            }

            //  allocate new vertex 
            pFaceVertex[j] = AddVertex( v );

            //  we want vertices in the 0-ring neighborhood to be linked into closed linked list
            if (vertexEntry[vIdx] == NULL) 
            {
                vertexEntry[vIdx] = pFaceVertex[j];
                pFaceVertex[j]->pNext = pFaceVertex[j];
            }
            else
            {
                vertexEntry[vIdx]->AddToZeroRing( pFaceVertex[j] );
            }
        }
        AddPolygon( pFaceVertex[0], pFaceVertex[1], pFaceVertex[2] );

        if (IsCanceled())
        {
            return;
        }
    }

    //  correct normals at vertices corresponding to smoothing groups
    SmoothNormals( vertexEntry );

    //  put vertices into set (this removes duplicate vertices)
    for (int i = 0; i < numVert; i++)
    {
        ExpVertex::ZeroRingIterator it( vertexEntry[i] );
        while (it)
        {
            VertexSet::iterator sIt = m_VertexSet.find( it );
            if (sIt == m_VertexSet.end())
            {
                m_VertexSet.insert( it );
            }
            else
            {
                it->pBase = (*sIt);
            }
            ++it;
        }
    }

    if (bReleaseTriObj) 
    {
        delete pTriObj;
    }

    if (bHasVoidFaces)
    {
        Warn( "Mesh %s has faces with no material assigned.", node->GetName() );
    }
} // RBExport::ProcessMesh