Browse Source

Added a separate code path for converting frame group animations, and renamed some variables to use the correct frame/pose terminology

console
Nico de Poel 5 years ago
parent
commit
10e54f10ca
  1. 43
      Assets/Scripts/Modules/AliasModel.cs
  2. 2
      Assets/Scripts/Modules/RenderModule.cs

43
Assets/Scripts/Modules/AliasModel.cs

@ -81,11 +81,20 @@ public class AliasModel
ConvertUVs(stVertices, header.skinWidth, header.skinHeight, out var uvs); ConvertUVs(stVertices, header.skinWidth, header.skinHeight, out var uvs);
// Identify animation sequences and turn each one into a separate Mesh with a single blend shape animation // Identify animation sequences and turn each one into a separate Mesh with a single blend shape animation
if (frameType == QAliasFrameType.Single)
ImportSingleFrameAnimations(header, poseVertices, indices, uvs);
else
ImportGroupFrameAnimations(header, poseVertices, indices, uvs);
}
private void ImportSingleFrameAnimations(QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs)
{
Mesh mesh; Mesh mesh;
string animName = null; string animName = null;
int startFrame = 0; int startFrame = 0;
for (int frameIdx = 0; frameIdx < header.numFrames; ++frameIdx) for (int frameIdx = 0; frameIdx < header.numFrames; ++frameIdx)
{ {
// Individual sequences are identified by their prefix
string frameName = AnimationRegex.Match(header.frames[frameIdx].name).Value; string frameName = AnimationRegex.Match(header.frames[frameIdx].name).Value;
if (animName == null) if (animName == null)
{ {
@ -109,6 +118,18 @@ public class AliasModel
animationMeshes.Add((startFrame, mesh)); animationMeshes.Add((startFrame, mesh));
} }
private void ImportGroupFrameAnimations(QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs)
{
for (int frameIdx = 0; frameIdx < header.numFrames; ++frameIdx)
{
var frame = header.frames[frameIdx];
Mesh mesh = CreateAnimatedMesh(header, poseVertices, indices, uvs, $"{name}_{frameIdx}",
frame.firstPose, frame.firstPose + frame.numPoses);
animationMeshes.Add((frame.firstPose, mesh));
}
}
/// <summary> /// <summary>
/// Quake has a bit of a weird outdated mesh setup where skin textures are split into a front side and a back side. /// Quake has a bit of a weird outdated mesh setup where skin textures are split into a front side and a back side.
/// Vertices on the seam between the front and back are used by triangles on both sides, but require a correction /// Vertices on the seam between the front and back are used by triangles on both sides, but require a correction
@ -233,17 +254,17 @@ public class AliasModel
private static Mesh CreateAnimatedMesh( private static Mesh CreateAnimatedMesh(
QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs, QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs,
string animationName, int startFrame, int endFrame)
string animationName, int startPose, int endPose)
{ {
ConvertVertices(header, poseVertices[startFrame], out var baseVertices, out var baseNormals);
ConvertVertices(header, poseVertices[startPose], out var baseVertices, out var baseNormals);
var mesh = new Mesh { name = animationName }; var mesh = new Mesh { name = animationName };
mesh.SetVertices(baseVertices); mesh.SetVertices(baseVertices);
mesh.SetNormals(baseNormals); mesh.SetNormals(baseNormals);
if (endFrame - startFrame > 1)
if (endPose - startPose > 1)
{ {
CreateBlendShapes(mesh, animationName, baseVertices, baseNormals, header, poseVertices, startFrame, endFrame);
CreateBlendShapes(mesh, animationName, baseVertices, baseNormals, header, poseVertices, startPose, endPose);
} }
mesh.SetIndices(indices, MeshTopology.Triangles, 0, false); mesh.SetIndices(indices, MeshTopology.Triangles, 0, false);
@ -256,7 +277,7 @@ public class AliasModel
private static void CreateBlendShapes( private static void CreateBlendShapes(
Mesh mesh, string animName, Vector3[] baseVertices, Vector3[] baseNormals, Mesh mesh, string animName, Vector3[] baseVertices, Vector3[] baseNormals,
QAliasHeader header, QTriVertex[][] poseVertices, int startFrame, int endFrame)
QAliasHeader header, QTriVertex[][] poseVertices, int startPose, int endPose)
{ {
var deltaVertices = new Vector3[header.numVerts]; var deltaVertices = new Vector3[header.numVerts];
var deltaNormals = new Vector3[header.numVerts]; var deltaNormals = new Vector3[header.numVerts];
@ -264,13 +285,13 @@ public class AliasModel
Vector3 scale = header.scale.ToVector3(); Vector3 scale = header.scale.ToVector3();
Vector3 origin = header.scaleOrigin.ToVector3(); Vector3 origin = header.scaleOrigin.ToVector3();
int numFrames = endFrame - startFrame;
int numPoses = endPose - startPose;
// Repeat the first frame at the end, so we can smoothly animate the entire cycle and loop the animation without any breaks.
for (int index = 1; index <= numFrames; ++index)
// Repeat the first pose at the end, so we can smoothly animate the entire cycle and loop the animation without any breaks.
for (int index = 1; index <= numPoses; ++index)
{ {
int frameIdx = startFrame + index % numFrames;
var poseVerts = poseVertices[frameIdx];
int poseIdx = startPose + index % numPoses;
var poseVerts = poseVertices[poseIdx];
for (int vertIdx = 0; vertIdx < header.numVerts; ++vertIdx) for (int vertIdx = 0; vertIdx < header.numVerts; ++vertIdx)
{ {
@ -279,7 +300,7 @@ public class AliasModel
deltaNormals[vertIdx] = QLightNormals.Get(poseVerts[vertIdx].lightNormalIndex) - baseNormals[vertIdx]; deltaNormals[vertIdx] = QLightNormals.Get(poseVerts[vertIdx].lightNormalIndex) - baseNormals[vertIdx];
} }
mesh.AddBlendShapeFrame(animName, (float)index / numFrames, deltaVertices, deltaNormals, null);
mesh.AddBlendShapeFrame(animName, (float)index / numPoses, deltaVertices, deltaNormals, null);
} }
} }
} }

2
Assets/Scripts/Modules/RenderModule.cs

@ -48,7 +48,7 @@ public partial class RenderModule
aliasModel.Animate(0, out Mesh mesh, out float blendWeight); aliasModel.Animate(0, out Mesh mesh, out float blendWeight);
if (header.numFrames > 1)
if (header.numPoses > 1)
{ {
var mr = go.AddComponent<SkinnedMeshRenderer>(); var mr = go.AddComponent<SkinnedMeshRenderer>();
mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));

Loading…
Cancel
Save