Skip to content

Instantly share code, notes, and snippets.

@PurpBatBoi
Last active October 31, 2025 19:41
Show Gist options
  • Select an option

  • Save PurpBatBoi/5646421e8e9cf6fc6819ad0337d79192 to your computer and use it in GitHub Desktop.

Select an option

Save PurpBatBoi/5646421e8e9cf6fc6819ad0337d79192 to your computer and use it in GitHub Desktop.
created this shader that mimics the water rendering in super mario sunshine
shader_type spatial;
render_mode unshaded, blend_add, depth_draw_always;
uniform sampler2D texture_lod_0 : hint_default_black;
uniform sampler2D texture_lod_1;
uniform sampler2D texture_lod_2;
uniform sampler2D texture_lod_3;
uniform float lod1_distance : hint_range(0.1, 50, 0.05) = 5.0;
uniform float lod2_distance : hint_range(0.1, 100, 0.05) = 20.0;
uniform float lod3_distance : hint_range(0.1, 150, 0.05) = 50.0;
uniform float lod4_distance : hint_range(0.1, 300, 0.05) = 100.0;
uniform float blend_amount : hint_range(0.0, 20.0) = 2.0;
uniform float lod2_blend_softness : hint_range(0.0, 50.0, 0.1) = 10.0;
uniform float highlight_intensity : hint_range(0.0, 10.0, 0.1) = 1.5;
uniform float highlight_start_distance : hint_range(0.1, 150.0, 0.1) = 25.0;
uniform float highlight_end_distance : hint_range(0.1, 200.0, 0.1) = 45.0;
uniform float highlight_softness : hint_range(0.1, 50.0, 0.1) = 10.0;
uniform float highlight_clip_min : hint_range(0.0, 1.0, 0.01) = 0.0;
uniform float highlight_clip_max : hint_range(0.0, 1.0, 0.01) = 1.0;
uniform float top_down_blend_bias : hint_range(0.1, 4.0, 0.1) = 1.0;
uniform float brightness_min : hint_range(0.0, 1.0, 0.01) = 0.13;
uniform float Texture_Scale_1;
uniform vec2 Texture_Offset_1 = vec2(0.0);
uniform vec2 Texture_Pan_1 = vec2(0.0);
uniform float Texture_Scale_2;
uniform vec2 Texture_Offset_2 = vec2(0.0);
uniform vec2 Texture_Pan_2 = vec2(0.0);
uniform float Texture_Scale_H = 0.8;
uniform vec2 Texture_Offset_H = vec2(0.0);
uniform vec2 Texture_Pan_H = vec2(0.0, 0.05);
uniform float Texture_Scale_HM = 1.5;
uniform vec2 Texture_Offset_HM = vec2(0.0);
uniform vec2 Texture_Pan_HM = vec2(0.05, 0.0); // Different pan speed for variation
varying vec3 world_pos;
vec2 TransformTexture(vec2 uv, float TextureScale, vec2 TextureOffset, vec2 TexturePan){
return uv * TextureScale + TextureOffset + (TexturePan * TIME);
}
float blend_lod(float base_color, float next_lod, float start_dist, float end_dist, float camera_dist) {
float blend_factor = smoothstep(start_dist, end_dist, camera_dist);
return mix(base_color, next_lod, blend_factor);
}
float calculate_band_factor(float start_dist, float end_dist, float softness, float camera_dist) {
if (start_dist >= end_dist) return 0.0;
float fade_in = smoothstep(start_dist, start_dist + softness, camera_dist);
float fade_out = 1.0 - smoothstep(end_dist - softness, end_dist, camera_dist);
return fade_in * fade_out;
}
void vertex() {
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment() {
float dist_radial = distance(world_pos, CAMERA_POSITION_WORLD);
vec3 camera_forward = normalize((inverse(VIEW_MATRIX) * vec4(0.0, 0.0, -1.0, 0.0)).xyz);
float dist_linear = dot(world_pos - CAMERA_POSITION_WORLD, camera_forward);
vec3 down_vec = vec3(0.0, -1.0, 0.0);
float top_down_factor = max(0.0, dot(camera_forward, down_vec));
top_down_factor = pow(top_down_factor, top_down_blend_bias);
float dist = mix(dist_radial, dist_linear, top_down_factor);
vec2 UV_transformed_1 = TransformTexture(UV, Texture_Scale_1, Texture_Offset_1, Texture_Pan_1);
vec2 UV_transformed_2 = TransformTexture(UV, Texture_Scale_2, Texture_Offset_2, Texture_Pan_2);
vec4 color_lod0 = texture(texture_lod_0, UV);
float color_lod1 = texture(texture_lod_1, UV_transformed_1).r;
float color_lod1_alt = texture(texture_lod_1, UV_transformed_2).r;
float color_lod2 = texture(texture_lod_2, UV_transformed_1).r;
float color_lod2_alt = texture(texture_lod_2, UV_transformed_2).r;
float color_lod3 = texture(texture_lod_3, UV_transformed_1).r;
float color_lod3_alt = texture(texture_lod_3, UV_transformed_2).r;
float color_lod4 = color_lod0.r;
float col_mix_1 = color_lod1 - color_lod1_alt;
float col_mix_2 = color_lod2 - color_lod2_alt + 0.5;
float col_mix_3 = color_lod3 - color_lod3_alt;
float blended_color = blend_lod(color_lod0.r, col_mix_1, lod1_distance - blend_amount, lod1_distance, dist);
blended_color = blend_lod(blended_color, col_mix_2, lod2_distance - blend_amount, lod2_distance, dist);
blended_color = blend_lod(blended_color, col_mix_3, lod3_distance - lod2_blend_softness, lod3_distance, dist);
float final_base_alpha = blend_lod(blended_color, color_lod4, lod4_distance - blend_amount, lod4_distance, dist);
if (final_base_alpha > brightness_min && final_base_alpha < 2.0) {
final_base_alpha = 0.0;
}
float highlight_band_intensity = calculate_band_factor(highlight_start_distance, highlight_end_distance, highlight_softness, dist);
vec2 UV_transformed_H = TransformTexture(UV, Texture_Scale_H, Texture_Offset_H, Texture_Pan_H);
float highlight_mask_primary = texture(texture_lod_1, UV_transformed_H).r;
vec2 UV_transformed_HM = TransformTexture(UV, Texture_Scale_HM, Texture_Offset_HM, Texture_Pan_HM);
float highlight_mask_modulator = texture(texture_lod_2, UV_transformed_HM).r;
float combined_raw_mask = highlight_mask_primary * highlight_mask_modulator;
float final_processed_mask = smoothstep(highlight_clip_min, highlight_clip_max, combined_raw_mask);
float highlight_value = final_processed_mask * highlight_band_intensity * highlight_intensity;
float final_alpha = final_base_alpha + highlight_value;
ALBEDO = vec3(final_alpha);
ALPHA = final_alpha;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment