Skip to content

Commit 71e735e

Browse files
authored
Merge pull request #24 from nasshu2916/feature/amin-reduce-key
フレーム削減周りのリファクタ
2 parents 174c6b0 + 360bfec commit 71e735e

File tree

7 files changed

+147
-51
lines changed

7 files changed

+147
-51
lines changed

Assets/ArtNet/Editor/DmxRecorder/TimelineConverter.cs

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ public void SaveDmxTimelineClips(string directory)
5050
var curves = timelineUniverse.AnimationCurves();
5151
for (var i = 0; i < curves.Length; i++)
5252
{
53-
if (curves[i].keys.Length == 0) continue;
54-
clip.SetCurve($"Universe{universe}", typeof(DmxData), $"Ch{i + 1:D3}", curves[i]);
53+
var curve = curves[i];
54+
if (curve.keys.Length == 0) continue;
55+
56+
clip.SetCurve($"Universe{universe}", typeof(DmxData), $"Ch{i + 1:D3}", curve);
5557
}
5658
}
5759
SaveAsset(clip, directory, "ArtNetDmx.anim");
@@ -75,17 +77,17 @@ private static void SaveAsset<T>(T asset, string directory, string fileName) whe
7577
public class TimelineUniverse
7678
{
7779
public int Universe { get; }
78-
private List<DmxFrameData>[] ChannelDmxFrameData { get; }
80+
private List<KeyFrameData>[] ChannelDmxFrameData { get; }
7981

8082
public TimelineUniverse(int groupKey, IReadOnlyCollection<UniverseData> universeData)
8183
{
8284
Universe = groupKey;
83-
ChannelDmxFrameData = new List<DmxFrameData>[512];
85+
ChannelDmxFrameData = new List<KeyFrameData>[512];
8486

8587
for (var i = 0; i < ChannelDmxFrameData.Length; i++)
8688
{
8789
ChannelDmxFrameData[i] = universeData.Where(x => x.Values.Length > i)
88-
.Select(x => new DmxFrameData((float) x.Time, x.Values[i]))
90+
.Select(x => new KeyFrameData((float) x.Time, x.Values[i]))
8991
.OrderBy(x => x.Time).ToList();
9092
}
9193
}
@@ -94,7 +96,7 @@ public TimelineUniverse(int universe, AnimationClip clip)
9496
{
9597
Universe = universe;
9698
var curveBindings = AnimationUtility.GetCurveBindings(clip);
97-
ChannelDmxFrameData = new List<DmxFrameData>[512];
99+
ChannelDmxFrameData = new List<KeyFrameData>[512];
98100
for (var i = 0; i < ChannelDmxFrameData.Length; i++)
99101
{
100102
var propertyName = $"Ch{i + 1:D3}";
@@ -106,7 +108,7 @@ public TimelineUniverse(int universe, AnimationClip clip)
106108

107109
if (curve is null) continue;
108110

109-
ChannelDmxFrameData[i] = curve.keys.Select(x => new DmxFrameData((int) (x.time * 1000), (byte) x.value)).ToList();
111+
ChannelDmxFrameData[i] = curve.keys.Select(x => new KeyFrameData((int) (x.time * 1000), (byte) x.value)).ToList();
110112
}
111113
}
112114

@@ -162,7 +164,14 @@ public AnimationCurve[] AnimationCurves()
162164
{
163165
var keyframes = ChannelDmxFrameData[i]
164166
.Select(data => new Keyframe(data.Time, data.Value)).ToArray();
165-
curves[i] = new AnimationCurve(keyframes);
167+
var curve = new AnimationCurve(keyframes);
168+
for (var j = 0; j < curve.keys.Length; j++)
169+
{
170+
AnimationUtility.SetKeyLeftTangentMode(curve, j, AnimationUtility.TangentMode.Constant);
171+
AnimationUtility.SetKeyRightTangentMode(curve, j, AnimationUtility.TangentMode.Constant);
172+
}
173+
174+
curves[i] = curve;
166175
}
167176

168177
return curves;
@@ -173,40 +182,10 @@ public void ThinOutUnchangedFrames()
173182
for (var i = 0; i < ChannelDmxFrameData.Length; i++)
174183
{
175184
var dmxFrameData = ChannelDmxFrameData[i];
176-
if (dmxFrameData.Count == 0) continue;
177-
178-
var latest = dmxFrameData[0];
179-
var newDmxFrameData = new List<DmxFrameData> { dmxFrameData[0] };
180-
181-
for (var j = 1; j < dmxFrameData.Count - 1; j++)
182-
{
183-
var current = dmxFrameData[j];
184-
var next = dmxFrameData[j + 1];
185-
if (IsOmittedFrame(latest, current, next)) continue;
186-
187-
latest = current;
188-
newDmxFrameData.Add(dmxFrameData[j]);
189-
}
190-
191-
newDmxFrameData.Add(dmxFrameData[^1]);
192-
ChannelDmxFrameData[i] = newDmxFrameData;
185+
ChannelDmxFrameData[i] = KeyFrameReducer.Reduce(dmxFrameData);
193186
}
194187
}
195188

196-
private static bool IsOmittedFrame(
197-
DmxFrameData prev,
198-
DmxFrameData current,
199-
DmxFrameData next,
200-
float tolerance = 0.01f)
201-
{
202-
var prevDiff = current.Value - prev.Value;
203-
var nextDiff = next.Value - current.Value;
204-
var prevDiffTime = current.Time - prev.Time;
205-
var nextDiffTime = next.Time - current.Time;
206-
207-
return Math.Abs(prevDiff / prevDiffTime - nextDiff / nextDiffTime) <= tolerance;
208-
}
209-
210189
public IEnumerable<UniverseData> ToUniverseData()
211190
{
212191
var universeData = new List<UniverseData>();
@@ -226,16 +205,4 @@ public IEnumerable<UniverseData> ToUniverseData()
226205
return universeData;
227206
}
228207
}
229-
230-
public struct DmxFrameData
231-
{
232-
public float Time { get; }
233-
public byte Value { get; }
234-
235-
public DmxFrameData(float time, byte value)
236-
{
237-
Time = time;
238-
Value = value;
239-
}
240-
}
241208
}

Assets/ArtNet/Editor/KeyFrameData.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace ArtNet.Editor
2+
{
3+
public struct KeyFrameData
4+
{
5+
public float Time { get; }
6+
public byte Value { get; }
7+
8+
public KeyFrameData(float time, byte value)
9+
{
10+
Time = time;
11+
Value = value;
12+
}
13+
}
14+
}

Assets/ArtNet/Editor/KeyFrameData.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ArtNet.Editor
5+
{
6+
public static class KeyFrameReducer
7+
{
8+
public static List<KeyFrameData> Reduce(List<KeyFrameData> keyFrameData)
9+
{
10+
if (keyFrameData.Count <= 2) return keyFrameData;
11+
12+
var newDmxFrameData = new List<KeyFrameData> { keyFrameData[0] };
13+
var latest = keyFrameData[0];
14+
15+
for (var i = 1; i < keyFrameData.Count - 1; i++)
16+
{
17+
var current = keyFrameData[i];
18+
if (latest.Value == current.Value) continue;
19+
20+
newDmxFrameData.Add(current);
21+
latest = current;
22+
}
23+
24+
newDmxFrameData.Add(keyFrameData[^1]);
25+
return newDmxFrameData;
26+
}
27+
}
28+
}

Assets/ArtNet/Editor/KeyFrameReducer.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace ArtNet.Editor
6+
{
7+
public class RamerDouglasPeucker
8+
{
9+
private readonly float _threshold;
10+
11+
public RamerDouglasPeucker(float errorThreshold)
12+
{
13+
_threshold = errorThreshold * errorThreshold;
14+
}
15+
16+
public List<Keyframe> Reduce(ReadOnlySpan<Keyframe> keys)
17+
{
18+
return Execute(keys, 0, keys.Length - 1);
19+
}
20+
21+
private List<Keyframe> Execute(ReadOnlySpan<Keyframe> keys, int startIndex, int endIndex)
22+
{
23+
if (endIndex - startIndex < 2)
24+
{
25+
return new List<Keyframe> { keys[startIndex], keys[endIndex] };
26+
}
27+
28+
// 最大距離のKeyframeを探索
29+
var maxDistance = 0f;
30+
var maxIndex = startIndex;
31+
for (var i = startIndex + 1; i < endIndex; i++)
32+
{
33+
var distance = PerpendicularDistanceSquared(keys[i], keys[startIndex], keys[endIndex]);
34+
if (distance <= maxDistance) continue;
35+
36+
maxIndex = i;
37+
maxDistance = distance;
38+
}
39+
40+
// 最大距離が閾値未満なら直線を返す
41+
if (maxDistance < _threshold)
42+
{
43+
return new List<Keyframe> { keys[startIndex], keys[endIndex] };
44+
}
45+
46+
// 最大距離の点で再帰的に処理
47+
var result1 = Execute(keys, startIndex, maxIndex);
48+
var result2 = Execute(keys, maxIndex, endIndex);
49+
50+
// 重複を取り除いて結合
51+
result1.RemoveAt(result1.Count - 1);
52+
result1.AddRange(result2);
53+
54+
return result1;
55+
}
56+
57+
/// <summary>
58+
/// 垂線距離の2乗を計算
59+
/// </summary>
60+
private static float PerpendicularDistanceSquared(Keyframe point, Keyframe startPoint, Keyframe endPoint)
61+
{
62+
var dx = endPoint.time - startPoint.time;
63+
var dy = endPoint.value - startPoint.value;
64+
65+
var denominator = dx * dx + dy * dy;
66+
67+
if (denominator < 1e-6f)
68+
{
69+
var psx = point.time - startPoint.time;
70+
var psy = point.value - startPoint.value;
71+
return psx * psx + psy * psy;
72+
}
73+
74+
var numerator = dy * point.time - dx * point.value + endPoint.time * startPoint.value - endPoint.value * startPoint.time;
75+
return (numerator * numerator) / denominator;
76+
}
77+
}
78+
}

Assets/ArtNet/Editor/RamerDouglasPeucker.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)