Files
swarm-farm/entities/alien/assets/shader/vat.gdshader
T
2026-09-01 22:41:37 +02:00

169 lines
6.2 KiB
Plaintext

// Shader stolen here : https://godotshaders.com/shader/vertex-animation-texture-uses-openvat-output/
shader_type spatial;
render_mode cull_disabled; // Prevents GPU hardware culling so shader can handle it
/*
For use with models exported from Blender using the OpenVAT plugin.
Expects:
Vertex Normals - Packed (Math gets too complex to include a toggle. Making a separate shader recommended if normals are not needed.)
Use Single Row - On
Export Model - On
Model Format - glTF Binary. (Unsure why the otherse do not work)
Ensure .exr file is set to Lossless compression and MipMaps - Off.
*/
// --- Uniforms ---
group_uniforms openVAT_inputs;
/** OpenVAT texture exported from Blender plugin. */
uniform sampler2D vertex_animation_texture : repeat_disable;
/** Min values from the .json file included with OpenVAT exports. */
uniform vec3 min_bounds;
/** Max values from the .json file included with OpenVAT exports. */
uniform vec3 max_bounds;
/** Plays animation automatically. Turn off to control manually via keyframes. */
uniform bool autoplay = true;
/**
Autoplay speed in frames per second. Defaults to 30.
[b]Blender default is 24. May require adjustment either in Blender or Here to match speed.[b]
*/
uniform float autoplay_speed = 30.0;
/** Frame to display if animating manually. */
uniform float frame = 1.0;
/** Enable this if the asset does not have 2 UV sets. */
uniform bool use_uv_1 = false;
/** Cull Mode, editable here for flexibility.
0: Backface Cull
1: Frontface Cull
2: Cull disabled (double sided rendering)*/
uniform int cull_mode : hint_enum("Back:0", "Front:1", "Disabled:2") = 0;
group_uniforms;
group_uniforms Albedo_map;
uniform sampler2D albedo_map : source_color, hint_default_white;
uniform vec4 albedo_tint : source_color = vec4(1.0);
group_uniforms;
group_uniforms ORM_inputs;
/**
[b]ORM texture.[/b] Standardized detail maps for PBR materials. Ignore, remap, or remove as needed.
[b]O[/b]cclusion (Ambient)
[b]R[/b]oughness
[b]M[/b]etallic
*/
uniform sampler2D orm_map : hint_default_white;
/** Select channel used by Occlusion map. R G [b]or[/b] B, combining will have strange results */
uniform vec4 occlusion_channel : source_color = vec4(1.0, 0.0, 0.0, 1.0);
/** Strength of Occlusion*/
uniform float occlusion : hint_range(0.0, 1.0) = 1.0;
/** Select channel used by Roughness map. R G [b]or[/b] B, combining will have strange results */
uniform vec4 roughness_channel : source_color = vec4(0.0, 1.0, 0.0, 1.0);
/** Strength of Roughness*/
uniform float roughness : hint_range(0.0, 1.0) = 1.0;
/** Select channel used by Metallic map. R G [b]or[/b] B, combining will have strange results */
uniform vec4 metallic_channel : source_color = vec4(0.0, 0.0, 1.0, 1.0);
/** Strength of Metallic*/
uniform float metallic : hint_range(0.0, 1.0) = 1.0;
/** Strength of Specular (No Map Included)*/
uniform float specular : hint_range(0.0, 1.0) = 0.5;
group_uniforms;
group_uniforms Normal_map;
uniform sampler2D normal_map : hint_roughness_normal;
uniform float normal_map_scale : hint_range(-10.0, 10.0) = 1.0;
/** Passed data from INSTANCE_CUSTOM_VARIABLE :
x : Unique Id
y : Damage effect
z : Size
**/
varying flat float unique_id;
varying flat float damage_effect;
varying flat float size;
float remapFloat(float value, float input_min, float input_max, float output_min, float output_max){
// Code to replicate the remap feature from Visual Shader.
float _input_range = input_max - input_min;
float _output_range = output_max - output_min;
return output_min + _output_range * ((value - input_min) / _input_range);
}
void vertex() {
unique_id = INSTANCE_CUSTOM.x;
damage_effect = INSTANCE_CUSTOM.y;
size = INSTANCE_CUSTOM.z;
// Animation Timing
// ------
// Divided by 2. since bottom half of texture is the normal data.
// Second argument (0) is MipMap level. These VATs use no mipmaps so always 0.
int total_frames = textureSize(vertex_animation_texture, 0).y / 2;
// Checks if Autoplaying is checked
float play_frame = autoplay ? (TIME * autoplay_speed / size) : frame;
// Loops the current frame counter so it stays between 0 and total_frames - 1
float current_frame = mod(play_frame + unique_id, float(total_frames));
// Compute UV Coordinates
// ------
// samples pixel from the center, not the edge. Avoid unwanted bleeding into normal data pixels at the end of the loop.
float center_pixel = current_frame - 0.5;
float vat_y = center_pixel / float(total_frames);
vat_y = clamp(vat_y * 0.5, 0.0, 0.5);
vec2 vat_uv = vec2((use_uv_1 ? UV.x : UV2.x), vat_y);
// Vertex Position Displacement
// ------
vec4 vat_pos_raw = texture(vertex_animation_texture, vat_uv);
// Must go through some remapping to convert Blender to Godot coordinates
vec3 offset_values = vec3(
remapFloat(vat_pos_raw.r, 0.0, 1.0, min_bounds.x, max_bounds.x),
remapFloat(vat_pos_raw.b, 0.0, 1.0, min_bounds.z, max_bounds.z),
remapFloat(vat_pos_raw.g, 1.0, 0.0, min_bounds.y, max_bounds.y)
);
VERTEX += offset_values;
// Normals. 0.5 added to UV.y to shift it down by 1/2 the map - to the normals section.
vec4 vat_norm_raw = texture(vertex_animation_texture, vat_uv + vec2(0.0, 0.5));
vec3 decoded_normals = vec3(
remapFloat(vat_norm_raw.r, 0.0, 1.0, -1.0, 1.0),
remapFloat(vat_norm_raw.b, 0.0, 1.0, -1.0, 1.0),
remapFloat(vat_norm_raw.g, 1.0, 0.0, -1.0, 1.0)
);
NORMAL = normalize(decoded_normals);
// Calculate Tangent and Binormal from computed Normal
TANGENT = normalize(vec3(abs(NORMAL.y) + abs(NORMAL.z), 0.0, -abs(NORMAL.x)));
BINORMAL = normalize(vec3(0.0, abs(NORMAL.x) + abs(NORMAL.z), -abs(NORMAL.y)));
}
void fragment() {
// Cull Mode
if (cull_mode == 0 && !FRONT_FACING) {
discard; // Cull back faces
}
else if (cull_mode == 1 && FRONT_FACING) {
discard; // Cull front faces
}
// Albedo
ALBEDO = texture(albedo_map, UV).rgb * albedo_tint.rgb;
EMISSION = vec3(1.,1.,1.) * damage_effect;
// ORM maps (Occlusion, Roughness, Metallic) Packing
vec4 orm_tex = texture(orm_map, UV);
AO = occlusion * dot(orm_tex.rgb, occlusion_channel.rgb);
ROUGHNESS = roughness * dot(orm_tex.rgb, roughness_channel.rgb);
METALLIC = metallic * dot(orm_tex.rgb, metallic_channel.rgb);
// Specular
SPECULAR = specular;
// Normal Map
NORMAL_MAP = texture(normal_map, UV).rgb;
NORMAL_MAP_DEPTH = normal_map_scale;
}