Esempio n. 1
0
Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t)
{
	ObjectState os = node->EvalWorldState(t);

	bool local = !mFlattenHierarchy;

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

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

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

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

	Result result = Ok;

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

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

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

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

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

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

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

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

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

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

		}

		break;
	}

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

	if (copymesh)
		delete copymesh;

	return result;
}
Esempio n. 2
0
void RenderMesh::ConvertFaces(Mesh *Mesh, int MatIndex, Tab<Vert3> &Verts, Tab<Face3> &Faces, bool NegScale)
{
    Face3			TmpFace;
    Vert3			TmpVert;
	BitArray		Written;
	int				i,j,k,NumFace;
	int				NumUV,UVCount,Index;
	int				NumVert,Count,VIndex;
	Face			*aFace;
	Tab<BasisVert>	FNormals;
	Tab<VNormal>	Normals;
	UVVert			*UVVert;
	TVFace			*UVFace;
	Point3			S,T,SxT;
	unsigned long	Sg;

	bool useMeshNorms = false;


	if(NegScale)
	{
		gVIndex[0] = 2;
		gVIndex[1] = 1;
		gVIndex[2] = 0;
	}
	else
	{
		gVIndex[0] = 0;
		gVIndex[1] = 1;
		gVIndex[2] = 2;
	}

	// Do we have an EditNormal modifier present - if so we use those normals instead.
	// We only use this if they have been applied on a face with smoothing groups, otherwise
	// it messes up the tangent space calculation.  Probably not the most obtmized route, but it
	// works...

	MeshNormalSpec * meshNorm = Mesh->GetSpecifiedNormals();
	if(meshNorm && meshNorm->GetNumNormals())
		useMeshNorms = true;

	NumFace = 0;

	for(i=0; i < Mesh->getNumFaces(); i++) 
	{
		if(!Mesh->faces[i].Hidden())
		{
			Index = Mesh->getFaceMtlIndex(i) + 1;

			if(Index == MatIndex || MatIndex == 0)
			{
				NumFace++;
			}
		}

	}

	NumVert = Mesh->getNumVerts();
    Verts.SetCount(NumVert);

    Faces.SetCount(NumFace);

	if(NumVert == 0 || NumFace == 0)
	{
		return;
	}

	ComputeVertexNormals(Mesh,FNormals,Normals,NegScale);

    Written.SetSize(Mesh->getNumVerts());
    Written.ClearAll();

	NumUV = Mesh->getNumMaps();	

	if(NumUV)
	{	
		Count = 0;

		if(NumUV > MAX_TMUS + 1)
		{
			NumUV = MAX_TMUS + 1;
		}

		for(i=0; i < Mesh->getNumFaces(); i++) 
		{
			aFace = &Mesh->faces[i];

			TmpFace.m_Num[0] = aFace->v[gVIndex[0]];
			TmpFace.m_Num[1] = aFace->v[gVIndex[1]];
			TmpFace.m_Num[2] = aFace->v[gVIndex[2]];


			Sg = aFace->smGroup;

			for(j=0; j < 3; j++) 
			{
				VIndex			 = aFace->v[gVIndex[j]];
				TmpVert.m_Pos	 = Mesh->verts[VIndex];

				if(Sg)
				{
					if(useMeshNorms)
					{
						int normID = meshNorm->Face(i).GetNormalID(gVIndex[j]);
						TmpVert.m_Normal = meshNorm->Normal(normID).Normalize();
						Normals[VIndex].GetNormal(Sg,S,T,SxT);
					}
					else
					        TmpVert.m_Normal = Normals[VIndex].GetNormal(Sg,S,T,SxT);
					
					TmpVert.m_S		 = S;
					TmpVert.m_T		 = T;
					TmpVert.m_SxT	 = SxT;

				}
				else
				{
					TmpVert.m_Normal = FNormals[i].m_Normal;
					TmpVert.m_S		 = FNormals[i].m_S;
					TmpVert.m_T		 = FNormals[i].m_T;
					TmpVert.m_SxT	 = FNormals[i].m_SxT;
				}

				UVCount		 = 0;
				TmpVert.m_Sg = Sg;

				for(k=0;k<m_MapChannels.Count();k++)
				{	
					int index = m_MapChannels[k];

					if(Mesh->getNumMapVerts(index))
					{
						UVVert = Mesh->mapVerts(index);
						UVFace = Mesh->mapFaces(index);

						TmpVert.m_UV[k].x = UVVert[UVFace[i].t[gVIndex[j]]].x;
						TmpVert.m_UV[k].y = UVVert[UVFace[i].t[gVIndex[j]]].y;

	
					}
					else
					{
						TmpVert.m_UV[k].x = 0.0f;
						TmpVert.m_UV[k].y = 0.0f;
					}
				}
				
		
				if(Written[VIndex]) 
				{
					if((Sg == 0) || 
					   (Verts[VIndex].m_Sg != TmpVert.m_Sg) ||	
					   (!UVVertEqual(Verts[VIndex].m_UV[0],TmpVert.m_UV[0]))) 
					{
						TmpFace.m_Num[j] = Verts.Count();
						Verts.Append(1,&TmpVert,10);
					}
				} 
				else 
				{
					Verts[VIndex] = TmpVert;
					Written.Set(VIndex);
				}

			}

			if(!Mesh->faces[i].Hidden())
			{
				Index = Mesh->getFaceMtlIndex(i) + 1;

				if(Index == MatIndex || MatIndex == 0)
				{
					Faces[Count++] = TmpFace;
				}

			}

		}

	}
	else
	{
		for(i=0; i < Mesh->getNumFaces(); i++) 
		{
			aFace = &Mesh->faces[i];

			Faces[i].m_Num[0] = aFace->v[gVIndex[0]];
			Faces[i].m_Num[1] = aFace->v[gVIndex[1]];
			Faces[i].m_Num[2] = aFace->v[gVIndex[2]];

			for(j=0; j < 3; j++) 
			{
				VIndex					= aFace->v[gVIndex[j]];
				Verts[VIndex].m_Pos		= Mesh->verts[VIndex];
				Verts[VIndex].m_Normal	= Normals[VIndex].GetNormal(aFace->smGroup,S,T,SxT);
				Verts[VIndex].m_S		= Point3(0.0f,0.0f,0.0f);
				Verts[VIndex].m_T		= Point3(0.0f,0.0f,0.0f);
				Verts[VIndex].m_SxT		= Point3(0.0f,0.0f,0.0f);

				for(k=0; k < MAX_TMUS; k++)
				{
					Verts[VIndex].m_UV[k].x = 0.0f;
					Verts[VIndex].m_UV[k].y = 0.0f;
				}

			}

		}

	}
	Verts.Shrink();
	

}
Esempio n. 3
0
/*
*	Get vertex normal using smooth group with normal method.(using RVertex information)
*	FaceVertexIdx is between 0 and 2 local to a triangle
*/
Point3 SGP_MaxInterface::GetVertexNormal( Mesh* pMesh, int faceId, int vertexId, int FaceVertexIdx )
{
	//////////////////////////////////////////////////////////////////////////
	// Below is the way if someone has used "edit normals modifier" to change vertex normal
	MeshNormalSpec *pNormalSpec = pMesh->GetSpecifiedNormals();
	if( pNormalSpec )
	{
		const int NumFaces = pNormalSpec->GetNumFaces();
		const int NumNormals = pNormalSpec->GetNumNormals();

		if( NumFaces != 0 && NumNormals != 0 )
		{
			const int NormalID = pNormalSpec->Face(faceId).GetNormalID(FaceVertexIdx);
			return pNormalSpec->Normal(NormalID).Normalize();
		}
	}
	//////////////////////////////////////////////////////////////////////////

	RVertex *pRVertex;
	pRVertex = pMesh->getRVertPtr(vertexId);


	// get the face
	Face *pFace;
	pFace = &pMesh->faces[faceId];

	// get the smoothing group of the face
	DWORD smGroup;
	smGroup = pFace->smGroup;

	// get the number of normals
	int normalCount;
	normalCount = pRVertex->rFlags & NORCT_MASK;

	// check if the normal is specified ...
	if(pRVertex->rFlags & SPECIFIED_NORMAL)
	{
		return pRVertex->rn.getNormal();
	}
	// ... otherwise, check for a smoothing group
	else if((normalCount > 0) && (smGroup != 0))
	{
		// If there is only one vertex is found in the rn member.
		if(normalCount == 1)
		{
			return pRVertex->rn.getNormal();
		}
		else
		{
			int normalId;
			Point3 n(0,0,0);
			for(normalId = 0; normalId < normalCount; normalId++)
			{
				if(pRVertex->ern[normalId].getSmGroup() & smGroup)
				{
					n = n+pRVertex->ern[normalId].getNormal();
				}
			}
			n = n.Normalize();
			return n;
		}
	}

	// if all fails, return the face normal
	return pMesh->getFaceNormal(faceId);
}
Esempio n. 4
0
void SymmetryMod::ModifyTriObject (TimeValue t, ModContext &mc, TriObject *tobj, INode *inode) {
	Mesh &mesh = tobj->GetMesh();
	Interval iv = FOREVER;
	int axis, slice, weld, flip;
	float threshold;

	mp_pblock->GetValue (kSymAxis, t, axis, iv);
	mp_pblock->GetValue (kSymFlip, t, flip, iv);
	mp_pblock->GetValue (kSymSlice, t, slice, iv);
	mp_pblock->GetValue (kSymWeld, t, weld, iv);
	mp_pblock->GetValue (kSymThreshold, t, threshold, iv);
	if (threshold<0) threshold=0;

	// Get transform from mirror controller:
	Matrix3 tm  = CompMatrix (t, NULL, &mc, &iv);
	Matrix3 itm = Inverse (tm);

	// Get DotProd(N,x)=offset plane definition from transform
	Point3 Axis(0,0,0);
	Axis[axis] = flip ? -1.0f : 1.0f;
	Point3 origin = tm.GetTrans();
	Point3 N = Normalize(tm*Axis - origin);
	float offset = DotProd (N, origin);

	// Slice operation does not handle NormalSpecs, but it handles mapping channels.
	// move our mesh normal data to a map channel
	MeshNormalSpec *pNormals = mesh.GetSpecifiedNormals ();
	int normalMapChannel = INVALID_NORMALMAPCHANNEL;
	if (pNormals && pNormals->GetNumFaces())
	{
		pNormals->SetParent(&mesh);
		//find an empty map channel
		for (int mp = 0; mp < mesh.getNumMaps(); mp++) 
		{			
			if (!mesh.mapSupport(mp)) 
			{
				normalMapChannel = mp;

				mesh.setMapSupport(normalMapChannel,TRUE);
				MeshMap& map = mesh.Map(normalMapChannel);
				for (int i = 0; i < map.fnum; i++)
				{
					for (int j = 0; j < 3; j++)
					{
						unsigned int newID = pNormals->Face(i).GetNormalID(j);
						map.tf[i].t[j] = newID;
					}
				}
				map.setNumVerts(pNormals->GetNumNormals());
				for (int i = 0; i < map.vnum; i++)
				{
					map.tv[i] = pNormals->Normal(i);
				}				

				// make sure nothing is done with MeshNormalSpec (until data is copied back) 
				pNormals->Clear();
				break;
			}
		}
	}
	
	// Slice off everything below the plane.
	if (slice) SliceTriObject (mesh, N, offset);
	MirrorTriObject (mesh, axis, tm, itm,normalMapChannel);
	if (weld) WeldTriObject (mesh, N, offset, threshold);

	//now move the normals back
	if (pNormals && normalMapChannel != -1)
	{
		MeshMap& map = mesh.Map(normalMapChannel);
		pNormals->SetNumFaces(map.fnum);

		pNormals->SetNumNormals(map.vnum);
		pNormals->SetAllExplicit(true);
		BitArray temp;
		temp.SetSize(map.vnum);
		temp.SetAll();
		pNormals->SpecifyNormals(TRUE,&temp);

		for (int i = 0; i < map.vnum; i++)
		{
			pNormals->GetNormalArray()[i] = map.tv[i];
			pNormals->SetNormalExplicit(i,true);
		}	

		for (int i = 0; i < map.fnum; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				pNormals->SetNormalIndex(i,j,map.tf[i].t[j]);				
				MeshNormalFace& face = pNormals->Face(i);
				face.SpecifyAll(true);
			}
		}

		pNormals->SetFlag(MESH_NORMAL_MODIFIER_SUPPORT);

		for (int i = 0; i < pNormals->GetNumFaces(); i++)
		{
			for (int j = 0; j < 3; j++)
			{
				int id = pNormals->GetNormalIndex(i,j);	
			}
		}

		pNormals->CheckNormals();
		pNormals->SetParent(NULL);

		// Free the map channel
		mesh.setMapSupport(normalMapChannel,FALSE);
	}
	
	tobj->UpdateValidity (GEOM_CHAN_NUM, iv);
	tobj->UpdateValidity (TOPO_CHAN_NUM, iv);
	tobj->UpdateValidity (VERT_COLOR_CHAN_NUM, iv);
	tobj->UpdateValidity (TEXMAP_CHAN_NUM, iv);
	tobj->UpdateValidity (SELECT_CHAN_NUM, iv);
}
BOOL GetVertexNormalUsingSmoothGroup(Point3& VN, Mesh& mesh, int faceId, int globalvertexId, int _FaceVertexIdx)
{
    //_FaceVertexIdx is between 0 and 2 local to a triangle

    //THIS IS WHAT YOU NEED IF SOMEONE HAS USED THE EDIT NORMAL MODIFIER
    MeshNormalSpec * normalspec = mesh.GetSpecifiedNormals();
    if (normalspec)
    {
        const int NumFaces      = normalspec->GetNumFaces   ();
        const int NumNormals   = normalspec->GetNumNormals   ();

        if (NumFaces && NumNormals)
        {
            const int normID = normalspec->Face(faceId).GetNormalID(_FaceVertexIdx);
            VN = normalspec->Normal(normID).Normalize();
            return TRUE;
        }
    }

    // get the "rendered" vertex
    RVertex *pRVertex = mesh.getRVertPtr(globalvertexId);
    if(! pRVertex)return FALSE;

    // get the face
    const Face& Face = mesh.faces[faceId];

    // get the smoothing group of the face
    const DWORD smGroup = Face.smGroup;

    // get the number of normals
    const int normalCount = pRVertex->rFlags & NORCT_MASK;

    // check if the normal is specified ...
    if(pRVertex->rFlags & SPECIFIED_NORMAL)
    {
        VN = pRVertex->rn.getNormal();
        return TRUE;
    }
    // ... otherwise, check for a smoothing group
    else if((normalCount > 0) && (smGroup != 0))
    {
        // If there is only one vertex is found in the rn member.
        if(normalCount == 1)
        {
            VN = pRVertex->rn.getNormal();
            return TRUE;
        }
        else
        {
            for(int normalId = 0; normalId < normalCount; normalId++)
            {
                if(pRVertex->ern[normalId].getSmGroup() & smGroup)
                {
                    VN = pRVertex->ern[normalId].getNormal();
                    return TRUE;
                }
            }
        }
    }

    // if all failed, return the face normal
    VN = mesh.getFaceNormal(faceId);
    return TRUE;
}