Beispiel #1
0
// function is similar to part of CSkelMeshInstance::SetMesh()
static void BuildSkeleton(TArray<CCoords> &Coords, const TArray<RJoint> &Bones, const TArray<AnalogTrack> &Anim)
{
	guard(BuildSkeleton);

	int numBones = Anim.Num();
	Coords.Empty(numBones);
	Coords.AddZeroed(numBones);

	for (int i = 0; i < numBones; i++)
	{
		const AnalogTrack &A = Anim[i];
		const RJoint &B = Bones[i];
		CCoords &BC = Coords[i];
		// compute reference bone coords
		CVec3 BP;
		CQuat BO;
		// get default pose
		BP = CVT(A.KeyPos[0]);
		BO = CVT(A.KeyQuat[0]);
		if (!i) BO.Conjugate();

		BC.origin = BP;
		BO.ToAxis(BC.axis);
		// move bone position to global coordinate space
		if (i)	// do not rotate root bone
		{
			assert(B.parent >= 0);
			Coords[B.parent].UnTransformCoords(BC, BC);
		}
	}

	unguard;
}
Beispiel #2
0
// function is similar to part of CSkelMeshInstance::SetMesh() and Rune mesh loader
static void BuildSkeleton(TArray<CCoords> &Coords, const TArray<CSkelMeshBone> &Bones)
{
	guard(BuildSkeleton);

	int numBones = Bones.Num();
	Coords.Empty(numBones);
	Coords.AddZeroed(numBones);

	for (int i = 0; i < numBones; i++)
	{
		const CSkelMeshBone &B = Bones[i];
		CCoords &BC = Coords[i];
		// compute reference bone coords
		CVec3 BP;
		CQuat BO;
		// get default pose
		BP = B.Position;
		BO = B.Orientation;
#if MIRROR_MESH
		BP[1] *= -1;							// y
		BO.y  *= -1;
		BO.w  *= -1;
#endif
		if (!i) BO.Conjugate();					// root bone

		BC.origin = BP;
		BO.ToAxis(BC.axis);
		// move bone position to global coordinate space
		if (i)	// do not rotate root bone
		{
			assert(B.ParentIndex < i);
			Coords[B.ParentIndex].UnTransformCoords(BC, BC);
		}
#if 0
	//!!
if (i == 32)
{
	appNotify("Bone %d (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f %8.3f)", i, VECTOR_ARG(BP), QUAT_ARG(BO));
#define C BC
	appNotify("REF   : o=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.origin ));
	appNotify("        0=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[0]));
	appNotify("        1=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[1]));
	appNotify("        2=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[2]));
#undef C
}
#endif
	}

	unguard;
}
Beispiel #3
0
void ExportMd5Mesh(const CSkeletalMesh *Mesh)
{
	guard(ExportMd5Mesh);

	int i;

	UObject *OriginalMesh = Mesh->OriginalMesh;
	if (!Mesh->Lods.Num())
	{
		appNotify("Mesh %s has 0 lods", OriginalMesh->Name);
		return;
	}

	FArchive *Ar = CreateExportArchive(OriginalMesh, "%s.md5mesh", OriginalMesh->Name);
	if (!Ar) return;

	const CSkelMeshLod &Lod = Mesh->Lods[0];

	Ar->Printf(
		"MD5Version 10\n"
		"commandline \"Created with UE Viewer\"\n"
		"\n"
		"numJoints %d\n"
		"numMeshes %d\n"
		"\n",
		Mesh->RefSkeleton.Num(),
		Lod.Sections.Num()
	);

	// compute skeleton
	TArray<CCoords> BoneCoords;
	BuildSkeleton(BoneCoords, Mesh->RefSkeleton);

	// write joints
	Ar->Printf("joints {\n");
	for (i = 0; i < Mesh->RefSkeleton.Num(); i++)
	{
		const CSkelMeshBone &B = Mesh->RefSkeleton[i];

		const CCoords &BC = BoneCoords[i];
		CVec3 BP;
		CQuat BO;
		BP = BC.origin;
		BO.FromAxis(BC.axis);
		if (BO.w < 0) BO.Negate();				// W-component of quaternion will be removed ...

		Ar->Printf(
			"\t\"%s\"\t%d ( %f %f %f ) ( %.10f %.10f %.10f )\n",
			*B.Name, (i == 0) ? -1 : B.ParentIndex,
			VECTOR_ARG(BP),
			BO.x, BO.y, BO.z
		);
#if 0
	//!!
if (i == 32 || i == 34)
{
	CCoords BC;
	BC.origin = BP;
	BO.ToAxis(BC.axis);
	appNotify("Bone %d (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f %8.3f)", i, VECTOR_ARG(BP), QUAT_ARG(BO));
#define C BC
	appNotify("INV   : o=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.origin ));
	appNotify("        0=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[0]));
	appNotify("        1=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[1]));
	appNotify("        2=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[2]));
#undef C
//	BO.Negate();
	BO.w *= -1;
	BO.ToAxis(BC.axis);
#define C BC
	appNotify("INV2  : o=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.origin ));
	appNotify("        0=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[0]));
	appNotify("        1=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[1]));
	appNotify("        2=%8.3f %8.3f %8.3f",    VECTOR_ARG(C.axis[2]));
#undef C
}
#endif
	}
	Ar->Printf("}\n\n");

	// collect weights information
	TArray<VertInfluences> Weights;				// Point -> Influences
	Weights.AddZeroed(Lod.NumVerts);
	for (i = 0; i < Lod.NumVerts; i++)
	{
		const CSkelMeshVertex &V = Lod.Verts[i];
		CVec4 UnpackedWeights;
		V.UnpackWeights(UnpackedWeights);
		for (int j = 0; j < NUM_INFLUENCES; j++)
		{
			if (V.Bone[j] < 0) break;
			VertInfluence *I = new (Weights[i].Inf) VertInfluence;
			I->Bone   = V.Bone[j];
			I->Weight = UnpackedWeights[j];
		}
	}

	CIndexBuffer::IndexAccessor_t Index = Lod.Indices.GetAccessor();

	// write meshes
	// we are using some terms here:
	// - "mesh vertex" is a vertex in Lod.Verts[] array, global for whole mesh
	// - "surcace vertex" is a vertex from the mesh stripped to only one (current) section
	for (int m = 0; m < Lod.Sections.Num(); m++)
	{
		const CMeshSection &Sec = Lod.Sections[m];

		TArray<int>  MeshVerts;					// surface vertex -> mesh vertex
		TArray<int>  BackWedge;					// mesh vertex -> surface vertex
		TArray<bool> UsedVerts;					// mesh vertex -> surface: used of not
		TArray<int>  MeshWeights;				// mesh vertex -> weight index
		MeshVerts.Empty(Lod.NumVerts);
		UsedVerts.AddZeroed(Lod.NumVerts);
		BackWedge.AddZeroed(Lod.NumVerts);
		MeshWeights.AddZeroed(Lod.NumVerts);

		// find verts and triangles for current material
		for (i = 0; i < Sec.NumFaces * 3; i++)
		{
			int idx = Index(i + Sec.FirstIndex);

			if (UsedVerts[idx]) continue;		// vertex is already used in previous triangle
			UsedVerts[idx] = true;
			int locWedge = MeshVerts.Add(idx);
			BackWedge[idx] = locWedge;
		}

		// find influences
		int WeightIndex = 0;
		for (i = 0; i < Lod.NumVerts; i++)
		{
			if (!UsedVerts[i]) continue;
			MeshWeights[i] = WeightIndex;
			WeightIndex += Weights[i].Inf.Num();
		}

		// mesh header
		const UUnrealMaterial *Tex = Sec.Material;
		if (Tex)
		{
			Ar->Printf(
				"mesh {\n"
				"\tshader \"%s\"\n\n",
				Tex->Name
			);
			ExportObject(Tex);
		}
		else
		{
			Ar->Printf(
				"mesh {\n"
				"\tshader \"material_%d\"\n\n",
				m
			);
		}
		// verts
		Ar->Printf("\tnumverts %d\n", MeshVerts.Num());
		for (i = 0; i < MeshVerts.Num(); i++)
		{
			int iPoint = MeshVerts[i];
			const CSkelMeshVertex &V = Lod.Verts[iPoint];
			Ar->Printf("\tvert %d ( %f %f ) %d %d\n",
				i, V.UV.U, V.UV.V, MeshWeights[iPoint], Weights[iPoint].Inf.Num());
		}
		// triangles
		Ar->Printf("\n\tnumtris %d\n", Sec.NumFaces);
		for (i = 0; i < Sec.NumFaces; i++)
		{
			Ar->Printf("\ttri %d", i);
#if MIRROR_MESH
			for (int j = 2; j >= 0; j--)
#else
			for (int j = 0; j < 3; j++)
#endif
				Ar->Printf(" %d", BackWedge[Index(Sec.FirstIndex + i * 3 + j)]);
			Ar->Printf("\n");
		}
		// weights
		Ar->Printf("\n\tnumweights %d\n", WeightIndex);
		int saveWeightIndex = WeightIndex;
		WeightIndex = 0;
		for (i = 0; i < Lod.NumVerts; i++)
		{
			if (!UsedVerts[i]) continue;
			for (int j = 0; j < Weights[i].Inf.Num(); j++)
			{
				const VertInfluence &I = Weights[i].Inf[j];
				CVec3 v;
				v = Lod.Verts[i].Position;
#if MIRROR_MESH
				v[1] *= -1;						// y
#endif
				BoneCoords[I.Bone].TransformPoint(v, v);
				Ar->Printf(
					"\tweight %d %d %f ( %f %f %f )\n",
					WeightIndex, I.Bone, I.Weight, VECTOR_ARG(v)
				);
				WeightIndex++;
			}
		}
		assert(saveWeightIndex == WeightIndex);

		// mesh footer
		Ar->Printf("}\n");
	}

	delete Ar;

	unguard;
}
Beispiel #4
0
static void ExportSkinData(ExportContext& Context, const CSkelMeshLod& Lod, FArchive& Ar)
{
	guard(ExportSkinData);

	int numBones = Context.SkelMesh->RefSkeleton.Num();

	int MatrixBufIndex = Context.Data.AddZeroed();
	BufferData& MatrixBuf = Context.Data[MatrixBufIndex];
	MatrixBuf.Setup(numBones, "MAT4", BufferData::FLOAT, sizeof(CMat4));

	Ar.Printf(
		"  \"nodes\" : [\n"
		"    {\n"
		"      \"name\" : \"%s\",\n"
		"      \"mesh\" : 0,\n"
		"      \"skin\" : 0,\n"
		"      \"children\" : [ 1 ]\n"
		"    },\n",
		Context.MeshName);

	TArray<CCoords> BoneCoords;
	BoneCoords.AddZeroed(numBones);

	for (int boneIndex = 0; boneIndex < numBones; boneIndex++)
	{
		const CSkelMeshBone& B = Context.SkelMesh->RefSkeleton[boneIndex];

		// Find all children
		TStaticArray<int, 32> children;
		for (int j = 0; j < numBones; j++)
		{
			if (boneIndex == j) continue;
			const CSkelMeshBone& B2 = Context.SkelMesh->RefSkeleton[j];
			if (B2.ParentIndex == boneIndex)
			{
				children.Add(j);
			}
		}

		Ar.Printf(
			"    {\n"
			"      \"name\" : \"%s\",\n",
			*B.Name
		);

		// Write children
		if (children.Num())
		{
			Ar.Printf("      \"children\" : [ %d", children[0]+FIRST_BONE_NODE);
			for (int j = 1; j < children.Num(); j++)
			{
				Ar.Printf(", %d", children[j]+FIRST_BONE_NODE);
			}
			Ar.Printf(" ],\n");
		}

		// Bone transform
		CVec3 bonePos = B.Position;
		CQuat boneRot = B.Orientation;
		if (boneIndex == 0)
		{
			boneRot.Conjugate();
		}

		TransformPosition(bonePos);
		TransformRotation(boneRot);

		Ar.Printf(
			"      \"translation\" : [ %g, %g, %g ],\n"
			"      \"rotation\" : [ %g, %g, %g, %g ]\n",
			bonePos[0], bonePos[1], bonePos[2],
			boneRot.x, boneRot.y, boneRot.z, boneRot.w
		);

		boneRot.w *= -1;

		CCoords& BC = BoneCoords[boneIndex];
		BC.origin = bonePos;
		boneRot.ToAxis(BC.axis);
		if (boneIndex)
		{
			// World coordinate
			BoneCoords[B.ParentIndex].UnTransformCoords(BC, BC);
		}
		CCoords InvCoords;
		InvertCoords(BC, InvCoords);

		CMat4 BC4x4(InvCoords);
		MatrixBuf.Put(BC4x4);

		// Closing brace
		Ar.Printf(
			"    }%s\n",
			boneIndex == (numBones-1) ? "" : ","
		);
	}

	// Close "nodes" array
	Ar.Printf("  ],\n");

	// Make "skins"
	Ar.Printf(
		"  \"skins\" : [\n"
		"    {\n"
		"      \"inverseBindMatrices\" : %d,\n"
		"      \"skeleton\" : 1,\n"
		"      \"joints\" : [",
		MatrixBufIndex
	);
	for (int i = 0; i < numBones; i++)
	{
		if ((i & 31) == 0) Ar.Printf("\n        ");
		Ar.Printf("%d%s", i+FIRST_BONE_NODE, (i == numBones-1) ? "" : ",");
	}
	Ar.Printf(
		"\n"
		"      ]\n"
		"    }\n"
		"  ],\n"
	);

	unguard;
}