mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 07:45:33 +00:00
Add FrameAnimator3D for animated texture support on Blockbench models
This commit is contained in:
parent
35275f9048
commit
07be138a1b
3 changed files with 158 additions and 0 deletions
|
|
@ -5,10 +5,60 @@
|
|||
[ext_resource type="AudioStream" uid="uid://bjvklk7qmlivd" path="res://SFX/288963__littlerobotsoundfactory__click_electronic_14.wav" id="3_pmslt"]
|
||||
[ext_resource type="AudioStream" uid="uid://myr6n2c1u503" path="res://SFX/581602__samsterbirdies__beep-error.mp3" id="4_4smss"]
|
||||
[ext_resource type="PackedScene" uid="uid://w6jg5rx6d5gp" path="res://3D/BlockbenchModels/ControlPad/Control_Pad_Shoot.gltf" id="5_uhypp"]
|
||||
[ext_resource type="Texture2D" uid="uid://b7i8madir447q" path="res://3D/BlockbenchModels/ControlPad/Control_Pad_Shoot_0.png" id="6_pmslt"]
|
||||
[ext_resource type="Script" uid="uid://b46e1ft1scvwt" path="res://Scripts/Interactables/FrameAnimator3D.cs" id="6_uok2k"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_itd0i"]
|
||||
radius = 0.868968
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_4smss"]
|
||||
resource_name = "material_0"
|
||||
transparency = 2
|
||||
alpha_scissor_threshold = 0.05
|
||||
alpha_antialiasing_mode = 0
|
||||
cull_mode = 2
|
||||
albedo_texture = ExtResource("6_pmslt")
|
||||
texture_filter = 0
|
||||
texture_repeat = false
|
||||
|
||||
[sub_resource type="Animation" id="Animation_pmslt"]
|
||||
resource_name = "Flash"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("AnimatorManager:CurrentFrame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.20016107, 0.40089402, 0.60219884),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_4smss"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("AnimatorManager:CurrentFrame")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [0]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_fmo5v"]
|
||||
_data = {
|
||||
&"Flash": SubResource("Animation_pmslt"),
|
||||
&"RESET": SubResource("Animation_4smss")
|
||||
}
|
||||
|
||||
[node name="ControlPad" type="Area3D" unique_id=454991887 groups=["Interactable"]]
|
||||
collision_layer = 0
|
||||
collision_mask = 136
|
||||
|
|
@ -38,3 +88,16 @@ stream = ExtResource("4_4smss")
|
|||
bus = &"Effects"
|
||||
|
||||
[node name="blockbench_export2" parent="." unique_id=920256639 instance=ExtResource("5_uhypp")]
|
||||
|
||||
[node name="cylinder" parent="blockbench_export2" index="0"]
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_4smss")
|
||||
|
||||
[node name="AnimatorManager" type="Node3D" parent="." unique_id=1796988427 node_paths=PackedStringArray("TargetMesh")]
|
||||
script = ExtResource("6_uok2k")
|
||||
TargetMesh = NodePath("../blockbench_export2/cylinder")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=38747516]
|
||||
libraries/ = SubResource("AnimationLibrary_fmo5v")
|
||||
autoplay = &"Flash"
|
||||
|
||||
[editable path="blockbench_export2"]
|
||||
|
|
|
|||
94
Scripts/Interactables/FrameAnimator3D.cs
Normal file
94
Scripts/Interactables/FrameAnimator3D.cs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Interactables;
|
||||
|
||||
/// <summary>
|
||||
/// Animates a tiled texture by shifting the UV1 vertical offset on a mesh surface material.
|
||||
/// Designed for Blockbench-exported meshes whose texture is a vertical sprite sheet
|
||||
/// (e.g. 16×64 with 4 frames stacked top-to-bottom).
|
||||
///
|
||||
/// Usage:
|
||||
/// 1. Attach this node as a child of (or sibling to) the MeshInstance3D you want to animate.
|
||||
/// 2. Optionally assign <see cref="TargetMesh"/> in the inspector; if left empty the node
|
||||
/// will search its parent for the first MeshInstance3D automatically.
|
||||
/// 3. Set <see cref="FrameCount"/> to the number of frames in the sprite sheet.
|
||||
/// 4. Drive <see cref="CurrentFrame"/> from an AnimationPlayer track — the script handles
|
||||
/// the UV offset calculation.
|
||||
/// </summary>
|
||||
[Tool]
|
||||
public partial class FrameAnimator3D : Node3D
|
||||
{
|
||||
/// <summary>
|
||||
/// The mesh whose surface_0 material UV offset will be updated.
|
||||
/// If null, the node searches its parent for the first MeshInstance3D on _Ready.
|
||||
/// </summary>
|
||||
[Export] public MeshInstance3D TargetMesh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of animation frames stacked vertically in the texture.
|
||||
/// </summary>
|
||||
[Export] public int FrameCount { get; set; } = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Surface index on the mesh to apply the UV offset to.
|
||||
/// Defaults to 0, matching Blockbench's typical single-surface export.
|
||||
/// </summary>
|
||||
[Export] public int SurfaceIndex { get; set; } = 0;
|
||||
|
||||
private int _currentFrame;
|
||||
|
||||
/// <summary>
|
||||
/// The active frame index (0-based). Set this from an AnimationPlayer track to animate.
|
||||
/// Clamped to [0, <see cref="FrameCount"/> - 1].
|
||||
/// </summary>
|
||||
[Export]
|
||||
public int CurrentFrame
|
||||
{
|
||||
get => _currentFrame;
|
||||
set
|
||||
{
|
||||
_currentFrame = Mathf.Clamp(value, 0, Mathf.Max(0, FrameCount - 1));
|
||||
ApplyFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// Auto-discover the mesh from the parent if none was assigned in the inspector.
|
||||
if (TargetMesh is null)
|
||||
{
|
||||
TargetMesh = GetParent() as MeshInstance3D
|
||||
?? GetParentOrNull<Node>()?.FindChild("*", recursive: false, owned: false) as MeshInstance3D;
|
||||
}
|
||||
|
||||
ApplyFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the normalised V offset for <see cref="CurrentFrame"/> and writes it to the
|
||||
/// override material on <see cref="TargetMesh"/>'s surface.
|
||||
/// Each frame occupies an equal vertical slice: offset = frame / frameCount.
|
||||
/// </summary>
|
||||
private void ApplyFrame()
|
||||
{
|
||||
if (TargetMesh is null || FrameCount <= 0) return;
|
||||
|
||||
// Ensure we have an override material to write to so we don't mutate shared resources.
|
||||
if (TargetMesh.GetSurfaceOverrideMaterial(SurfaceIndex) is not StandardMaterial3D mat)
|
||||
{
|
||||
var baseMat = TargetMesh.GetActiveMaterial(SurfaceIndex);
|
||||
|
||||
// Duplicate the base material so sibling nodes keep their own state.
|
||||
mat = baseMat?.Duplicate() as StandardMaterial3D;
|
||||
if (mat is null) return;
|
||||
|
||||
TargetMesh.SetSurfaceOverrideMaterial(SurfaceIndex, mat);
|
||||
}
|
||||
|
||||
// Each frame is a 1/FrameCount slice; V offset moves down one slice per frame.
|
||||
float vOffset = (float)_currentFrame / FrameCount;
|
||||
mat.Uv1Offset = new Vector3(mat.Uv1Offset.X, vOffset, mat.Uv1Offset.Z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
Scripts/Interactables/FrameAnimator3D.cs.uid
Normal file
1
Scripts/Interactables/FrameAnimator3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b46e1ft1scvwt
|
||||
Loading…
Add table
Add a link
Reference in a new issue