You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b3868ce
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -316,6 +316,7 @@
316
316
- Added `SpineSlotNode3D` for bone following, explicit 3D geometry insertion between Spine batches, and slot material overrides, plus batching statistics and renderer benchmarks.
317
317
- Added `SpineSprite3D.camera_relative_depth`, `depth_write_enabled`, `alpha_cutoff`, `get_aabb()`, and `get_depth_shader_code()`, with a custom-shader guide and interactive front/back depth example for module and GDExtension.
318
318
- Added explicit single-camera slot-anchor following through `SpineSlotNode3D.depth_camera`, with fixed-depth fallback and diagnostics for invalid cameras and multi-view/physics limitations.
319
+
- Added opt-in generated lighting, atlas normal maps, PBR controls, and texture-alpha-tested shadow modes to `SpineSprite3D`, with lazy shadow-only instances and an interactive Raptor lighting example.
319
320
- Added `SpineAnimationTrack` support for `SpineSprite3D` and Godot 4 GDExtension, including AnimationPlayer playback/editor scrubbing for both 2D and 3D sprites and a shared timeline example.
320
321
- Added an interactive 2D/3D benchmark example with configurable character counts, animation/pause controls, CPU timing and renderer statistics for module and GDExtension.
321
322
- Added tint black (two-color tinting) for Godot 4.3+ module and GDExtension runtimes, with animated coin examples and custom shader color attributes. See [#3169](https://github.com/EsotericSoftware/spine-runtimes/issues/3169).
@@ -327,6 +328,7 @@
327
328
- Added `SpineTrackEntry.get_additive()` / `set_additive()` for additive blending per track entry.
- Fixed callback-time `time_scale` changes affecting animation and skeleton/physics advances one update late after controller extraction.
331
333
- Fixed unrelated scene-tree mutations resetting `SpineSlotNode3D` insertion sorting and revealing inactive-bone children on manual or paused sprites; unchanged descendants retain ownership during transfers.
332
334
- Fixed newly allocated `SpineSprite3D` batch instances rendering while hidden, including pool growth and inherited visibility.
The generated materials are unlit and double-sided by default. Each attachment gets a small local Z offset according to its position in the **applied Spine draw order**. From behind, the vertex shader flips that offset, putting later attachments nearer the camera again. Attachment, triangle and batch submission order do not reverse. This preserves the authored layering from both sides, rather than revealing the back of a physical stack. It does not turn planar artwork into a volumetric character.
@@ -32,16 +34,71 @@ These depth-write settings control **generated materials**. Custom materials ret
32
34
33
35
The regression covers default `pixel_size = 0.01` with a `0.001` gap, and a larger 48-unit-wide fixture viewed from 60 units away with a `0.01` gap. On the tested Compatibility backend, the latter needed more than `0.001` once vertex displacement was active. Tune spacing and camera clipping ranges for your scene. Larger gaps make the layered construction more visible and increase the position jump when the camera crosses edge-on.
34
36
35
-
Alpha fades and soft atlas edges also deserve testing: fragments disappear at the cutoff, and surviving translucent fragments can occlude later geometry behind them. This is not order-independent transparency. Lighting and shadow support are separate from this depth policy; generated Spine materials currently cast no shadows.
37
+
Alpha fades and soft atlas edges also deserve testing: fragments disappear at the cutoff, and surviving translucent fragments can occlude later geometry behind them. This is not order-independent transparency.
38
+
39
+
## Generated lighting, normal maps, and shadows
40
+
41
+
Lighting is opt-in so existing scenes keep their authored unlit appearance:
42
+
43
+
```gdscript
44
+
sprite.lighting_enabled = true
45
+
sprite.normal_map_enabled = true
46
+
sprite.normal_map_flip_y = true
47
+
sprite.normal_scale = 1.0
48
+
sprite.specular = 0.25
49
+
sprite.roughness = 0.65
50
+
sprite.metallic = 0.0
51
+
```
52
+
53
+
Generated lit materials use the attachment plane's normal when no normal map exists. The runtime supplies standard mesh normals and UV-derived tangents, so atlas pages with imported normal maps can use Godot's compressed tangent-space normal-map path. Normal-map loading is not a separate 3D path: configure the atlas importer's existing normal-map prefix (for example, `n` resolves `n_raptor.png`) and `SpineAtlasResource` supplies the matching page texture. `normal_map_flip_y` defaults on for the convention used by the bundled Raptor asset; disable it for maps authored with the opposite Y convention. Example19 starts the high-contrast Raptor map at `normal_scale = 0.25`; tune strength for each asset and light rig. Animated normal/PBR controls are uniforms and do not rebuild mesh buffers or duplicate warmed materials.
Modes are **Off**, **On**, **Double-Sided**, and **Shadows Only**. Generated shadows use dedicated shadows-only RenderingServer instances and alpha-tested materials. They share the visible batch meshes and are allocated lazily on first use; turning shadows off hides and retains the warmed pool. `shadow_alpha_cutoff` is independent of visible `alpha_cutoff`, includes skeleton/slot/attachment tint alpha, and can be animated without creating a material for each value. Lighting does not need to be enabled for a generated material to cast shadows.
63
+
64
+
`camera_relative_depth` still operates per rendering camera for visible generated shaders. A shadow map has the light's view, so test extreme slot spacing, culling, and lights crossing the planar character in your scene. The alpha-tested shadow is a planar silhouette, not volumetric self-shadowing.
36
65
37
66
## Custom Spine materials
38
67
39
68
No user shader source is rewritten. Every cached `ShaderMaterial` pass receives these reserved uniforms from the sprite:
40
69
41
70
-`spine_texture`: current atlas-page texture.
42
71
-`spine_premultiplied_alpha`: the atlas page's PMA flag.
72
+
-`spine_normal_texture`: current atlas-page normal map, when one was imported.
73
+
-`spine_has_normal_texture`: whether the current page has a normal map.
43
74
-`spine_camera_relative_depth`: the sprite's camera-relative-depth flag.
44
-
-`spine_alpha_cutoff`: the sprite's alpha cutoff.
75
+
-`spine_alpha_cutoff`: the sprite's visible alpha cutoff.
76
+
-`spine_normal_map_enabled`, `spine_normal_map_flip_y`, and `spine_normal_scale`.
77
+
-`spine_specular`, `spine_roughness`, and `spine_metallic`.
78
+
79
+
Custom shaders receive light tint in `CUSTOM0`, dark tint in `CUSTOM1`, and standard mesh `NORMAL`/`TANGENT` attributes. They remain authored contracts: the runtime never inserts lighting, normal-map, blending, culling, depth, or shadow code into their source. Custom batches cast directly according to `shadow_casting`, so the shader's authored alpha/scissor and culling behavior controls its shadow pass; `shadow_alpha_cutoff` is only for generated shadow materials.
80
+
81
+
Use Godot's normal-map outputs in a custom lit shader:
if (spine_normal_map_flip_y) mapped_normal.g = 1.0 - mapped_normal.g;
95
+
NORMAL_MAP = mapped_normal;
96
+
NORMAL_MAP_DEPTH = spine_normal_scale;
97
+
}
98
+
}
99
+
```
100
+
101
+
Do not manually rely on the sampled blue channel: Godot may import normal maps with two-channel compression and reconstruct Z internally when `NORMAL_MAP` is used. `NORMAL_MAP_DEPTH = 0.0` restores the flat normal.
45
102
46
103
Template values for reserved uniforms do not override the sprite. Other uniforms remain template-owned. Reassign a template after changing its parameters to refresh cached copies. Every visible custom pass, including `next_pass`, needs to implement the policy if it should match the generated geometry. A pass that ignores it retains physical vertex positions and can hide or detach facial details from the back. Non-shader next passes do not acquire custom vertex logic automatically.
47
104
@@ -132,3 +189,5 @@ Native mesh culling bounds and `sprite.get_aabb()` include both possible depth d
132
189
Editor click/box picking conservatively includes attachment triangles at both possible depth positions. It may select a triangle at the currently unused position, especially with exaggerated spacing. It does not follow texture alpha, arbitrary custom shader deformation, or gameplay collision shapes.
133
190
134
191
Run `examples/18-depth-offset-orbit/depth-offset-orbit.tscn` in either Godot 4 example project. It uses the native sprite properties and generated materials. Compare the front/back toggle, then use **Exaggerate gap**, **Marker follows flip**, and **Face shader ignores flip** to inspect the child/custom-material contracts. The default gap can be restored with **Gap 0.001**.
192
+
193
+
Run `examples/19-3d-lighting/3d-lighting.tscn` to inspect generated lighting, the Raptor atlas normal map, moving omni-light response, normal strength/Y convention, and texture-alpha shadows on opaque ground.
@@ -87,6 +91,8 @@ position = Vector3(0, 1.5, 0.25)
87
91
skeleton_data_res = ExtResource("3")
88
92
pixel_size = 0.004
89
93
slot_depth_offset = 0.0002
94
+
lighting_enabled = true
95
+
shadow_casting = 2
90
96
preview_skin = "Default"
91
97
preview_animation = "animation"
92
98
preview_frame = true
@@ -98,5 +104,5 @@ offset_top = 20.0
98
104
offset_right = 1128.0
99
105
offset_bottom = 76.0
100
106
theme_override_font_sizes/font_size = 20
101
-
text = "Native SpineSprite3D — batched geometry, tint black, and a lit 3D sphere inserted at the hand slot\nThe light affects the sphere, orange box, and ground; generated Spine materials are unlit and cast no shadows."
107
+
text = "Native SpineSprite3D — batched geometry, tint black, lighting, and alpha-cutout shadows\nGodot lights affect Spine and inserted 3D geometry; Spineboy uses flat normals."
@@ -87,6 +91,8 @@ position = Vector3(0, 1.5, 0.25)
87
91
skeleton_data_res = ExtResource("3")
88
92
pixel_size = 0.004
89
93
slot_depth_offset = 0.0002
94
+
lighting_enabled = true
95
+
shadow_casting = 2
90
96
preview_skin = "Default"
91
97
preview_animation = "animation"
92
98
preview_frame = true
@@ -98,5 +104,5 @@ offset_top = 20.0
98
104
offset_right = 1128.0
99
105
offset_bottom = 76.0
100
106
theme_override_font_sizes/font_size = 20
101
-
text = "Native SpineSprite3D — batched geometry, tint black, and a lit 3D sphere inserted at the hand slot\nThe light affects the sphere, orange box, and ground; generated Spine materials are unlit and cast no shadows."
107
+
text = "Native SpineSprite3D — batched geometry, tint black, lighting, and alpha-cutout shadows\nGodot lights affect Spine and inserted 3D geometry; Spineboy uses flat normals."
0 commit comments