diff --git a/Assets/Scripts/Game/Entity.cs b/Assets/Scripts/Game/Entity.cs index 169239f..40e5201 100644 --- a/Assets/Scripts/Game/Entity.cs +++ b/Assets/Scripts/Game/Entity.cs @@ -6,7 +6,10 @@ public class Entity private readonly int entityNum; private GameObject gameObject; - private SkinnedMeshRenderer meshRenderer; + + private MeshFilter meshFilter; + private MeshRenderer meshRenderer; + private SkinnedMeshRenderer skinnedMeshRenderer; private AliasModel aliasModel; private GameObject worldModel; @@ -20,14 +23,6 @@ public class Entity private void CreateGameObject() { gameObject = new GameObject($"Entity_{entityNum}"); - - // DEBUG - we'll want to instantiate a prefab and assign materials from a preset collection - meshRenderer = gameObject.AddComponent(); - meshRenderer.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); - meshRenderer.shadowCastingMode = ShadowCastingMode.Off; - meshRenderer.receiveShadows = false; - meshRenderer.lightProbeUsage = LightProbeUsage.Off; - meshRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; } public void Destroy() @@ -38,12 +33,20 @@ public class Entity public void ClearModel() { aliasModel = null; - meshRenderer.sharedMesh = null; + + Object.Destroy(meshFilter); + Object.Destroy(meshRenderer); + Object.Destroy(skinnedMeshRenderer); + + // TODO: not sure if this is the right way to unlink world sub-models + gameObject.transform.DetachChildren(); } public void SetAliasModel(AliasModel model) { + ClearModel(); aliasModel = model; + AssignMeshRenderer(); // Set a default pose based on the first animation frame UpdateAnimation(0); @@ -51,6 +54,7 @@ public class Entity public void SetWorldModel(GameObject worldModelGO) { + ClearModel(); worldModel = worldModelGO; worldModel.transform.SetParent(gameObject.transform); } @@ -60,10 +64,17 @@ public class Entity if (aliasModel != null) { aliasModel.Animate(frameNum, out Mesh mesh, out float blendWeight); - meshRenderer.sharedMesh = mesh; - - if (mesh != null && mesh.blendShapeCount > 0) - meshRenderer.SetBlendShapeWeight(0, blendWeight); + + if (skinnedMeshRenderer != null) + { + skinnedMeshRenderer.sharedMesh = mesh; + if (mesh != null && mesh.blendShapeCount > 0) + skinnedMeshRenderer.SetBlendShapeWeight(0, blendWeight); + } + else if (meshFilter != null) + { + meshFilter.sharedMesh = mesh; + } } if (worldModel != null) @@ -77,4 +88,30 @@ public class Entity gameObject.transform.position = position; gameObject.transform.rotation = rotation; } + + private void AssignMeshRenderer() + { + // DEBUG - we'll want to instantiate a prefab and assign materials from a preset collection + var material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); + if (aliasModel.IsAnimated) + { + skinnedMeshRenderer = gameObject.AddComponent(); + skinnedMeshRenderer.material = material; + skinnedMeshRenderer.shadowCastingMode = ShadowCastingMode.Off; + skinnedMeshRenderer.receiveShadows = false; + skinnedMeshRenderer.lightProbeUsage = LightProbeUsage.Off; + skinnedMeshRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; + } + else + { + meshFilter = gameObject.AddComponent(); + meshRenderer = gameObject.AddComponent(); + meshRenderer.material = material; + + meshRenderer.shadowCastingMode = ShadowCastingMode.Off; + meshRenderer.receiveShadows = false; + meshRenderer.lightProbeUsage = LightProbeUsage.Off; + meshRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; + } + } } diff --git a/Assets/Scripts/Modules/GameModule.cs b/Assets/Scripts/Modules/GameModule.cs index e042f3e..64ba3ea 100644 --- a/Assets/Scripts/Modules/GameModule.cs +++ b/Assets/Scripts/Modules/GameModule.cs @@ -24,7 +24,7 @@ public partial class GameModule { if (!int.TryParse(modelName.Substring(1), out int subModelNum)) { - Debug.LogWarning($"Invalid world submodel index: {modelName}"); + Debug.LogWarning($"Invalid world sub-model index: {modelName}"); return; } diff --git a/Assets/Scripts/Modules/RenderModule.cs b/Assets/Scripts/Modules/RenderModule.cs index 62598cb..fb3698c 100644 --- a/Assets/Scripts/Modules/RenderModule.cs +++ b/Assets/Scripts/Modules/RenderModule.cs @@ -31,8 +31,8 @@ public partial class RenderModule Debug.Log($"Alias model '{name}' (frame type {frameType}) with {header.numVerts} vertices, {header.numTriangles} triangles, {header.numFrames} frame(s), {header.numPoses} pose(s):\n{sb}"); - AliasModel aliasModel = new AliasModel(name, frameType); - aliasModel.ImportMeshData(header, poseVertices, triangles, stVertices); + AliasModel aliasModel = new AliasModel(name, header, frameType); + aliasModel.ImportMeshData(poseVertices, triangles, stVertices); uq.GameAssets.AddAliasModel(aliasModel); diff --git a/Assets/Scripts/Support/AliasModel.cs b/Assets/Scripts/Support/AliasModel.cs index 23b7a97..6a7ea02 100644 --- a/Assets/Scripts/Support/AliasModel.cs +++ b/Assets/Scripts/Support/AliasModel.cs @@ -8,14 +8,17 @@ public class AliasModel private static readonly Regex AnimationRegex = new Regex(@"^[a-zA-Z]+"); private readonly string name; + private readonly QAliasHeader header; private readonly QAliasFrameType frameType; private readonly List<(int, Mesh)> animationMeshes = new List<(int, Mesh)>(); public string Name => name; + public bool IsAnimated => header.numPoses > 1; - public AliasModel(string name, QAliasFrameType frameType) + public AliasModel(string name, QAliasHeader header, QAliasFrameType frameType) { this.name = name; + this.header = header; this.frameType = frameType; } @@ -72,7 +75,7 @@ public class AliasModel animationMeshes.Clear(); } - public void ImportMeshData(QAliasHeader header, QTriVertex[][] poseVertices, QTriangle[] triangles, QSTVert[] stVertices) + public void ImportMeshData(QTriVertex[][] poseVertices, QTriangle[] triangles, QSTVert[] stVertices) { // Massage the input data for easier conversion PreprocessMeshData(header, triangles, ref poseVertices, ref stVertices); @@ -83,12 +86,12 @@ public class AliasModel // 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); + ImportSingleFrameAnimations(poseVertices, indices, uvs); else - ImportGroupFrameAnimations(header, poseVertices, indices, uvs); + ImportGroupFrameAnimations(poseVertices, indices, uvs); } - private void ImportSingleFrameAnimations(QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs) + private void ImportSingleFrameAnimations(QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs) { Mesh mesh; string animName = null; @@ -119,7 +122,7 @@ public class AliasModel animationMeshes.Add((startFrame, mesh)); } - private void ImportGroupFrameAnimations(QAliasHeader header, QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs) + private void ImportGroupFrameAnimations(QTriVertex[][] poseVertices, ushort[] indices, Vector2[] uvs) { for (int frameIdx = 0; frameIdx < header.numFrames; ++frameIdx) {