Fixed garbled shader sprite on player

This commit is contained in:
MaddoScientisto 2026-02-28 10:38:39 +01:00
commit 63ad349b42
3 changed files with 147 additions and 101 deletions

View file

@ -5,14 +5,37 @@ namespace Cirno.Scripts.Components.Actors._3D;
[Tool]
public partial class AnimatedShaderSprite3D : AnimatedSprite3D
{
private bool _isConnected = false;
private bool _isConnected;
private ShaderMaterial _shaderMaterial;
// Export the shader parameter name so the shader can use a different uniform name if needed.
[Export]
public string ShaderParameterName { get; set; } = "tex";
/// <summary>
/// Called when the node enters the scene tree. Ensure the shader receives the current
/// sprite frame right away (avoids the garbled default until the first frame change).
/// </summary>
public override void _Ready()
{
base._Ready();
ConnectSignals();
_shaderMaterial = (ShaderMaterial)MaterialOverride;
// Safely try to use the MaterialOverride as a ShaderMaterial. If it's not present
// we warn and skip applying parameters to avoid runtime exceptions.
if (MaterialOverride is ShaderMaterial sm)
{
_shaderMaterial = sm;
}
else
{
_shaderMaterial = null;
GD.PrintErr($"AnimatedShaderSprite3D: MaterialOverride is not a ShaderMaterial on '{Name}'. Shader parameters will not be applied.");
}
// Defer applying the current frame until after the engine finishes initialization
// so we avoid reading frames or materials before they're fully ready.
CallDeferred(nameof(ApplyCurrentFrame));
}
@ -29,7 +52,42 @@ public partial class AnimatedShaderSprite3D : AnimatedSprite3D
protected void HandleFrameChanged()
{
_shaderMaterial.SetShaderParameter("tex", SpriteFrames.GetFrameTexture(Animation, Frame));
ApplyCurrentFrame();
}
/// <summary>
/// Safely set the shader parameter to the current animation/frame texture.
/// This method protects against missing SpriteFrames, missing animation names,
/// and null material so it won't crash at startup.
/// </summary>
private void ApplyCurrentFrame()
{
if (_shaderMaterial is null)
{
return;
}
var frames = SpriteFrames;
if (frames is null)
{
// No frames assigned; nothing to do.
return;
}
// Guard against missing animation or frame out-of-range.
try
{
var tex = frames.GetFrameTexture(Animation, Frame);
if (tex is not null)
{
_shaderMaterial.SetShaderParameter(ShaderParameterName, tex);
}
}
catch (System.Exception ex)
{
// Don't crash the editor/runtime for a missing animation name or bad frame index.
GD.PrintErr($"AnimatedShaderSprite3D: Could not apply frame texture on '{Name}': {ex.Message}");
}
}
protected override void Dispose(bool disposing)