Godot Version
4.4-stable
Question
I’ve been trying a bunch of “tutorials” and searching everywhere but only find dead ends. I have a half-competent attempt I found digging deep. It doesn’t work as the reference.
shader_type spatial;
//render_mode depth_prepass_alpha, depth_draw_opaque;
render_mode diffuse_burley;
uniform float time_scale = 1.0;
uniform float pivot = 1.0;
uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_nearest, repeat_enable;
uniform float wrap : hint_range(-2.0f, 2.0f) = 0.0f;
uniform float steepness : hint_range(1.0f, 8.0f) = 1.0f;
uniform int cuts : hint_range(1, 8) = 3;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_nearest;
varying vec3 instance_origin;
varying float random_value;
void vertex() {
random_value = INSTANCE_CUSTOM.z;
float time = (TIME * (0.5 + INSTANCE_CUSTOM.y) * time_scale) + (6.28318 * INSTANCE_CUSTOM.x);
float pivot_angle = cos(time) * 0.1 * pivot;
mat2 rotation_matrix = mat2(vec2(cos(pivot_angle), -sin(pivot_angle)), vec2(sin(pivot_angle), cos(pivot_angle)));
instance_origin = MODELVIEW_MATRIX[3].xyz;
//billboarding
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0],INV_VIEW_MATRIX[1],INV_VIEW_MATRIX[2],MODEL_MATRIX[3]);
VERTEX.xz = rotation_matrix * VERTEX.xz;
NORMAL = vec3(0.0, 1.0, 0.0);
}
void fragment() {
vec2 base_uv = UV;
LIGHT_VERTEX = instance_origin;
//vec4 original_color = texture(SCREEN_TEXTURE, SCREEN_UV);
vec4 albedo_tex = texture(texture_albedo, base_uv);
ALBEDO = albedo.rgb * albedo_tex.rgb;
ALPHA *= albedo.a * albedo_tex.a;
}
void light() {
float attenuation = ATTENUATION;
float NdotL = dot(NORMAL, LIGHT);
float diffuse_amount = NdotL + (attenuation - 1.0) + wrap;
diffuse_amount *= steepness;
float cuts_inv = 1.0f / float(cuts);
float diffuse_stepped = clamp(diffuse_amount + mod(1.0f - diffuse_amount, cuts_inv), 0.0f, 1.0f);
// Apply diffuse result
vec3 diffuse = ALBEDO.rgb * LIGHT_COLOR / PI;
diffuse *= diffuse_stepped;
DIFFUSE_LIGHT += diffuse;
}
this is the shader I’m currently using. It works, but colors don’t fully match.
shader_type spatial;
//render_mode ambient_light_disabled;
//const float PI = 3.1415926536f;
uniform vec4 albedo : source_color = vec4(1.0f);
uniform sampler2D albedo_texture : source_color;
uniform bool clamp_diffuse_to_max = false;
uniform int cuts : hint_range(1, 8) = 3;
uniform float wrap : hint_range(-2.0f, 2.0f) = 0.0f;
uniform float steepness : hint_range(1.0f, 8.0f) = 1.0f;
uniform bool use_attenuation = true;
uniform bool use_specular = true;
uniform float specular_strength : hint_range(0.0f, 1.0f) = 1.0f;
uniform float specular_shininess : hint_range(0.0f, 32.0f) = 16.0f;
uniform sampler2D specular_map : source_color;
uniform bool use_rim = true;
uniform float rim_width : hint_range(0.0f, 16.0f) = 8.0f;
uniform vec4 rim_color : source_color = vec4(1.0f);
uniform bool use_ramp = false;
uniform sampler2D ramp : source_color;
uniform bool use_borders = false;
uniform float border_width = 0.01f;
varying vec3 vertex_pos;
varying vec3 normal;
float split_specular(float specular) {
return step(0.5f, specular);
}
void vertex() {
vertex_pos = VERTEX;
normal = NORMAL;
}
void fragment() {
ALBEDO = albedo.rgb * texture(albedo_texture, UV).rgb;
}
void light() {
// Attenuation.
float attenuation = 1.0f;
if (use_attenuation) {
attenuation = ATTENUATION;
}
// Diffuse lighting.
float NdotL = dot(NORMAL, LIGHT);
float diffuse_amount = NdotL + (attenuation - 1.0) + wrap;
//float diffuse_amount = NdotL * attenuation + wrap;
diffuse_amount *= steepness;
float cuts_inv = 1.0f / float(cuts);
float diffuse_stepped = clamp(diffuse_amount + mod(1.0f - diffuse_amount, cuts_inv), 0.0f, 1.0f);
// Calculate borders.
float border = 0.0f;
if (use_borders) {
float corr_border_width = length(cross(NORMAL, LIGHT)) * border_width * steepness;
border = step(diffuse_stepped - corr_border_width, diffuse_amount)
- step(1.0 - corr_border_width, diffuse_amount);
}
// Apply diffuse result to different styles.
vec3 diffuse = ALBEDO.rgb * LIGHT_COLOR / PI;
if (use_ramp) {
diffuse *= texture(ramp, vec2(diffuse_stepped * (1.0f - border), 0.0f)).rgb;
} else {
diffuse *= diffuse_stepped * (1.0f - border);
}
if (clamp_diffuse_to_max) {
// Clamp diffuse to max for multiple light sources.
DIFFUSE_LIGHT = max(DIFFUSE_LIGHT, diffuse);
} else {
DIFFUSE_LIGHT += diffuse;
}
// Specular lighting.
if (use_specular) {
vec3 H = normalize(LIGHT + VIEW);
float NdotH = dot(NORMAL, H);
float specular_amount = max(pow(NdotH, specular_shininess*specular_shininess), 0.0f)
* texture(specular_map, UV).r
* attenuation;
specular_amount = split_specular(specular_amount);
SPECULAR_LIGHT += specular_strength * specular_amount * LIGHT_COLOR;
}
// Simple rim lighting.
if (use_rim) {
float NdotV = dot(NORMAL, VIEW);
float rim_light = pow(1.0 - NdotV, rim_width);
DIFFUSE_LIGHT += rim_light * rim_color.rgb * rim_color.a * LIGHT_COLOR / PI;
}
}
I’m using this shader for my ground. Both have the same exact green color as the Albedo. The grass sprite is a simple white shape. I know very little shader logic, enough to copy and paste and have an idea of what’s happening to make very small changes.
This are my references:
I’ve tried everything, but all codes I find around, all changes I try to make, all still lacks and all still has some really annoying edge case. I’m kinda desperate as I don’t know what to do, since none of the sources really explain or show exactly how the effect is done, and nothing I find online produces the same result.





