Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial implementation of zCVobAnimate #329

Merged
merged 8 commits into from
Mar 30, 2024
60 changes: 60 additions & 0 deletions Assets/GothicVR/Resources/Prefabs/Vobs/zCVobAnimate.prefab
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6503575194566409312
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2022050282646122291}
- component: {fileID: 5252305678164495226}
- component: {fileID: 8916690276963802196}
m_Layer: 0
m_Name: zCVobAnimate
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2022050282646122291
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6503575194566409312}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5252305678164495226
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6503575194566409312}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 024fa582612e45c0afcf4ba9d756341e, type: 3}
m_Name:
m_EditorClassIdentifier:
<visualScheme>k__BackingField:
--- !u!114 &8916690276963802196
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6503575194566409312}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 26c624505e9a4bf3a7b7e2fa4a9bd981, type: 3}
m_Name:
m_EditorClassIdentifier:

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion Assets/GothicVR/Scripts/Caches/AssetCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,15 @@ public static IMorphMesh TryGetMmb(string key)
if (MmbCache.TryGetValue(preparedKey, out var data))
return data;

var newData = new MorphMesh(GameData.Vfs, $"{preparedKey}.mmb").Cache();
IMorphMesh newData = null;
try
JaXt0r marked this conversation as resolved.
Show resolved Hide resolved
{
newData = new MorphMesh(GameData.Vfs, $"{preparedKey}.mmb").Cache();
}
catch (Exception)
{
// ignored
}
MmbCache[preparedKey] = newData;

return newData;
Expand Down
30 changes: 17 additions & 13 deletions Assets/GothicVR/Scripts/Caches/MorphMeshCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class MorphMeshCache
/// | Array index is former vertexId
/// | Data is new vertexIds from Unity mesh
/// </summary>
private static readonly Dictionary<string, List<List<int>>> HeadVertexMapping = new();
private static readonly Dictionary<string, List<List<int>>> VertexMapping = new();

/// <summary>
/// We also store the vertices migrated from ZenKit to Unity. They basically differentiate by:
Expand All @@ -39,36 +39,40 @@ public static class MorphMeshCache
/// [0] - is frame ID of the Morph Animation
/// {{x,y,z}, {x,y,z}} - are the morph values of every vertex
/// </summary>
private static readonly Dictionary<string, List<Vector3[]>> HeadAnimationMorphs = new();
private static readonly Dictionary<string, List<Vector3[]>> AnimationMorphs = new();


public static bool IsMappingAlreadyCached(string morphMeshName)
{
var preparedKey = GetPreparedKey(morphMeshName);

return HeadVertexMapping.ContainsKey(preparedKey);
return VertexMapping.ContainsKey(preparedKey);
}

public static void AddVertexMapping(string morphMeshName, int arraySize)
{
var preparedKey = GetPreparedKey(morphMeshName);

HeadVertexMapping.Add(preparedKey, new(arraySize));
VertexMapping.Add(preparedKey, new(arraySize));

// Initialize
Enumerable.Range(0, arraySize)
.ToList()
.ForEach(_ => HeadVertexMapping[preparedKey].Add(new List<int>()));
.ForEach(_ => VertexMapping[preparedKey].Add(new List<int>()));
}

public static void AddVertexMappingEntry(string preparedMorphMeshName, int originalVertexIndex, int additionalUnityVertexIndex)
{
HeadVertexMapping[preparedMorphMeshName][originalVertexIndex].Add(additionalUnityVertexIndex);
var preparedKey = GetPreparedKey(preparedMorphMeshName);

VertexMapping[preparedKey][originalVertexIndex].Add(additionalUnityVertexIndex);
}

public static void SetUnityVerticesForVertexMapping(string preparedMorphMeshName, Vector3[] unityVertices)
{
UnityVertices.Add(preparedMorphMeshName, unityVertices);
var preparedKey = GetPreparedKey(preparedMorphMeshName);

UnityVertices.Add(preparedKey, unityVertices);
}

public static Vector3[] GetOriginalUnityVertices(string morphMeshName)
Expand All @@ -85,20 +89,20 @@ public static Vector3[] GetOriginalUnityVertices(string morphMeshName)
/// | Key is frameId
/// | Data is the already processed morph data (morph addition to original triangle data)
/// </summary>
public static List<Vector3[]> TryGetHeadMorphData(string mmbName, string animationName)
public static List<Vector3[]> TryGetMorphData(string mmbName, string animationName)
{
var preparedMmbKey = GetPreparedKey(mmbName);
var preparedAnimKey = GetPreparedKey(animationName);
var preparedKey = $"{preparedMmbKey}-{preparedAnimKey}";

if (HeadAnimationMorphs.TryGetValue(preparedKey, out var data))
if (AnimationMorphs.TryGetValue(preparedKey, out var data))
return data;

// Create logic
var mmb = AssetCache.TryGetMmb(mmbName);
var anim = mmb.Animations.First(anim => anim.Name.EqualsIgnoreCase(animationName));

var originalVertexMapping = HeadVertexMapping[preparedMmbKey];
var originalVertexMapping = VertexMapping[preparedMmbKey];
var originalUnityVertexData = UnityVertices[preparedMmbKey];
// Original vertex count from ZenKit data.
var vertexCount = anim.Vertices.Count;
Expand All @@ -124,7 +128,7 @@ public static List<Vector3[]> TryGetHeadMorphData(string mmbName, string animati
}
}

HeadAnimationMorphs[preparedKey] = newData;
AnimationMorphs[preparedKey] = newData;

return newData;
}
Expand All @@ -142,9 +146,9 @@ public static string GetPreparedKey(string key)

public static void Dispose()
{
HeadVertexMapping.Clear();
VertexMapping.Clear();
UnityVertices.Clear();
HeadAnimationMorphs.Clear();
AnimationMorphs.Clear();
}
}
}
2 changes: 2 additions & 0 deletions Assets/GothicVR/Scripts/Caches/PrefabCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum PrefabType
Npc,
WayPoint,
Vob,
VobAnimate,
VobItem,
VobContainer,
VobDoor,
Expand All @@ -34,6 +35,7 @@ private static string GetPath(PrefabType type)
PrefabType.Npc => "Prefabs/Npc",
PrefabType.WayPoint => "Prefabs/WayPoint",
PrefabType.Vob => "Prefabs/Vobs/Vob",
PrefabType.VobAnimate => "Prefabs/Vobs/zCVobAnimate",
PrefabType.VobItem => "Prefabs/Vobs/oCItem",
PrefabType.VobContainer => "Prefabs/Vobs/oCMobContainer",
PrefabType.VobDoor => "Prefabs/Vobs/oCMobDoor",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public abstract class AbstractMeshBuilder

protected Vector3 RootPosition;
protected Quaternion RootRotation;

protected bool isMorphMeshMappingAlreadyCached;


public abstract GameObject Build();
Expand Down Expand Up @@ -102,6 +104,11 @@ public void SetMrm(IMultiResolutionMesh mrm)
this.Mrm = mrm;
}

public void SetMmb(IMorphMesh mmb)
{
this.Mmb = mmb;
}

public void SetMrm(string mrmName)
{
Mrm = AssetCache.TryGetMrm(mrmName);
Expand Down Expand Up @@ -268,6 +275,19 @@ protected GameObject BuildViaMdmAndMdh()
return RootGo;
}

protected GameObject BuildViaMmb()
{
var meshFilter = RootGo.AddComponent<MeshFilter>();
var meshRenderer = RootGo.AddComponent<MeshRenderer>();

PrepareMeshFilter(meshFilter, Mmb.Mesh, meshRenderer);
PrepareMeshRenderer(meshRenderer, Mmb.Mesh);

SetPosAndRot(RootGo, RootPosition, RootRotation);

return RootGo;
}

protected void PrepareMeshRenderer(Renderer rend, IMultiResolutionMesh mrmData)
{
if (null == mrmData)
Expand Down Expand Up @@ -317,7 +337,7 @@ protected void PrepareMeshRenderer(Renderer rend, IMultiResolutionMesh mrmData)
rend.SetMaterials(finalMaterials);
}

protected void PrepareMeshFilter(MeshFilter meshFilter, IMultiResolutionMesh mrmData, MeshRenderer meshRenderer, bool isMorphMesh = false, string morphMeshName = "")
protected void PrepareMeshFilter(MeshFilter meshFilter, IMultiResolutionMesh mrmData, MeshRenderer meshRenderer)
{
Mesh mesh = new Mesh();
meshFilter.mesh = mesh;
Expand Down Expand Up @@ -558,19 +578,44 @@ protected void PrepareMeshCollider(GameObject obj, Mesh mesh, List<IMaterial> ma
}
}

protected virtual void CreateMorphMeshBegin(IMultiResolutionMesh mrm, Mesh mesh)
private void CreateMorphMeshBegin(IMultiResolutionMesh mrm, Mesh mesh)
{
// NOP
if (Mmb == null)
{
return;
}

// MorphMeshes will change the vertices. This call optimizes performance.
mesh.MarkDynamic();

isMorphMeshMappingAlreadyCached = MorphMeshCache.IsMappingAlreadyCached(Mmb.Name);
if (isMorphMeshMappingAlreadyCached)
{
return;
}

MorphMeshCache.AddVertexMapping(Mmb.Name, mrm.PositionCount);
}

protected virtual void CreateMorphMeshEntry(int index1, int preparedVerticesCount)
private void CreateMorphMeshEntry(int index1, int preparedVerticesCount)
{
// NOP
// We add mapping data to later reuse for IMorphAnimation samples
if (Mmb == null || isMorphMeshMappingAlreadyCached)
{
return;
}

MorphMeshCache.AddVertexMappingEntry(Mmb.Name, index1, preparedVerticesCount - 1);
}

protected virtual void CreateMorphMeshEnd(List<Vector3> preparedVertices)
private void CreateMorphMeshEnd(List<Vector3> preparedVertices)
{
// NOP
if (Mmb == null || isMorphMeshMappingAlreadyCached)
{
return;
}

MorphMeshCache.SetUnityVerticesForVertexMapping(Mmb.Name, preparedVertices.ToArray());
}

/// <summary>
Expand Down
Loading