Created
June 7, 2023 17:42
-
-
Save HungryProton/148d7da76854b342a9f2f34d9c099f6f to your computer and use it in GitHub Desktop.
Under water shader with caustics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
shader_type spatial; | |
uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; | |
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; | |
uniform float v_depth_offset = 0.0; | |
uniform float v_depth_fade = 1.0; | |
uniform sampler2D underwater_color : repeat_disable; | |
uniform sampler2D caustics_texture : hint_default_black; | |
uniform float caustics_speed = 1.0; | |
uniform float caustics_scale = 1.0; | |
uniform float caustics_power : hint_range(0.0, 4.0) = 1.0; | |
uniform float caustics_strength : hint_range(0.0, 32.0) = 1.0; | |
varying vec3 scene_world_position; | |
varying vec2 uv1; | |
varying vec2 uv2; | |
vec3 position_from_depth(vec2 uv, mat4 inv_view, mat4 inv_proj) { | |
float depth_sample = texture(depth_texture, uv).x; | |
vec3 ndc = vec3(uv * 2.0 - 1.0, depth_sample); | |
vec4 scene_world = inv_view * inv_proj * vec4(ndc, 1.0); | |
return scene_world.xyz / scene_world.w; | |
} | |
// Source: https://github.com/paddy-exe/Godot-RealTimeCaustics | |
mat3 makeRotationDir(vec3 direction, vec3 up){ | |
mat3 rm; | |
vec3 xaxis = cross(up, direction); | |
xaxis = normalize(xaxis); | |
vec3 yaxis = cross(direction, xaxis); | |
yaxis = normalize(yaxis); | |
rm[0].x = xaxis.x; | |
rm[0].y = yaxis.x; | |
rm[0].z = direction.x; | |
rm[1].x = xaxis.y; | |
rm[1].y = yaxis.y; | |
rm[1].z = direction.y; | |
rm[2].x = xaxis.z; | |
rm[2].y = yaxis.z; | |
rm[2].z = direction.z; | |
return rm; | |
} | |
void vertex() { | |
POSITION = vec4(VERTEX, 1.0); | |
} | |
void fragment() { | |
// Depth | |
scene_world_position = position_from_depth(SCREEN_UV, INV_VIEW_MATRIX, INV_PROJECTION_MATRIX); | |
// Get the vertical depth (in world coordinates) | |
float v_depth = scene_world_position.y + v_depth_offset; | |
v_depth /= v_depth_fade; | |
v_depth = clamp(1.0 - v_depth, 0.0, 1.0); | |
// Sample the gradient color and the original color | |
vec4 color = texture(underwater_color, vec2(v_depth, 0.5)); | |
vec3 screen_color = texture(screen_texture, SCREEN_UV).rgb; | |
// Mix with the original screen color, based on the gradient alpha value | |
color = mix(vec4(screen_color, 1.0), color, color.a); | |
ALBEDO = color.rgb; | |
} | |
void light() { | |
// Two values to know if we're dealing with directional lights or point lights | |
float is_directional_light = float(LIGHT_IS_DIRECTIONAL); | |
float is_point_light = 1.0 - is_directional_light; | |
// Diffuse | |
DIFFUSE_LIGHT += ALBEDO * is_directional_light; | |
// Caustics | |
// Get the light vector in world position // TODO : not sure about the maths | |
vec3 world_light = (INV_VIEW_MATRIX * vec4(LIGHT, 0.0)).xyz; | |
mat3 lrm = makeRotationDir(world_light, vec3(0.0, 1.0, 0.0)); | |
mat4 t = mat4(lrm); | |
t[3].xyz = scene_world_position; | |
// Get the light projected world UV | |
vec2 uv = (t * vec4(scene_world_position, 1.0)).xz; | |
// Get two samples from the caustic texture, scrolling in different directions | |
vec2 caustic_uv1 = uv * (1.0 / caustics_scale) + TIME * 0.75 * caustics_speed; | |
vec2 caustic_uv2 = uv * (-1.0 / (caustics_scale * 0.90)) + TIME * caustics_speed; | |
vec3 c1 = texture(caustics_texture, caustic_uv1).rgb; | |
vec3 c2 = texture(caustics_texture, caustic_uv2).rgb; | |
c1 = pow(c1, vec3(caustics_power)); | |
c2 = pow(c2, vec3(caustics_power)); | |
vec3 c = min(c1, c2) * caustics_strength * ALBEDO; | |
DIFFUSE_LIGHT += c * is_directional_light; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment