Script that merges a bunch of Godot gradients into a single texture
tool
extends EditorScript
const output_file := "res://project_specific/gfx/player_gradients/player_gradients.png"
func _run() -> void:
var merged_image := Image.new()
var texture_width := 32
var texture_height := PlayerGradients.gradients.size()
merged_image.create(texture_width, texture_height, false, Image.FORMAT_RGBA8)
for i in PlayerGradients.gradients.size():
var gradient:Gradient = load(PlayerGradients.gradients[i])
var gradient_texture := GradientTexture.new()
gradient_texture.width = 32
#gradient_texture.height = 1
gradient_texture.gradient = gradient
var gradient_data := gradient_texture.get_data()
merged_image.blit_rect(gradient_data, Rect2(Vector2.ZERO, gradient_data.get_size()), Vector2(0.0, i))
merged_image.save_png(output_file)
get_editor_interface().get_resource_filesystem().scan()
the output:
Singleton that has some helper functions:
extends Node
class_name PlayerGradients
const gradients := [
"res://project_specific/gfx/player_gradients/beige.tres",
"res://project_specific/gfx/player_gradients/blue-pink.tres",
"res://project_specific/gfx/player_gradients/blue.tres",
"res://project_specific/gfx/player_gradients/blue_dark.tres",
"res://project_specific/gfx/player_gradients/brown.tres",
"res://project_specific/gfx/player_gradients/cyan-pink.tres",
"res://project_specific/gfx/player_gradients/cyan-yellow.tres",
"res://project_specific/gfx/player_gradients/green.tres",
"res://project_specific/gfx/player_gradients/indigo-green.tres",
"res://project_specific/gfx/player_gradients/lemon-lime.tres",
"res://project_specific/gfx/player_gradients/lime-lemon.tres",
"res://project_specific/gfx/player_gradients/navy-peach.tres",
"res://project_specific/gfx/player_gradients/notint.tres",
"res://project_specific/gfx/player_gradients/orange.tres",
"res://project_specific/gfx/player_gradients/pink-cyan.tres",
"res://project_specific/gfx/player_gradients/pink.tres",
"res://project_specific/gfx/player_gradients/purple-gold.tres",
"res://project_specific/gfx/player_gradients/purple-teal.tres",
"res://project_specific/gfx/player_gradients/purple.tres",
"res://project_specific/gfx/player_gradients/red-yellow.tres",
"res://project_specific/gfx/player_gradients/red.tres",
"res://project_specific/gfx/player_gradients/rose.tres",
"res://project_specific/gfx/player_gradients/white.tres",
"res://project_specific/gfx/player_gradients/yellow-pink.tres",
"res://project_specific/gfx/player_gradients/yellow.tres",
]
static func index_of_gradient_name(gradient_name:String)->int:
var full_path := "res://project_specific/gfx/player_gradients/" + gradient_name + ".tres"
return gradients.find(full_path)
static func uv_index_of_gradient_name(gradient_name:String)->float:
var index := index_of_gradient_name(gradient_name)
var half_pixel := 0.5 / gradients.size()
return (float(index) / gradients.size()) + half_pixel
static func load_gradient(gradient_name:String)->Gradient:
var full_path := "res://project_specific/gfx/player_gradients/" + gradient_name + ".tres"
return load(full_path) as Gradient
Script on the spine sprite that sets the vertex color of the slots that we want to tint
func apply_gradient_tint():
var slots := get_skeleton().get_slots()
for s in slots:
var slot:SpineSlot = s
var attachment:SpineAttachment = slot.get_attachment()
if not attachment:
continue
var should_tint := attachment.get_attachment_name().find("-tint") != -1
if should_tint:
var y_coordinate := PlayerGradients.uv_index_of_gradient_name(gradient_name)
var tint_color := Color(0.0, y_coordinate, 0.0, 1.0)
slot.set_color(tint_color)
else:
slot.set_color(Color.white)
Shader that uses those vertex coordinates to tint (or not tint) the characters
shader_type canvas_item;
uniform sampler2D gradient;
void fragment() {
vec4 vertex_color = COLOR;
vec4 sample = texture(TEXTURE, UV);
vec2 grad_uv = vec2(sample.r, vertex_color.y);
vec3 grad = texture(gradient, grad_uv).rgb;
COLOR.rgb = mix(sample.rgb, grad.rgb, 1.0 - vertex_color.r);
COLOR.a = sample.a;
}
This shader is used as the 'normal' shader on the spine sprite.
This technique allows us to render all of our spine sprites with gradient tinting and with 1 draw call.