Пример #1
0
static void extractTriangleGeometry( GmModel* gm, INode* node, Mesh* mesh, Mtl* material )
{
#ifdef SGEXPORT_PHYSIQUE
	Modifier*			phyMod		= 0;
	IPhysiqueExport*	phyExport	= 0;
	IPhyContextExport*	mcExport	= 0;
#endif
	Modifier*			skinMod		= 0;
	ISkin*				skin		= 0;
	String				nodeName	( node->GetName() );

	try
	{
		// vertex transform to left-handed system
		Matrix3 pivot = TmUtil::getPivotTransform( node );
		Matrix3 vertexTM = pivot * s_convtm;
		bool insideOut = TmUtil::hasNegativeParity( pivot );

		/*Matrix4x4 pm = TmUtil::toLH( vertexTM );
		Debug::println( "Object {0} vertex local TM is", nodeName );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(0,0), pm(0,1), pm(0,2), pm(0,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(1,0), pm(1,1), pm(1,2), pm(1,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(2,0), pm(2,1), pm(2,2), pm(2,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(3,0), pm(3,1), pm(3,2), pm(3,3) );*/

		// add vertex positions
		int vertices = mesh->getNumVerts();
		for ( int vi = 0 ; vi < vertices ; ++vi )
		{
			Point3 v = vertexTM * mesh->verts[vi];
			mb::Vertex* vert = gm->addVertex();
			vert->setPosition( v.x, v.y, v.z );
		}

		// add vertex weights (from Physique modifier)
#ifdef SGEXPORT_PHYSIQUE
		phyMod = PhyExportUtil::findPhysiqueModifier( node );
		if ( phyMod )
		{
			Debug::println( "  Found Physique modifier: {0}", gm->name );

			// get (possibly shared) Physique export interface
			phyExport = (IPhysiqueExport*)phyMod->GetInterface( I_PHYINTERFACE );
			if( !phyExport )
				throw Exception( Format("No Physique modifier export interface") );

			// export from initial pose?
			phyExport->SetInitialPose( false );
			
			// get (unique) context dependent export inteface
			mcExport = (IPhyContextExport*)phyExport->GetContextInterface( node );
			if( !mcExport )
				throw Exception( Format("No Physique modifier context export interface") );

			// convert to rigid for time independent vertex assignment
			mcExport->ConvertToRigid( true );

			// allow blending to export multi-link assignments
			mcExport->AllowBlending( true );

			// list bones
			Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) );
			PhyExportUtil::listBones( mcExport, bones );

			// add vertex weight maps
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				INode* bone = bones[i];
				String name = bone->GetName();
				mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT );
				PhyExportUtil::addWeights( vmap, bone, mcExport );
			}
		}
#endif // SGEXPORT_PHYSIQUE

		// add vertex weights (from Skin modifier)
		skinMod = SkinExportUtil::findSkinModifier( node );
		if ( skinMod )
		{
			skin = (ISkin*)skinMod->GetInterface(I_SKIN);
			require( skin );
			ISkinContextData* skincx = skin->GetContextInterface( node );
			require( skincx );
			Debug::println( "  Found Skin modifier: {0} ({1} bones, {2} points)", gm->name, skin->GetNumBones(), skincx->GetNumPoints() );
			
			if ( skincx->GetNumPoints() != gm->vertices() )
				throw Exception( Format("Only some vertices ({0}/{1}) of {2} are skinned", skincx->GetNumPoints(), gm->vertices(), gm->name) );

			// list bones
			Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) );
			SkinExportUtil::listBones( skin, bones );

			// add vertex weight maps
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				INode* bone = bones[i];
				String name = bone->GetName();
				mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT );
				SkinExportUtil::addWeights( vmap, bone, skin, skincx );
				//Debug::println( "    Bone {0} is affecting {1} vertices", name, vmap->size() );
			}

			// DEBUG: print skin node tm and initial object tm
			/*Matrix3 tm;
			int ok = skin->GetSkinInitTM( node, tm );
			require( ok == SKIN_OK );
			Debug::println( "  NodeInitTM of {0}", nodeName );
			TmUtil::println( tm, 4 );
			ok = skin->GetSkinInitTM( node, tm, true );
			require( ok == SKIN_OK );
			Debug::println( "  NodeObjectTM of {0}", nodeName );
			TmUtil::println( tm, 4 );*/

			// DEBUG: print bones
			/*Debug::println( "  bones of {0}:", nodeName );
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				Debug::println( "    bone ({0}): {1}", i, String(bones[i]->GetName()) );
				skin->GetBoneInitTM( bones[i], tm );
				Debug::println( "      InitNodeTM:" );
				TmUtil::println( tm, 6 );
				skin->GetBoneInitTM( bones[i], tm, true );
				Debug::println( "      InitObjectTM:" );
				TmUtil::println( tm, 6 );
			}*/

			// DEBUG: print bones used by the points
			/*for ( int i = 0 ; i < skincx->GetNumPoints() ; ++i )
			{
				int bonec = skincx->GetNumAssignedBones(i);
				Debug::println( "    point {0} has {1} bones", i, bonec );
				for ( int k = 0 ; k < bonec ; ++k )
				{
					int boneidx = skincx->GetAssignedBone( i, k );
					float w = skincx->GetBoneWeight( i, k );
					Debug::println( "    point {0} boneidx ({1}): {2}, weight {3}", i, k, boneidx, w );
				}
			}*/
		}

		// ensure clockwise polygon vertex order
		int vx[3] = {2,1,0};
		if ( insideOut )
		{
			int tmp = vx[0];
			vx[0] = vx[2];
			vx[2] = tmp;
		}
	
		// list unique materials used by the triangles
		Vector<ShellMaterial> usedMaterials( Allocator<ShellMaterial>(__FILE__,__LINE__) );
		if ( material )
		{
			for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
			{
				Face& face = mesh->faces[fi];
				
				int mergesubmaterial = -1;
				int originalsubmaterial = -1;

				for ( int j = 0; j < material->NumSubMtls(); ++j)
				{
					// Get Sub Material Slot name 
					TSTR name = material->GetSubMtlSlotName(j);

					// Light maps are stored in sub material slot named "Baked Material"
					if ( strcmp( name, "Baked Material" ) == 0 ) 
						mergesubmaterial = j;
					else 
						originalsubmaterial = j;				
				}

				if ( mergesubmaterial != -1 ) // A baked material was found, shell materials will be created
				{
					Mtl* mat = material->GetSubMtl( originalsubmaterial );
					Mtl* bakedmtl = material->GetSubMtl( mergesubmaterial );
				
					if ( mat->NumSubMtls() > 0 ) // Check for nested multi-material
					{
						for ( int j = 0; j < mat->NumSubMtls(); ++j)
							usedMaterials.add( ShellMaterial( mat->GetSubMtl( face.getMatID() % mat->NumSubMtls() ), bakedmtl ) );
					} else
						usedMaterials.add( ShellMaterial( mat, bakedmtl ) );
				}
				else if ( material->NumSubMtls() > 0 ) // Multi-material without baked material 
				{  
					usedMaterials.add( ShellMaterial( material->GetSubMtl( face.getMatID() % material->NumSubMtls() ), 0 ) ); 
				}
				else	// Single material without baked material
				{
					usedMaterials.add( ShellMaterial( material, 0 ) );
				}				
			}
			std::sort( usedMaterials.begin(), usedMaterials.end() );
			usedMaterials.setSize( std::unique( usedMaterials.begin(), usedMaterials.end() ) - usedMaterials.begin() );
		}

		// create used materials
		for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi )
		{
			ShellMaterial shellmtl = usedMaterials[mi];
			gm->materials.add( GmUtil::createGmMaterial( shellmtl.original, shellmtl.baked ) );
		}

		// add triangles
		for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
		{
			mb::Polygon* poly = gm->addPolygon();

			// triangle indices
			Face& face = mesh->faces[fi];
			for ( int vxi = 0 ; vxi < 3 ; ++vxi )
			{
				int vi = face.v[ vx[vxi] ];
				require( vi >= 0 && vi < gm->vertices() );
				mb::Vertex* vert = gm->getVertex( vi );
				poly->addVertex( vert );
			}

			// triangle material
			int polyMaterialIndex = 0;
			if ( material )
			{
				ShellMaterial mat( material, 0 );
				
				int numsubmaterials = material->NumSubMtls();  

				if ( numsubmaterials > 0 )
				{
					mat.original = material->GetSubMtl( face.getMatID() % material->NumSubMtls() );
		
					for ( int j = 0; j < numsubmaterials; ++j) // Is baked material present?
					{
						TSTR name = material->GetSubMtlSlotName(j);
						if ( strcmp( name, "Baked Material" ) == 0 )
							mat.baked = material->GetSubMtl( j );
						if ( strcmp( name, "Original Material" ) == 0 )
							mat.original = material->GetSubMtl( j );
					}
					if ( mat.original->NumSubMtls() > 0 )  // Is there a nested multi-material?
					{
						mat.original = mat.original->GetSubMtl( face.getMatID() % mat.original->NumSubMtls() );
					}
				}

				for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi )
				{
					if ( usedMaterials[mi] == mat )
					{
						polyMaterialIndex = mi;
						break;
					}
				}
			}
			poly->setMaterial( polyMaterialIndex );
		}

		// add vertex colors
		int mp = 0;
		if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 )
		{
			mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "rgb", mb::VertexMapFormat::VERTEXMAP_RGB );

			int tverts = mesh->getNumMapVerts( mp );
			UVVert* tvert = mesh->mapVerts( mp );
			TVFace* tface = mesh->mapFaces( mp );

			//Debug::println( "Vertex colors:" );
			for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
			{
				Face& face = mesh->faces[fi];
				mb::Polygon* poly = gm->getPolygon( fi );

				for ( int vxi = 0 ; vxi < 3 ; ++vxi )
				{
					int vi = face.v[ vx[vxi] ];
					mb::Vertex* vert = gm->getVertex( vi );
					Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ];
					float rgb[3] = {tc.x, tc.y, tc.z};
					vmad->addValue( vert->index(), poly->index(), rgb, 3 );
					//Debug::println( "  vertex[{0}].rgb: {1} {2} {3}", vert->index(), rgb[0], rgb[1], rgb[2] );
				}
			}
		}

		// add texcoord layers
		int lastCoords = MAX_MESHMAPS-2;
		while ( lastCoords > 0 && (!mesh->mapSupport(lastCoords) || 0 == mesh->getNumMapVerts(lastCoords)) )
			--lastCoords;
		if ( lastCoords > 8 )
			throw IOException( Format("Too many texture coordinate sets ({1}) in {0}", gm->name, lastCoords) );

		for ( mp = 1 ; mp <= lastCoords ; ++mp )
		{
			mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 2, "uv", mb::VertexMapFormat::VERTEXMAP_TEXCOORD );

			if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 )
			{
				int tverts = mesh->getNumMapVerts( mp );
				UVVert* tvert = mesh->mapVerts( mp );
				TVFace* tface = mesh->mapFaces( mp );
				
				for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
				{
					Face& face = mesh->faces[fi];
					mb::Polygon* poly = gm->getPolygon( fi );

					for ( int vxi = 0 ; vxi < 3 ; ++vxi )
					{
						int vi = face.v[ vx[vxi] ];
						mb::Vertex* vert = gm->getVertex( vi );
						Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ];
						float uv[2] = {tc.x, 1.f-tc.y};
						vmad->addValue( vert->index(), poly->index(), uv, 2 );
					}
				}
			}
		}

		// compute face vertex normals from smoothing groups
		require( mesh->getNumFaces() == gm->polygons() );
		mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "vnormals", mb::VertexMapFormat::VERTEXMAP_NORMALS );
		for ( int fi = 0 ; fi < gm->polygons() ; ++fi )
		{
			mb::Polygon* poly = gm->getPolygon( fi );
			require( poly );
			require( poly->index() >= 0 && poly->index() < mesh->getNumFaces() );
			Face& face = mesh->faces[ poly->index() ];

			require( poly->vertices() == 3 );
			for ( int j = 0 ; j < poly->vertices() ; ++j )
			{
				Vector3 vn(0,0,0);
				mb::Vertex* vert = poly->getVertex( j );

				// sum influencing normals
				for ( int k = 0 ; k < vert->polygons() ; ++k )
				{
					mb::Polygon* vpoly = vert->getPolygon( k );
					require( vpoly );
					require( vpoly->index() >= 0 && vpoly->index() < mesh->getNumFaces() );
					Face& vface = mesh->faces[ vpoly->index() ];

					if ( 0 != (face.smGroup & vface.smGroup) || poly == vpoly )
					{
						Vector3 vpolyn;
						vpoly->getNormal( &vpolyn.x, &vpolyn.y, &vpolyn.z );
						vn += vpolyn;
					}
				}

				// normalize
				float lensqr = vn.lengthSquared();
				if ( lensqr > Float::MIN_VALUE )
					vn *= 1.f / Math::sqrt(lensqr);
				else
					vn = Vector3(0,0,0);

				vmad->addValue( vert->index(), poly->index(), vn.begin(), 3 );
			}
		}

		// re-export mesh points in non-deformed pose if Skin modifier present
		// NOTE: 3ds Mesh must not be used after this, because collapsing can invalidate it
		if ( skin )
		{
			// evaluate derived object before Skin modifier
			TimeValue time = 0;
			bool evalNext = false;
			bool evalDone = false;
			::ObjectState os;
			::Object* obj = node->GetObjectRef();
			while ( obj->SuperClassID() == GEN_DERIVOB_CLASS_ID && !evalDone )
			{
				IDerivedObject* derivedObj = static_cast<IDerivedObject*>(obj);
				for ( int modStack = 0 ; modStack < derivedObj->NumModifiers() ; ++modStack )
				{
					if ( evalNext )
					{
						os = derivedObj->Eval( time, modStack );
						evalDone = true;
						break;
					}

					Modifier* mod = derivedObj->GetModifier(modStack);
					if ( mod->ClassID() == SKIN_CLASSID )
						evalNext = true;
				}
				obj = derivedObj->GetObjRef();
			}

			// evaluate possible non-derived object
			if ( evalNext && !evalDone )
			{
				os = obj->Eval( time );
				evalDone = true;
			}

			// convert to TriObject and get points
			if ( evalDone && os.obj->CanConvertToType( Class_ID(TRIOBJ_CLASS_ID,0) ) )
			{
				Debug::println( "  Evaluating object {0} before Skin modifier", nodeName );

				// get TriObject
				std::auto_ptr<TriObject> triAutoDel(0);
				TriObject* tri = static_cast<TriObject*>( os.obj->ConvertToType( time, Class_ID(TRIOBJ_CLASS_ID,0) ) );
				if ( tri != os.obj )
					triAutoDel = std::auto_ptr<TriObject>( tri );

				// get mesh points before Skin is applied
				//Debug::println( "  Original collapsed mesh has {0} points, before Skin modifier {1} points", mesh->getNumVerts(), tri->mesh.getNumVerts() );
				require( gm->vertices() == tri->mesh.getNumVerts() );
				Mesh* mesh = &tri->mesh;
				int vertices = mesh->getNumVerts();
				for ( int vi = 0 ; vi < vertices ; ++vi )
				{
					Point3 v = vertexTM * mesh->verts[vi];
					mb::Vertex* vert = gm->getVertex( vi );
					vert->setPosition( v.x, v.y, v.z );
				}
			}
		}

		// split vertices with discontinuous vertex map values
		for ( int vmi = 0 ; vmi < gm->discontinuousVertexMaps() ; ++vmi )
		{
			mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap( vmi );
			gm->splitVertexDiscontinuities( vmad );
		}

		// find base texcoord layer
		mb::DiscontinuousVertexMap* texcoords = 0;
		for ( int i = 0 ; i < gm->discontinuousVertexMaps() ; ++i )
		{
			mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap(i);
			if ( vmad->dimensions() == 2 && vmad->format() == mb::VertexMapFormat::VERTEXMAP_TEXCOORD )
			{
				texcoords = vmad;
				break;
			}
		}
		if ( !texcoords )
			Debug::printlnError( "Object {0} must have texture coordinates", gm->name );
			// requires identification of footsteps in MySceneExport::isExportableGeometry
			//throw IOException( Format("Object {0} must have texture coordinates", gm->name) );

		// optimize
		gm->removeUnusedVertices();

		// cleanup export interfaces
#ifdef SGEXPORT_PHYSIQUE
		if ( mcExport )
		{
			require( phyExport );
			phyExport->ReleaseContextInterface( mcExport );
			mcExport = 0;
		}
		if ( phyExport )
		{
			require( phyMod );
			phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport );
			phyExport = 0;
		}
#endif // SGEXPORT_PHYSIQUE
		if ( skin )
		{
			skinMod->ReleaseInterface( I_SKIN, skin );
			skin = 0;
			skinMod = 0;
		}
	}
	catch ( ... )
	{
		// cleanup export interfaces
#ifdef SGEXPORT_PHYSIQUE
		if ( mcExport )
		{
			require( phyExport );
			phyExport->ReleaseContextInterface( mcExport );
			mcExport = 0;
		}
		if ( phyExport )
		{
			require( phyMod );
			phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport );
			phyExport = 0;
		}
#endif // SGEXPORT_PHYSIQUE
		if ( skin )
		{
			skinMod->ReleaseInterface( I_SKIN, skin );
			skin = 0;
			skinMod = 0;
		}
		throw;
	}
}
Пример #2
0
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId)
{
    // check for valid mesh and physique modifier
    if((m_pIMesh == 0))
    {
        theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
        return 0;
    }

    // check if face id is valid
    if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces()))
    {
        theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__);
        return 0;
    }

    // check if face vertex id is valid
    if((faceVertexId < 0) || (faceVertexId >= 3))
    {
        theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__);
        return 0;
    }

    // allocate a new vertex candidate
    CVertexCandidate *pVertexCandidate;
    pVertexCandidate = new CVertexCandidate();
    if(pVertexCandidate == 0)
    {
        theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__);
        return 0;
    }

    // create the new vertex candidate
    if(!pVertexCandidate->Create())
    {
        delete pVertexCandidate;
        return 0;
    }

    // get vertex id
    int vertexId;
    vertexId = m_pIMesh->faces[faceId].v[faceVertexId];

    // get the absolute vertex position
    Point3 vertex;
    vertex = m_pIMesh->getVert(vertexId) * m_tm;

    // set the vertex candidate position
    pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z);
    pVertexCandidate->SetUniqueId(vertexId);

    // get the absolute vertex normal
    Point3 normal;
    normal = GetVertexNormal(faceId, vertexId);
    normal = normal * Inverse(Transpose(m_tm));
    normal = normal.Normalize();

    // set the vertex candidate normal
    pVertexCandidate->SetNormal(normal.x, normal.y, normal.z);
 
  if(m_pIMesh->numCVerts > 0)
  { 
        VertColor vc;
        vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]];
    CalVector vcCal(vc.x, vc.y, vc.z);
    pVertexCandidate->SetVertColor(vcCal);
  }  
 
    // get the vertex weight array
    float *pVertexWeights;
    pVertexWeights = m_pIMesh->getVertexWeights();
  //if( pVertexWeights == NULL ) {
    //    delete pVertexCandidate;
    //    theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__);
    //    return 0;
  //}

    // get the vertex weight (if possible)
    float weight;
    if(pVertexWeights != 0)
    {
        weight = pVertexWeights[vertexId];
    }
    else
    {
        weight = 0.0f;
    }

    // another 3ds max weird behaviour:
    // zero out epsilon weights
    if(weight < 0.0005f) weight = 0.0f;

    // set the vertex candidate weight
    pVertexCandidate->SetPhysicalProperty(weight);

    // get the material id of the face
    int materialId;
    materialId = GetFaceMaterialId(faceId);

    if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size()))
    {
        delete pVertexCandidate;
        theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__);
        return 0;
    }

    // get the material of the face
    StdMat *pStdMat;
    pStdMat = m_vectorStdMat[materialId];

    // loop through all the mapping channels and extract texture coordinates
    int mapId;
    for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++)
    {
        // get texture map
        Texmap *pTexMap;
        pTexMap = pStdMat->GetSubTexmap(mapId);

        // check if map is valid
        if((pTexMap != 0) && (pStdMat->MapEnabled(mapId)))
        {
            // get the mapping channel
            int channel;
            channel = pTexMap->GetMapChannel();

            bool bValidUV;
            bValidUV = false;

            // extract the texture coordinate
            UVVert uvVert;
            if(m_pIMesh->mapSupport(channel))
            {
                TVFace *pTVFace;
                pTVFace = m_pIMesh->mapFaces(channel);

                UVVert *pUVVert;
                pUVVert = m_pIMesh->mapVerts(channel);

                uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]];
                bValidUV = true;
            }
            else if(m_pIMesh->numTVerts > 0)
            {
                uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]];
                bValidUV = true;
            }

            // if we found valid texture coordinates, add them to the vertex candidate
            if(bValidUV)
            {
                // apply a possible uv generator
                StdUVGen *pStdUVGen;
                pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen();
                if(pStdUVGen != 0)
                {
                    Matrix3 tmUV;
                    pStdUVGen->GetUVTransform(tmUV);
                    uvVert = uvVert * tmUV;
                }

                // add texture coordinate to the vertex candidate, inverting the y coordinate
                pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y);
            }
        }
    }

    // check for physique modifier
    if(m_modifierType == MODIFIER_PHYSIQUE)
    {
        // create a physique export interface
        IPhysiqueExport *pPhysiqueExport;
        pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE);
        if(pPhysiqueExport == 0)
        {
            delete pVertexCandidate;
            theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // create a context export interface
        IPhyContextExport *pContextExport;
        pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode);
        if(pContextExport == 0)
        {
            m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
            delete pVertexCandidate;
            theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // set the flags in the context export interface
        pContextExport->ConvertToRigid(TRUE);
        pContextExport->AllowBlending(TRUE);

        // get the vertex export interface
        IPhyVertexExport *pVertexExport;
        pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId);
        if(pVertexExport == 0)
        {
            pPhysiqueExport->ReleaseContextInterface(pContextExport);
            m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
            delete pVertexCandidate;
            theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // get the vertex type
        int vertexType;
        vertexType = pVertexExport->GetVertexType();

        // handle the specific vertex type
        if(vertexType == RIGID_TYPE)
        {
            // typecast to rigid vertex
            IPhyRigidVertex *pTypeVertex;
            pTypeVertex = (IPhyRigidVertex *)pVertexExport;

                // add the influence to the vertex candidate
            // get the influencing bone
            if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f))
            {
                pPhysiqueExport->ReleaseContextInterface(pContextExport);
                m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
                delete pVertexCandidate;
                theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                return 0;
            }
        }
        else if(vertexType == RIGID_BLENDED_TYPE)
        {
            // typecast to blended vertex
            IPhyBlendedRigidVertex *pTypeVertex;
            pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport;

            // loop through all influencing bones
            int nodeId;
            for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++)
            {
                // add the influence to the vertex candidate
                if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId)))
                {
                    pPhysiqueExport->ReleaseContextInterface(pContextExport);
                    m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
                    delete pVertexCandidate;
                    theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                    return 0;
                }
            }
        }

        // release all interfaces
        pPhysiqueExport->ReleaseContextInterface(pContextExport);
        m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
    }
#if MAX_RELEASE >= 4000
    // check for skin modifier
    else if(m_modifierType == MODIFIER_SKIN)
    {
        // create a skin interface
        ISkin *pSkin;
        pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN);
        if(pSkin == 0)
        {
            delete pVertexCandidate;
            theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // create a skin context data interface
        ISkinContextData *pSkinContextData;
        pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode);
        if(pSkinContextData == 0)
        {
            m_pModifier->ReleaseInterface(I_SKIN, pSkin);
            delete pVertexCandidate;
            theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // loop through all influencing bones
        int nodeId;
        for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++)
        {
            // get the bone id
            int boneId;
            boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId);
            if(boneId < 0) continue;

            // add the influence to the vertex candidate
            if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId)))
            {
                m_pModifier->ReleaseInterface(I_SKIN, pSkin);
                delete pVertexCandidate;
                theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                return 0;
            }
        }

        // release all interfaces
        m_pModifier->ReleaseInterface(I_SKIN, pSkin);
    }
#endif
        else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) {
        }
        else 
    {
          theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__);
          return 0;
    }

    return pVertexCandidate;
}
Пример #3
0
// --[  Method  ]---------------------------------------------------------------
//
//  - Class     : CStravaganzaMaxTools
//
//  - prototype : bool AddNodeBones(std::vector<INode*> &vecMaxBones, INode *pMaxNode)
//
//  - Purpose   : Adds all bones belonging to the node to the given list.
//
// -----------------------------------------------------------------------------
bool CStravaganzaMaxTools::AddNodeBones(std::vector<INode*> &vecMaxBones, INode *pMaxNode)
{
	int  nCount       = 0;
	int  nBoneCount   = 0;
	bool bOK          = true;

	Modifier          *pPhyModifier  = NULL; // Physique modifier
	IPhysiqueExport   *pPhyExport    = NULL; // Physique export interface
	IPhyContextExport *pPhyObjExport = NULL; // Physique object export interface

	// Get Physique modifier

	if(pPhyModifier = GetPhysiqueModifier(pMaxNode))
	{
		pPhyExport = (IPhysiqueExport *)pPhyModifier->GetInterface(I_PHYINTERFACE);

		if(pPhyExport == NULL)
		{
			return false;
		}
	}
	else
	{
		return false;
	}

	// Get physique object export interface

	pPhyObjExport = pPhyExport->GetContextInterface(pMaxNode);

	if(pPhyObjExport == NULL)
	{
		pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport);
		return false;
	}

	pPhyObjExport->ConvertToRigid(true);
	pPhyObjExport->AllowBlending(true);

	INode *pMaxBone;

	// Build bone list

	LOG.Write("\nObject %s Bone List:", pMaxNode->GetName());

	for(nCount = 0; nCount < pPhyObjExport->GetNumberVertices(); nCount++)
	{
		IPhyVertexExport       *pPhyVertExport;
		IPhyBlendedRigidVertex *pPhyBRVertexExport;
		IPhyRigidVertex        *pPhyRigidVertexExport;
		IPhyFloatingVertex	   *pPhyFloatingVertex;

		pPhyVertExport = pPhyObjExport->GetVertexInterface(nCount);

		if(pPhyVertExport)
		{
			if(pPhyVertExport->GetVertexType() & BLENDED_TYPE)
			{
				pPhyBRVertexExport = (IPhyBlendedRigidVertex *)pPhyVertExport;

				for(nBoneCount = 0; nBoneCount < pPhyBRVertexExport->GetNumberNodes(); nBoneCount++)
				{
					pMaxBone = pPhyBRVertexExport->GetNode(nBoneCount);

					if(IsBoneInList(vecMaxBones, pMaxBone) == false)
					{
//						LOG.Write("\n  %s (blended)", pMaxBone->GetName());
						vecMaxBones.push_back(pMaxBone);
					}
				}
			}
			else
			{
				pPhyRigidVertexExport = (IPhyRigidVertex *)pPhyVertExport;

				pMaxBone = pPhyRigidVertexExport->GetNode();

				if(IsBoneInList(vecMaxBones, pMaxBone) == false)
				{
//					LOG.Write("\n  %s (rigid)", pMaxBone->GetName());
					vecMaxBones.push_back(pMaxBone);
				}
			}

			pPhyObjExport->ReleaseVertexInterface(pPhyVertExport);
		}

		pPhyFloatingVertex = pPhyObjExport->GetFloatingVertexInterface(nCount);

		if(pPhyFloatingVertex)
		{
			for(nBoneCount = 0; nBoneCount < pPhyFloatingVertex->GetNumberNodes(); nBoneCount++)
			{
				pMaxBone = pPhyFloatingVertex->GetNode(nBoneCount);

				if(IsBoneInList(vecMaxBones, pMaxBone) == false)
				{
//					LOG.Write("\n  %s (floating)", pMaxBone->GetName());
					vecMaxBones.push_back(pMaxBone);
				}
			}

			pPhyObjExport->ReleaseVertexInterface(pPhyFloatingVertex);
		}
	}

	pPhyExport->ReleaseContextInterface(pPhyObjExport);
	pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport);

	return bOK;
}
Пример #4
0
// --[  Method  ]---------------------------------------------------------------
//
//  - Class     : CStravaganzaMaxTools
//
//  - prototype : int BuildPhysiqueData(INode* pMaxNode,
//										CObject* pObject,
//                                      std::vector<std::string>    &vecBoneNames,
//										std::vector<CBlendedVertex> &vecBlendedVertices)
//
//  - Purpose   : Builds the bone data for a given node. Returns the number
//                of bones processed (0 = failure).
//
// -----------------------------------------------------------------------------
int	CStravaganzaMaxTools::BuildPhysiqueData(INode* pMaxNode,
											CObject* pObject,
											std::vector<std::string>    &vecBoneNames,
											std::vector<CBlendedVertex> &vecBlendedVertices)

{
	int nCount       = 0;
	int nBoneCount   = 0;

	Modifier          *pPhyModifier  = NULL; // Physique modifier
	IPhysiqueExport   *pPhyExport    = NULL; // Physique export interface
	IPhyContextExport *pPhyObjExport = NULL; // Physique object export interface

	vecBoneNames.clear();
	vecBlendedVertices.clear();

	// Build bone list

	std::vector<INode*> vecMaxBones;

	if(!AddNodeBones(vecMaxBones, pMaxNode))
	{
		LOG.Write("\nWARNING - Error building node %s bone list", pMaxNode->GetName());
		return 0;
	}

	// Build bones name list

	for(nBoneCount = 0; nBoneCount < vecMaxBones.size(); nBoneCount++)
	{
		vecBoneNames.push_back(vecMaxBones[nBoneCount]->GetName());
	}

	// Get Physique modifier

	if(pPhyModifier = GetPhysiqueModifier(pMaxNode))
	{
		pPhyExport = (IPhysiqueExport *)pPhyModifier->GetInterface(I_PHYINTERFACE);

		if(pPhyExport == NULL)
		{
			LOG.Write("\nWARNING - Couldn't get Physique export interface.\nFailed with node %s.", pMaxNode->GetName());
			return 0;
		}
	}

	// Get physique object export interface

	pPhyObjExport = pPhyExport->GetContextInterface(pMaxNode);

	if(pPhyObjExport == NULL)
	{
		pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport);
		LOG.Write("\nWARNING - Unable to get physique context export.\nFailed with node %s.", pMaxNode->GetName());
		return 0;
	}

	// Convert to rigid for time independent vertex assignment
	// Allow blending to export multi-link assignments

	pPhyObjExport->ConvertToRigid(true);
	pPhyObjExport->AllowBlending(true);

	// Build deformable vertex list

	bool bOK = true;
	int  nBlendedCount = 0, nBlendedRigidCount = 0, nFloatingCount = 0;

	for(nCount = 0; nCount < pPhyObjExport->GetNumberVertices(); nCount++)
	{
		IPhyVertexExport       *pPhyVertExport;
		IPhyBlendedRigidVertex *pPhyBRVertexExport;
		IPhyRigidVertex        *pPhyRigidVertexExport;
		IPhyFloatingVertex	   *pPhyFloatingVertex;

		pPhyVertExport  = pPhyObjExport->GetVertexInterface(nCount);

		CBlendedVertex blendedVertex;
		float fTotalWeight   = 0.0f;
		bool  bFloatingBones = false;

		// Floating Vertex

		pPhyFloatingVertex = pPhyObjExport->GetFloatingVertexInterface(nCount);

		if(pPhyFloatingVertex)
		{
			bFloatingBones = true;

			CVector3 v3OffsetVector;
			float    fWeight;

			// More than one bone

			int nNumVtxBones = pPhyFloatingVertex->GetNumberNodes();

//			LOG.Write("\n%u - Floating, with %u bones", nCount, nNumVtxBones);

			for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++)
			{
				int nIndex = GetBoneIndex(vecMaxBones, pPhyFloatingVertex->GetNode(nBoneCount));

				if(nIndex == -1)
				{
					LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyFloatingVertex->GetNode(nBoneCount)->GetName());
					bOK = false;
					break;
				}

				float fTotal;

				v3OffsetVector = Point3ToVector3(pPhyFloatingVertex->GetOffsetVector(nBoneCount));
				fWeight        = pPhyFloatingVertex->GetWeight(nBoneCount, fTotal);
				fTotalWeight  += fWeight;//fTotal;
				//fWeight = fTotal;

//				LOG.Write("\n     Weight = %f (%s)", fWeight, pPhyFloatingVertex->GetNode(nBoneCount)->GetName());

				blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight);
			}

//			LOG.Write("\n     Total = %f", fTotalWeight);

			if(!ARE_EQUAL(fTotalWeight, 1.0f))
			{
				LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight);
			}

			nFloatingCount++;

			pPhyObjExport->ReleaseVertexInterface(pPhyFloatingVertex);
		}

		if(pPhyVertExport)
		{
			if(pPhyVertExport->GetVertexType() & BLENDED_TYPE)
			{
				CVector3 v3OffsetVector;
				float    fWeight;

				// More than one bone

				pPhyBRVertexExport = (IPhyBlendedRigidVertex *)pPhyVertExport;
				int nNumVtxBones   = pPhyBRVertexExport->GetNumberNodes();

//				LOG.Write("\n%u - Blended, with %u bones", nCount, nNumVtxBones);

				for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++)
				{
					int nIndex = GetBoneIndex(vecMaxBones, pPhyBRVertexExport->GetNode(nBoneCount));

					if(nIndex == -1)
					{
						LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyBRVertexExport->GetNode(nBoneCount)->GetName());
						bOK = false;
						break;
					}

					v3OffsetVector = Point3ToVector3(pPhyBRVertexExport->GetOffsetVector(nBoneCount));
					fWeight        = pPhyBRVertexExport->GetWeight(nBoneCount);
					fTotalWeight  += fWeight;

//					LOG.Write("\n     Weight = %f (%s)", fWeight, pPhyBRVertexExport->GetNode(nBoneCount)->GetName());

					blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight);
				}

//				LOG.Write("\n     Total = %f", fTotalWeight);

				if(!ARE_EQUAL(fTotalWeight, 1.0f))
				{
					LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight);
				}

				nBlendedCount++;
			}
			else
			{
				CVector3 v3OffsetVector;
				float    fWeight;

				// Single bone

				pPhyRigidVertexExport = (IPhyRigidVertex *)pPhyVertExport;

				int nIndex = GetBoneIndex(vecMaxBones, pPhyRigidVertexExport->GetNode());

				if(nIndex == -1)
				{
					LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyRigidVertexExport->GetNode()->GetName());
					bOK = false;
					break;
				}

				v3OffsetVector = Point3ToVector3(pPhyRigidVertexExport->GetOffsetVector());
				fWeight        = 1.0f;
				fTotalWeight   = 1.0f;

//				LOG.Write("\n%u - Rigid (%s)", nCount, pPhyRigidVertexExport->GetNode()->GetName());

				blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight);

				nBlendedRigidCount++;
			}

			pPhyObjExport->ReleaseVertexInterface(pPhyVertExport);
		}

		for(int i = 0; i < blendedVertex.GetNumLinks(); i++)
		{
			// Normalize
			blendedVertex.SetWeight(i, blendedVertex.GetWeight(i) / fTotalWeight);
		}

		vecBlendedVertices.push_back(blendedVertex);
	}

	pPhyExport->ReleaseContextInterface(pPhyObjExport);
	pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport);

	if(!bOK)
	{
		vecMaxBones.clear();
		vecBoneNames.clear();
		vecBlendedVertices.clear();
	}
	else
	{
		LOG.Write("\nPhysique: %u bones, %u vertices (%u rigid, %u rigidblended, %u floating)",
				  vecBoneNames.size(),
				  vecBlendedVertices.size(),
				  nBlendedRigidCount,
				  nBlendedCount,
				  nFloatingCount);
	}

	return vecMaxBones.size();
}
Пример #5
0
void SGP_MaxInterface::GetBoneGroup( Modifier *pModifier,
									 int nModifierType, 
									 INode* pNode, 
									 Mesh* pMesh,
									 int nVertexId,
									 BoneGroup& boneGroup )
{
	if( !pMesh )
	{
		assert( false );
		return;
	}

	if( nVertexId >= pMesh->numVerts )
	{
		assert( false );
		return;
	}

	// static mesh
	if( nModifierType == MODIFIER_NONE )
	{
		INode* pParent = pNode->GetParentNode();
		if( pParent && ( IsBone( pParent ) || IsBipedBone( pParent ) ) )
		{
			Influence infl;
			infl.fWeight = 1.0f;
			strcpy( infl.szBoneName, pParent->GetName() );
			boneGroup.AddInfluence( infl );
		}
	}
	// check for physique modifier
	else if( nModifierType == MODIFIER_PHYSIQUE )
	{
		assert( pModifier && "get bone group error, modifier is null" );
		// create a physique export interface
		IPhysiqueExport *pPhysiqueExport = (IPhysiqueExport *)pModifier->GetInterface(I_PHYINTERFACE);
		if(pPhysiqueExport == NULL)
		{
			return;
		}

		// create a context export interface
		IPhyContextExport *pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(pNode);
		if(pContextExport == NULL)
		{
			pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
			return;
		}

		// set the flags in the context export interface
		pContextExport->ConvertToRigid(TRUE);
		pContextExport->AllowBlending(TRUE);

		// get the vertex export interface
		IPhyVertexExport *pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(nVertexId);
		if(pVertexExport == NULL)
		{
			pPhysiqueExport->ReleaseContextInterface(pContextExport);
			pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
			return;
		}

		// get the vertex type
		int vertexType = pVertexExport->GetVertexType();

		// handle the specific vertex type
		if(vertexType == RIGID_TYPE)
		{
			// typecast to rigid vertex
			IPhyRigidVertex *pTypeVertex = (IPhyRigidVertex *)pVertexExport;


			Influence infl;
			if( pTypeVertex->GetNode() )
			{
				strcpy( infl.szBoneName, pTypeVertex->GetNode()->GetName() );
				infl.fWeight = 1.0f;
				boneGroup.AddInfluence( infl );
			}
			else 
				return;
		}
		else if(vertexType == RIGID_BLENDED_TYPE)
		{
			// typecast to blended vertex
			IPhyBlendedRigidVertex *pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport;

			// loop through all influencing bones
			Influence infl;
			for(int nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++)
			{
				strcpy( infl.szBoneName, pTypeVertex->GetNode( nodeId )->GetName() );
				infl.fWeight = pTypeVertex->GetWeight( nodeId );

				boneGroup.AddInfluence( infl );
			}
		}

		// release all interfaces
		pPhysiqueExport->ReleaseContextInterface(pContextExport);
		pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);

	}
	else if( nModifierType == MODIFIER_SKIN)
	{
		assert( pModifier && "get bone group error, modifier is null" );
		// create a skin interface
		ISkin *pSkin = (ISkin*)pModifier->GetInterface(I_SKIN);
		if(pSkin == 0)
		{
			return;
		}

		// create a skin context data interface
		ISkinContextData *pSkinContextData;
		pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(pNode);
		if(pSkinContextData == NULL)
		{
			pModifier->ReleaseInterface(I_SKIN, pSkin);
			return;
		}

		// loop through all influencing bones
		for(int nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(nVertexId); nodeId++)
		{
			// get the bone id
			int boneId = pSkinContextData->GetAssignedBone(nVertexId, nodeId);
			if(boneId < 0)
				continue;

			INode* pBone = pSkin->GetBone( boneId );
			Influence infl;
			strcpy( infl.szBoneName, pBone->GetName() );
			infl.fWeight = pSkinContextData->GetBoneWeight(nVertexId, nodeId);

			boneGroup.AddInfluence( infl );
		}

		// release all interfaces
		pModifier->ReleaseInterface(I_SKIN, pSkin);
	}
}