Example #1
0
BOOL plDistributor::IConformCheck(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const
{
    Matrix3 OTM = IOTM(iRepNode);
    Mesh* mesh = cache[iRepNode].fMesh;

    Point3 dir = l2w.VectorTransform(Point3(0.f, 0.f, 1.f));
    dir = FNormalize(dir);

    const float kOneOverSqrt2 = 0.707107f;
    Point3 scalePt(kOneOverSqrt2, kOneOverSqrt2, 0.f);
    scalePt = l2w.VectorTransform(scalePt);
    float maxScaledDist = fMaxConform * scalePt.Length();

    Box3 bnd = mesh->getBoundingBox() * OTM;
    bnd = Box3(Point3(bnd.Min().x, bnd.Min().y, -bnd.Max().z), bnd.Max());
    bnd = bnd * l2w;
    Tab<int32_t> faces;
    IFindFaceSet(bnd, faces);

    int i;
    for( i = 0; i < mesh->getNumVerts(); i++ )
    {
        Point3 pt = mesh->getVert(i) * OTM;
        pt.z = 0;

        pt = pt * l2w;

        Point3 projPt;
        if( !IProjectVertex(pt, dir, maxScaledDist, faces, projPt) )
            return false;
    }
    return true;
}
Example #2
0
BOOL plDistributor::IConformAll(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const
{
    Matrix3 OTM = IOTM(iRepNode);
    Mesh* mesh = cache[iRepNode].fMesh;

    Point3 dir = l2w.VectorTransform(Point3(0.f, 0.f, 1.f));
    dir = FNormalize(dir);

    const float kOneOverSqrt2 = 0.707107f;
    Point3 scalePt(kOneOverSqrt2, kOneOverSqrt2, 0.f);
    scalePt = l2w.VectorTransform(scalePt);
    float maxScaledDist = fMaxConform * scalePt.Length();

    Box3 bnd = mesh->getBoundingBox() * OTM;
    bnd = Box3(Point3(bnd.Min().x, bnd.Min().y, -bnd.Max().z), bnd.Max());
    bnd = bnd * l2w;
    Tab<int32_t> faces;
    IFindFaceSet(bnd, faces);

    // l2w, iRepNode, cache, &iCache, maxScaledDist, dir
    iCache = cache.Count();
    cache.SetCount(iCache + 1);
    cache[iCache] = cache[iRepNode];
    cache[iCache].fMesh = new Mesh(*mesh);

    mesh = cache[iCache].fMesh;

    Matrix3 v2w = OTM * l2w;
    Matrix3 w2v = Inverse(v2w);

    BOOL retVal = true;
    int i;
    for( i = 0; i < mesh->getNumVerts(); i++ )
    {
        Point3 pt = mesh->getVert(i) * OTM;
        pt.z = 0;

        pt = pt * l2w;

        Point3 projPt;
        if( !IProjectVertex(pt, dir, maxScaledDist, faces, projPt) )
        {
            retVal = false;
            break;
        }

        Point3 del = w2v.VectorTransform(projPt - pt);
        mesh->getVert(i) += del;
    }
    if( !retVal )
    {
//      delete cache[iCache].fMesh;
        delete mesh;
        cache.SetCount(iCache);
        iCache = iRepNode;
    }
    return retVal;
}
Example #3
0
// Luna task 748T
void ConvertPathToFrenets (Spline3D *pSpline, Matrix3 & relativeTransform, Tab<Matrix3> & tFrenets,
						   int numSegs, bool align, float rotateAroundZ) {
	// Given a path, a sequence of points in 3-space, create transforms
	// for putting a cross-section around each of those points, loft-style.

	// bezShape is provided by user, tFrenets contains output, numSegs is one less than the number of transforms requested.

	// Strategy: The Z-axis is mapped along the path, and the X and Y axes 
	// are chosen in a well-defined manner to get an orthonormal basis.

	int i;

	if (numSegs < 1) return;
	tFrenets.SetCount (numSegs+1);

	int numIntervals = pSpline->Closed() ? numSegs+1 : numSegs;
	float denominator = float(numIntervals);
	Point3 xDir, yDir, zDir, location, tangent, axis;
	float position, sine, cosine, theta;
	Matrix3 rotation;

	// Find initial x,y directions:
	location = relativeTransform * pSpline->InterpCurve3D (0.0f);
	tangent = relativeTransform.VectorTransform (pSpline->TangentCurve3D (0.0f));
	Point3 lastTangent = tangent;

	Matrix3 inverseBasisOfSpline(1);
	if (align) {
		theBasisFinder.BasisFromZDir (tangent, xDir, yDir);
		if (rotateAroundZ) {
			Matrix3 rotator(1);
			rotator.SetRotate (AngAxis (tangent, rotateAroundZ));
			xDir = xDir * rotator;
			yDir = yDir * rotator;
		}
		Matrix3 basisOfSpline(1);
		basisOfSpline.SetRow (0, xDir);
		basisOfSpline.SetRow (1, yDir);
		basisOfSpline.SetRow (2, tangent);
		basisOfSpline.SetTrans (location);
		inverseBasisOfSpline = Inverse (basisOfSpline);
		lastTangent = Point3(0,0,1);
	} else {
		inverseBasisOfSpline.SetRow (3, -location);
	}

	// Make relative transform take the spline from its own object space to our object space,
	// and from there into the space defined by its origin and initial direction:
	relativeTransform = relativeTransform * inverseBasisOfSpline;
	// (Note left-to-right evaluation order: Given matrices A,B, point x, x(AB) = (xA)B

	// The first transform is necessarily the identity:
	tFrenets[0].IdentityMatrix ();

	// Set up xDir, yDir, zDir to match our first-point basis:
	xDir = Point3 (1,0,0);
	yDir = Point3 (0,1,0);
	zDir = Point3 (0,0,1);

	for (i=1; i<=numIntervals; i++) {
		position = float(i) / denominator;
		location = relativeTransform * pSpline->InterpCurve3D (position);
		tangent = relativeTransform.VectorTransform (pSpline->TangentCurve3D (position));

		// This is the procedure we follow at each step in the path: find the
		// orthonormal basis with the right orientation, then compose with
		// the translation putting the origin at the path-point.

		// As we proceed along the path, we apply minimal rotations to
		// our original basis to keep the Z-axis tangent to the curve.
		// The X and Y axes follow in a natural manner.

		// xDir, yDir, zDir still have their values from last time...
		// Create a rotation matrix which maps the last tangent onto the current tangent:
		axis = lastTangent ^ tangent;	// gives axis, scaled by sine of angle.
		sine = FLength(axis);	// positive - keeps angle value in (0,PI) range.
		cosine = DotProd (lastTangent, tangent);	// Gives cosine of angle.
		theta = atan2f (sine, cosine);
		rotation.SetRotate (AngAxis (Normalize(axis), theta));
		xDir = Normalize (rotation * xDir);
		yDir = Normalize (rotation * yDir);
		zDir = Normalize (rotation * zDir);
		lastTangent = tangent;

		if (i<=numSegs) {
			tFrenets[i].IdentityMatrix ();
			tFrenets[i].SetRow (0, xDir);
			tFrenets[i].SetRow (1, yDir);
			tFrenets[i].SetRow (2, zDir);
			tFrenets[i].SetTrans (location);
		}
	}

	/* following code not needed for now - treating all splines as open.
	if (!pSpline->Closed ()) return;

	// If we have a closed loop, our procedure may result in X,Y vectors
	// that are twisted severely between the first and last point.
	// Here we correct for that by pre-transforming each frenet transform
	// by a small rotation around the Z-axis.  (The last pass through the above
	// loop should give the final twist: the initial and final Z-axis directions
	// are the same, and the difference between the initial and final X-axis
	// directions is the total twist along the spline.)

	// Now we measure the difference between our original and final x-vectors:
	axis = originalXDir ^ xDir;
	sine = FLength (axis);
	cosine = DotProd (originalXDir, xDir);
	theta = atan2f (sine, cosine);
	for (i=1; i<=numSegs; i++) {
		rotation.SetRotate (AngAxis (Normalize(axis), -theta/denominator));
		tFrenets[i] = rotation * tFrenets[i];
	}
*/	
}
Example #4
0
	// Load blend shape poses
	bool BlendShape::loadPoses(ParamList &params, std::vector<vertex> &vertices,long numVertices,long offset,long targetIndex)
	{
		if (params.useSharedGeom)
		{
			assert(targetIndex == 0);
			m_target = T_MESH;
		}
		else
		{
			assert(offset == 0);
			poseGroup new_pg;
			m_target = T_SUBMESH;
			new_pg.targetIndex = targetIndex;
			m_poseGroups.insert(std::pair<int,poseGroup>(targetIndex,new_pg));
		}
		poseGroup& pg = m_poseGroups.find(targetIndex)->second;

		if(m_pGameNode && m_pMorphR3)
		{
            // Disable all skin Modifiers.
            std::vector<Modifier*> disabledSkinModifiers;
            IGameObject* pGameObject = m_pGameNode->GetIGameObject();
            if( pGameObject )
            {
                int numModifiers = pGameObject->GetNumModifiers();
                for( int i = 0; i < numModifiers; ++i )
                {
                    IGameModifier* pGameModifier = pGameObject->GetIGameModifier(i);
                    if( pGameModifier )
                    {
                        if( pGameModifier->IsSkin() )
                        {
                            Modifier* pModifier = pGameModifier->GetMaxModifier();
                            if( pModifier )
                            {
                                if( pModifier->IsEnabled() )
                                {
                                    disabledSkinModifiers.push_back(pModifier);
                                    pModifier->DisableMod();
                                }
                            }
                        }
                    }
                }
            }

			// Get the original mesh from the IGameNode.  Not using IGame here
			// since MorphR3 doesn't allow for it.  Also we don't know if our vertices
			// are in object or world space, so we'll just calculate diffs directly from 
			// the Max meshes and modify the coordinate system manually.  
			// Obtained method of getting mesh from 3D Studio Max SDK Training session by
			// David Lanier.
 			bool DeleteObjectWhenDone;
			const ObjectState& objectState = m_pGameNode->GetMaxNode()->EvalWorldState(GetCOREInterface()->GetTime());
			Object *origMeshObj = objectState.obj;
			if (!origMeshObj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
			{
				FxOgreMaxExporterLog( "Could not access original mesh for morph target comparison.");
				return false;
			}

			// Calculate the DiffTM matrix.  This is the difference between the INode's world transform
			// which is used to calculate the morph verticies, and the IGameNode's world transform, which is used
			// to calculate the Ogre mesh's verticies.
			Matrix3 DiffTM = m_pGameNode->GetObjectTM(GetCOREInterface()->GetTime()).ExtractMatrix3();

			// The below code is not well tested as FaceFX needs content in the native coordinates.
			// I've seen the direction of the morph movement flipped on some content when in Y-up mode 
			// which sets the coordinate system to IGAME_OGL.
			// I can't get this to work on all the morph examples I have however.
			IGameConversionManager* pConversionManager = GetConversionManager();
			if(IGameConversionManager::IGAME_OGL == pConversionManager->GetCoordSystem())
			{			
				Matrix3 conv = Matrix3(Point3(1,0,0), Point3(0,0,1), Point3(0,-1,0), Point3(0,0,0));
				DiffTM = DiffTM * conv;
			}

			TriObject *origMeshTriObj = (TriObject *) origMeshObj->ConvertToType(GetCOREInterface()->GetTime(), Class_ID(TRIOBJ_CLASS_ID, 0));
			if (origMeshObj != origMeshTriObj) DeleteObjectWhenDone = true;
			Mesh& origMesh = origMeshTriObj->GetMesh();
			const int NumVerts = origMesh.getNumVerts();
 

			for( int i = 0; i < m_pMorphR3->chanBank.size() && i < MR3_NUM_CHANNELS; ++i )
			{
				if( m_pMorphR3->chanBank[i].mActive )
				{
					morphChannel* pMorphChannel = &m_pMorphR3->chanBank[i];	
					if( pMorphChannel )
					{
						pMorphChannel->rebuildChannel();

						std::string posename = string_tools::string_cast<ogre_string_type>(pMorphChannel->mName.data());
						int numMorphVertices = pMorphChannel->mNumPoints;
						
						if( numMorphVertices != origMesh.getNumVerts() )
						{
							MessageBox(GetCOREInterface()->GetMAXHWnd(), _T("Morph targets have failed to export becuase the morph vertex count did not match the base mesh.  Collapse the modifier stack prior to export, as smoothing is not supported with morph target export."), _T("Morph Target Export Failed."), MB_OK);
							return false;
						}
						else
						{
							FxOgreMaxExporterLog( "Exporting Morph target: %s with %d vertices.\n", posename.c_str(), numMorphVertices);
							FxOgreMaxExporterLog( "Mesh has %d vertices.\n", numVertices);
							FxOgreMaxExporterLog( "%d total vertices.\n", vertices.size());
							assert(offset+numVertices <= vertices.size());
							// create a new pose
							pose p;
							p.poseTarget = m_target;
							p.index = targetIndex;
							p.blendShapeIndex = i;
							p.name = posename;
							p.pMChannel = pMorphChannel;

							size_t numPoints = pMorphChannel->mPoints.size();
							std::vector<Point3> vmPoints;
							vmPoints.reserve(numPoints);
							for( size_t k = 0; k < numPoints; ++k )
							{
								vmPoints.push_back(pMorphChannel->mPoints[k]);
							}

							Box3 morphBoundingBox;
							// calculate vertex offsets
							for (int k=0; k<numVertices; k++)
							{
								vertexOffset vo;
								assert ((offset+k)<vertices.size());

								vertex v = vertices[offset+k];
								assert(v.index < numMorphVertices);
								assert(v.index < origMesh.getNumVerts());

								Point3 meshVert = origMesh.getVert(v.index);
								Point3 morphVert = vmPoints[v.index];

								Point3 diff = morphVert - meshVert;

								// Transform our morph vertex movements by whatever
								// scaling/rotation is being done by IGame..
								Point3 ogreSpacediff = DiffTM.VectorTransform(diff);


								// Add this point to the bounding box
								morphBoundingBox += morphVert;

								vo.x = ogreSpacediff.x * params.lum;
								vo.y = ogreSpacediff.y * params.lum;
								vo.z = ogreSpacediff.z * params.lum;	

								vo.index = offset+k;
								if (fabs(vo.x) < PRECISION)
									vo.x = 0;
								if (fabs(vo.y) < PRECISION)
									vo.y = 0;
								if (fabs(vo.z) < PRECISION)
									vo.z = 0;
								if ((vo.x!=0) || (vo.y!=0) || (vo.z!=0))
									p.offsets.push_back(vo);
							}
							// add pose to pose list
							if (p.offsets.size() > 0)
							{
								pg.poses.push_back(p);
							}
							if (params.bsBB)
							{
								// update bounding boxes of loaded submeshes
								for (int j=0; j<params.loadedSubmeshes.size(); j++)
								{
									Point3 min = morphBoundingBox.Min() * params.lum;
									Point3 max = morphBoundingBox.Max() * params.lum;
									// Update coordinate system here.
									Point3 newMin, newMax;
									newMin.x = min.x;
									newMin.y = min.z;
									newMin.z = min.y;
									Box3 newBox(newMin, newMax);
									if (params.exportWorldCoords)
										newBox = newBox * m_pGameNode->GetWorldTM(GetCOREInterface()->GetTime()).ExtractMatrix3();
									params.loadedSubmeshes[j]->m_boundingBox += newBox;
								}
							}
						}

					}
				}
			}
            // Re-enable skin modifiers.
            for( int i = 0; i < disabledSkinModifiers.size(); ++i )
            {
                disabledSkinModifiers[i]->EnableMod();
            }
			// According to David Lanier, this should be deleted, but I get crashes when exporting blendShapes
			// without shared geometry when I use the object for the second time.  Perhaps it
			// can only be used/deleted once.  Even without shared geometry, I'll get a strange crash
			// a few seconds after successful export with this here.
//			if (DeleteObjectWhenDone)
//				origMeshTriObj->DeleteMe();
		}
		return true;
	}
Example #5
0
File: mesh.cpp Project: skopp/rush
//  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