From 81415a1abbe13dee7ea57818ef9ed139c7f7185f Mon Sep 17 00:00:00 2001 From: Phantomical Date: Mon, 11 May 2026 17:53:17 -0700 Subject: [PATCH 1/2] perf: Optimize ModuleSystemHeatColorAnimator 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. --- .../Modules/ModuleSystemHeatColorAnimator.cs | 136 +++++++++--------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/Source/Modules/ModuleSystemHeatColorAnimator.cs b/Source/Modules/ModuleSystemHeatColorAnimator.cs index dfd7c36..1a40310 100644 --- a/Source/Modules/ModuleSystemHeatColorAnimator.cs +++ b/Source/Modules/ModuleSystemHeatColorAnimator.cs @@ -34,108 +34,112 @@ public class ModuleSystemHeatColorAnimator : PartModule, IScalarModule public string includedTransformList; - public string ScalarModuleID - { - get { return moduleID; } - } - public bool CanMove - { - get { return true; } - } - public float GetScalar - { - get { return animationFraction; } - } + public string ScalarModuleID => moduleID; - public EventData OnMoving - { - get { return new EventData("OnMoving"); } - } + public bool CanMove => true; - public EventData OnStop - { - get { return new EventData("OnStop"); } - } - - - public void SetScalar(float t) - { - animationGoal = t; - } + public float GetScalar => animationFraction; - public bool IsMoving() - { - return true; - } + public EventData OnMoving => new("OnMoving"); + public EventData OnStop => new("OnStop"); + public void SetScalar(float t) => animationGoal = t; + public bool IsMoving() => true; public void SetUIWrite(bool value) { } public void SetUIRead(bool value) { } + float lastFraction = float.NaN; + float animationFraction = 0f; + float animationGoal = 0f; + Renderer[] targetRenderers = []; + int propertyID; - protected float animationFraction = 0f; - protected float animationGoal = 0f; - protected List targetRenderers; - - protected void Start() + void Start() { + if (string.IsNullOrEmpty(shaderProperty)) + { + enabled = false; + return; + } + + propertyID = Shader.PropertyToID(shaderProperty); + var renderers = new List(); - targetRenderers = new List(); if (string.IsNullOrEmpty(includedTransformList)) { - foreach (Transform x in part.GetComponentsInChildren()) + foreach (var transform in part.GetComponentsInChildren()) { - Renderer r = x.GetComponent(); + var renderer = transform.GetComponent(); + if (renderer == null) + continue; + if (!renderer.sharedMaterial.HasProperty(propertyID)) + continue; - if (r != null && r.material.HasProperty(shaderProperty)) targetRenderers.Add(r); + renderers.Add(renderer); } } else { - string[] allXformNames = includedTransformList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string xformName in allXformNames) + var names = includedTransformList.Split([','], StringSplitOptions.RemoveEmptyEntries); + foreach (var name in names) { - Transform[] xforms = part.FindModelTransforms(xformName); - foreach (Transform x in xforms) + foreach (var transform in part.FindModelTransforms(name)) { - Renderer r = x.GetComponent(); + var renderer = transform.GetComponent(); + if (renderer == null) + continue; + if (!renderer.sharedMaterial.HasProperty(propertyID)) + continue; - if (r != null && r.material.HasProperty(shaderProperty)) - targetRenderers.Add(r); + renderers.Add(renderer); } } } - if (HighLogic.LoadedSceneIsEditor && targetRenderers != null) - { - animationFraction = 0f; - Color c = new Color(redCurve.Evaluate(animationFraction) * colorScale, greenCurve.Evaluate(animationFraction) * colorScale, blueCurve.Evaluate(animationFraction) * colorScale, alphaCurve.Evaluate(animationFraction) * colorScale); - foreach (Renderer r in targetRenderers) - { - r.material.SetColor(shaderProperty, c); - } + targetRenderers = renderers.ToArray(); + if (targetRenderers.Length == 0) + { + enabled = false; + return; } - + + if (HighLogic.LoadedSceneIsEditor) + UpdateMaterials(); } - protected void Update() + void Update() { - if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor && targetRenderers != null) - { - animationFraction = Mathf.MoveTowards(animationFraction, animationGoal, TimeWarp.deltaTime * animRate); + animationFraction = Mathf.MoveTowards(animationFraction, animationGoal, TimeWarp.deltaTime * animRate); + if (Mathf.Abs(animationFraction - lastFraction) < 1e-3) + return; - Color c = new Color(redCurve.Evaluate(animationFraction) * colorScale, greenCurve.Evaluate(animationFraction) * colorScale, blueCurve.Evaluate(animationFraction) * colorScale, alphaCurve.Evaluate(animationFraction) * colorScale); + lastFraction = animationFraction; + UpdateMaterials(); + } - foreach (Renderer r in targetRenderers) - { - if (r != null && r.material != null) - r.material.SetColor(shaderProperty, c); - } + void UpdateMaterials() + { + var c = new Color( + redCurve.Evaluate(animationFraction) * colorScale, + greenCurve.Evaluate(animationFraction) * colorScale, + blueCurve.Evaluate(animationFraction) * colorScale, + alphaCurve.Evaluate(animationFraction) * colorScale + ); + + foreach (var renderer in targetRenderers) + { + if (renderer == null) + continue; + var material = renderer.material; + if (material == null) + continue; + + material.SetColor(propertyID, c); } } - } } From 5369cbe69c512d6ff671ac6b4b0c7d12c6e4370e Mon Sep 17 00:00:00 2001 From: Phantomical Date: Mon, 11 May 2026 18:08:25 -0700 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f23115..79e9ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Improved performance - SystemHeat resource converters now fully disable themselves when inactive. - Several other optimizations to make resource converters faster. + - Color animations no longer update all materials when they haven't changed. ## 0.9.0 - 2026-05-08