Skip to content

Commit caa46e1

Browse files
authored
perf: Optimize ModuleSystemHeatColorAnimator (#172)
We can't make this use material property blocks because that will conflict with upcoming work in shabby, but we can debounce the changes so that it only does the expensive part when there is a noticeable change in the output colour.
1 parent 03192e3 commit caa46e1

2 files changed

Lines changed: 75 additions & 67 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
## 0.9.1 - 2026-05-12
21

2+
## Unreleased
3+
- Improved performance
4+
- Color animations no longer update all materials when they haven't changed.
5+
6+
## 0.9.1 - 2026-05-12
37
- Fixed memory leaks from dangling event handlers.
48
- Improved performance
59
- Moved several PAW item updates out of FixedUpdate and running them only when the PAW is open

Source/Modules/ModuleSystemHeatColorAnimator.cs

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -34,108 +34,112 @@ public class ModuleSystemHeatColorAnimator : PartModule, IScalarModule
3434
public string includedTransformList;
3535

3636

37-
public string ScalarModuleID
38-
{
39-
get { return moduleID; }
40-
}
41-
public bool CanMove
42-
{
43-
get { return true; }
44-
}
45-
public float GetScalar
46-
{
47-
get { return animationFraction; }
48-
}
37+
public string ScalarModuleID => moduleID;
4938

50-
public EventData<float, float> OnMoving
51-
{
52-
get { return new EventData<float, float>("OnMoving"); }
53-
}
39+
public bool CanMove => true;
5440

55-
public EventData<float> OnStop
56-
{
57-
get { return new EventData<float>("OnStop"); }
58-
}
59-
60-
61-
public void SetScalar(float t)
62-
{
63-
animationGoal = t;
64-
}
41+
public float GetScalar => animationFraction;
6542

66-
public bool IsMoving()
67-
{
68-
return true;
69-
}
7043

44+
public EventData<float, float> OnMoving => new("OnMoving");
45+
public EventData<float> OnStop => new("OnStop");
7146

47+
public void SetScalar(float t) => animationGoal = t;
48+
public bool IsMoving() => true;
7249

7350
public void SetUIWrite(bool value)
7451
{ }
7552
public void SetUIRead(bool value)
7653
{ }
7754

55+
float lastFraction = float.NaN;
56+
float animationFraction = 0f;
57+
float animationGoal = 0f;
58+
Renderer[] targetRenderers = [];
59+
int propertyID;
7860

79-
protected float animationFraction = 0f;
80-
protected float animationGoal = 0f;
81-
protected List<Renderer> targetRenderers;
82-
83-
protected void Start()
61+
void Start()
8462
{
63+
if (string.IsNullOrEmpty(shaderProperty))
64+
{
65+
enabled = false;
66+
return;
67+
}
68+
69+
propertyID = Shader.PropertyToID(shaderProperty);
70+
var renderers = new List<Renderer>();
8571

86-
targetRenderers = new List<Renderer>();
8772
if (string.IsNullOrEmpty(includedTransformList))
8873
{
89-
foreach (Transform x in part.GetComponentsInChildren<Transform>())
74+
foreach (var transform in part.GetComponentsInChildren<Transform>())
9075
{
91-
Renderer r = x.GetComponent<Renderer>();
76+
var renderer = transform.GetComponent<Renderer>();
77+
if (renderer == null)
78+
continue;
79+
if (!renderer.sharedMaterial.HasProperty(propertyID))
80+
continue;
9281

93-
if (r != null && r.material.HasProperty(shaderProperty)) targetRenderers.Add(r);
82+
renderers.Add(renderer);
9483
}
9584
}
9685
else
9786
{
98-
string[] allXformNames = includedTransformList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
99-
foreach (string xformName in allXformNames)
87+
var names = includedTransformList.Split([','], StringSplitOptions.RemoveEmptyEntries);
88+
foreach (var name in names)
10089
{
101-
Transform[] xforms = part.FindModelTransforms(xformName);
102-
foreach (Transform x in xforms)
90+
foreach (var transform in part.FindModelTransforms(name))
10391
{
104-
Renderer r = x.GetComponent<Renderer>();
92+
var renderer = transform.GetComponent<Renderer>();
93+
if (renderer == null)
94+
continue;
95+
if (!renderer.sharedMaterial.HasProperty(propertyID))
96+
continue;
10597

106-
if (r != null && r.material.HasProperty(shaderProperty))
107-
targetRenderers.Add(r);
98+
renderers.Add(renderer);
10899
}
109100
}
110101
}
111-
if (HighLogic.LoadedSceneIsEditor && targetRenderers != null)
112-
{
113-
animationFraction = 0f;
114-
Color c = new Color(redCurve.Evaluate(animationFraction) * colorScale, greenCurve.Evaluate(animationFraction) * colorScale, blueCurve.Evaluate(animationFraction) * colorScale, alphaCurve.Evaluate(animationFraction) * colorScale);
115102

116-
foreach (Renderer r in targetRenderers)
117-
{
118-
r.material.SetColor(shaderProperty, c);
119-
}
103+
targetRenderers = renderers.ToArray();
104+
if (targetRenderers.Length == 0)
105+
{
106+
enabled = false;
107+
return;
120108
}
121-
109+
110+
if (HighLogic.LoadedSceneIsEditor)
111+
UpdateMaterials();
122112
}
123113

124-
protected void Update()
114+
void Update()
125115
{
126-
if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor && targetRenderers != null)
127-
{
128-
animationFraction = Mathf.MoveTowards(animationFraction, animationGoal, TimeWarp.deltaTime * animRate);
116+
animationFraction = Mathf.MoveTowards(animationFraction, animationGoal, TimeWarp.deltaTime * animRate);
117+
if (Mathf.Abs(animationFraction - lastFraction) < 1e-3)
118+
return;
129119

130-
Color c = new Color(redCurve.Evaluate(animationFraction) * colorScale, greenCurve.Evaluate(animationFraction) * colorScale, blueCurve.Evaluate(animationFraction) * colorScale, alphaCurve.Evaluate(animationFraction) * colorScale);
120+
lastFraction = animationFraction;
121+
UpdateMaterials();
122+
}
131123

132-
foreach (Renderer r in targetRenderers)
133-
{
134-
if (r != null && r.material != null)
135-
r.material.SetColor(shaderProperty, c);
136-
}
124+
void UpdateMaterials()
125+
{
126+
var c = new Color(
127+
redCurve.Evaluate(animationFraction) * colorScale,
128+
greenCurve.Evaluate(animationFraction) * colorScale,
129+
blueCurve.Evaluate(animationFraction) * colorScale,
130+
alphaCurve.Evaluate(animationFraction) * colorScale
131+
);
132+
133+
foreach (var renderer in targetRenderers)
134+
{
135+
if (renderer == null)
136+
continue;
137+
var material = renderer.material;
138+
if (material == null)
139+
continue;
140+
141+
material.SetColor(propertyID, c);
137142
}
138143
}
139-
140144
}
141145
}

0 commit comments

Comments
 (0)