Skip to content

Commit 8626713

Browse files
committed
Improving MaterialTemplate with animation support [WIP]
1 parent 9233c80 commit 8626713

File tree

1 file changed

+110
-31
lines changed

1 file changed

+110
-31
lines changed

src/SharpGLTF.Runtime/Runtime/MaterialTemplate.cs

Lines changed: 110 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.Text;
55
using System.Xml.Linq;
66

7+
using SharpGLTF.Schema2;
8+
79
namespace SharpGLTF.Runtime
810
{
911
class MaterialTemplate
@@ -19,63 +21,108 @@ internal MaterialTemplate(Schema2.Material srcMaterial, RuntimeOptions options)
1921

2022
var isolateMemory = options?.IsolateMemory ?? false;
2123

24+
// gather animation channels targeting this material
25+
26+
_PointerPrefix = $"/materials/{srcMaterial.LogicalIndex}/";
27+
_IsAnimated = false;
28+
2229
foreach (var srcChannel in srcMaterial.Channels)
2330
{
24-
var key = srcChannel.Key;
31+
// loop over animations to find if any animation points
32+
// to a property of this material and connect the dots.
2533

26-
var txform = srcChannel.TextureTransform;
27-
var scale = txform == null ? null : new AnimatableProperty<Vector2>(txform.Scale);
28-
var rotation = txform == null ? null : new AnimatableProperty<float>(txform.Rotation);
29-
var offset = txform == null ? null : new AnimatableProperty<Vector2>(txform.Offset);
30-
31-
foreach (var srcAnim in srcMaterial.LogicalParent.LogicalAnimations)
34+
foreach (var srcTrack in srcMaterial.LogicalParent.LogicalAnimations)
3235
{
33-
var lidx = srcAnim.LogicalIndex;
34-
35-
// paths look like:
36-
// "/materials/14/pbrMetallicRoughness/metallicRoughnessTexture/extensions/KHR_texture_transform/scale"
36+
var trackIdx = srcTrack.LogicalIndex;
3737

38-
var pointerPath = srcChannel.GetAnimationPointer();
38+
var channels = srcTrack.FindChannels(_PointerPrefix);
3939

40-
foreach (var c in srcAnim.FindChannels(pointerPath))
40+
foreach(var channel in channels)
4141
{
42-
System.Diagnostics.Trace.WriteLine(c.TargetPointerPath);
42+
var pointerPath = channel.TargetPointerPath;
43+
System.Diagnostics.Debug.Assert(pointerPath.StartsWith(_PointerPrefix));
44+
pointerPath = pointerPath.Substring(_PointerPrefix.Length -1);
45+
46+
var fieldInfo = Reflection.FieldInfo.From(srcMaterial, pointerPath);
47+
48+
if (fieldInfo.IsEmpty)
49+
{
50+
System.Diagnostics.Debug.Fail("If it reaches this point it's probably because it's animating a property of an unregistered extension.");
51+
continue;
52+
}
53+
54+
if (fieldInfo.Value is float defaultSingle)
55+
{
56+
_ScalarAnimatables ??= new Dictionary<string, AnimatableProperty<float>>();
57+
_AddAnimatableProperty(_ScalarAnimatables, trackIdx, channel, pointerPath, defaultSingle, isolateMemory);
58+
}
4359

44-
if (c.TargetPointerPath.EndsWith("/extensions/KHR_texture_transform/scale"))
60+
if (fieldInfo.Value is Vector2 defaultVector2)
4561
{
46-
if (scale == null) throw new InvalidOperationException("found pointer to a TextureTransform, but target was not found");
47-
var sampler = c.GetSamplerOrNull<Vector2>().CreateCurveSampler(isolateMemory);
48-
scale.SetCurve(lidx, sampler);
62+
_Vector2Animatables ??= new Dictionary<string, AnimatableProperty<Vector2>>();
63+
_AddAnimatableProperty(_Vector2Animatables, trackIdx, channel, pointerPath, defaultVector2, isolateMemory);
4964
}
5065

51-
if (c.TargetPointerPath.EndsWith("/extensions/KHR_texture_transform/rotation"))
66+
if (fieldInfo.Value is Vector3 defaultVector3)
5267
{
53-
if (rotation == null) throw new InvalidOperationException("found pointer to a TextureTransform, but target was not found");
54-
var sampler = c.GetSamplerOrNull<float>().CreateCurveSampler(isolateMemory);
55-
rotation.SetCurve(lidx, sampler);
68+
_Vector3Animatables ??= new Dictionary<string, AnimatableProperty<Vector3>>();
69+
_AddAnimatableProperty(_Vector3Animatables, trackIdx, channel, pointerPath, defaultVector3, isolateMemory);
5670
}
5771

58-
if (c.TargetPointerPath.EndsWith("/extensions/KHR_texture_transform/offset"))
72+
if (fieldInfo.Value is Vector4 defaultVector4)
5973
{
60-
if (offset == null) throw new InvalidOperationException("found pointer to a TextureTransform, but target was not found");
61-
var sampler = c.GetSamplerOrNull<Vector2>().CreateCurveSampler(isolateMemory);
62-
offset.SetCurve(lidx, sampler);
74+
_Vector4Animatables ??= new Dictionary<string, AnimatableProperty<Vector4>>();
75+
_AddAnimatableProperty(_Vector4Animatables, trackIdx, channel, pointerPath, defaultVector4, isolateMemory);
6376
}
64-
}
77+
}
6578
}
6679
}
6780
}
6881

82+
private void _AddAnimatableProperty<T>(Dictionary<string, AnimatableProperty<T>> dict, int trackIdx, AnimationChannel channel, string pointerPath, T defaultSingle, bool isolateMemory)
83+
where T : struct
84+
{
85+
if (!dict.TryGetValue(pointerPath, out var target))
86+
{
87+
target = new AnimatableProperty<T>(defaultSingle);
88+
dict[pointerPath] = target;
89+
}
90+
91+
var sampler = channel.GetSamplerOrNull<T>().CreateCurveSampler(isolateMemory);
92+
target.SetCurve(trackIdx, sampler);
93+
94+
_IsAnimated = true;
95+
}
96+
6997
#endregion
7098

7199
#region data
72-
73-
private readonly int _LogicalSourceIndex;
100+
101+
private readonly int _LogicalSourceIndex;
102+
103+
private readonly string _PointerPrefix;
104+
105+
private readonly Dictionary<string, AnimatableProperty<float>> _ScalarAnimatables;
106+
private readonly Dictionary<string, AnimatableProperty<Vector2>> _Vector2Animatables;
107+
private readonly Dictionary<string, AnimatableProperty<Vector3>> _Vector3Animatables;
108+
private readonly Dictionary<string, AnimatableProperty<Vector4>> _Vector4Animatables;
109+
110+
private bool _IsAnimated;
74111

75112
#endregion
76113

77114
#region properties
78115

116+
/// <summary>
117+
/// If true, it means this material is animated.
118+
/// </summary>
119+
/// <remarks>
120+
/// Before rendering a model using this material, you check this property and then call
121+
/// <see cref="UpdateRuntimeMaterial(int, float, Action{string, float})"/> to update your
122+
/// engine's material properties
123+
/// </remarks>
124+
public bool IsAnimated => _IsAnimated;
125+
79126
public string Name { get; set; }
80127

81128
public Object Extras { get; set; }
@@ -89,9 +136,41 @@ internal MaterialTemplate(Schema2.Material srcMaterial, RuntimeOptions options)
89136

90137
#region API
91138

92-
public Matrix3x2 GetTextureTransform(int trackLogicalIndex, float time)
139+
140+
public void UpdateRuntimeMaterial(int trackLogicalIndex, float time, Action<string, float> target)
93141
{
94-
throw new NotImplementedException();
142+
foreach(var kvp in _ScalarAnimatables)
143+
{
144+
var val = kvp.Value.GetValueAt(trackLogicalIndex, time);
145+
target.Invoke(kvp.Key, val);
146+
}
147+
}
148+
149+
public void UpdateRuntimeMaterial(int trackLogicalIndex, float time, Action<string, Vector2> target)
150+
{
151+
foreach (var kvp in _Vector2Animatables)
152+
{
153+
var val = kvp.Value.GetValueAt(trackLogicalIndex, time);
154+
target.Invoke(kvp.Key, val);
155+
}
156+
}
157+
158+
public void UpdateRuntimeMaterial(int trackLogicalIndex, float time, Action<string, Vector3> target)
159+
{
160+
foreach (var kvp in _Vector3Animatables)
161+
{
162+
var val = kvp.Value.GetValueAt(trackLogicalIndex, time);
163+
target.Invoke(kvp.Key, val);
164+
}
165+
}
166+
167+
public void UpdateRuntimeMaterial(int trackLogicalIndex, float time, Action<string, Vector4> target)
168+
{
169+
foreach (var kvp in _Vector4Animatables)
170+
{
171+
var val = kvp.Value.GetValueAt(trackLogicalIndex, time);
172+
target.Invoke(kvp.Key, val);
173+
}
95174
}
96175

97176
#endregion

0 commit comments

Comments
 (0)