Guest User

Water shader

a guest
Sep 27th, 2025
51
0
3 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.13 KB | Source Code | 0 0
  1. shader_type spatial;
  2. render_mode blend_mix;
  3.  
  4. const float wave_amplitude = 0.3;
  5. const float wave_frequency = 0.15;
  6. const float max_sea_height = 0.0;
  7. const float wave_time_scale = 0.015;
  8.  
  9. uniform sampler2D sea_texture : repeat_disable, source_color;
  10. uniform float water_alpha: hint_range(0.0, 1.0) = 0.5;
  11. uniform vec3 fresnel_sea_colour : source_color;
  12. uniform sampler2D foam_texture;
  13. uniform sampler2D texture_nm_0;
  14. uniform sampler2D texture_nm_1;
  15. uniform vec4 error_colour : source_color = vec4(1.0, 0, 0, 1);
  16. varying float vertex_y;
  17.  
  18. float wave_shaping_function(float x) {
  19. return pow(abs(sin(PI*x/2.0)), 2.5);
  20. }
  21.  
  22. // Time progression should be liner to ensure the wave is shaped correctly
  23. float get_wave_time_component(float time_offset, vec2 mapwide_uv) {
  24. float map_pos_contribution = ((1.0/cos(mapwide_uv.x)) + sin(mapwide_uv.y)) * 20.0;
  25. float time_contribution = (TIME+time_offset)*wave_frequency;
  26. // Need this to range from -1 to +1.
  27. // The 1 starts us there
  28. // The mod restricts us from 0.0 to 2.0 taking the range from -1.0 to 1.0
  29. return 1.0 -mod(time_contribution + map_pos_contribution, 2.0);
  30. }
  31.  
  32. float get_wave_height(float time_offset, vec2 mapwide_uv) {
  33. float x = get_wave_time_component(time_offset, mapwide_uv);
  34. return wave_shaping_function(x)*wave_amplitude;
  35. }
  36.  
  37. void vertex() {
  38. vertex_y = CUSTOM2.r;
  39.  
  40. VERTEX.y = max_sea_height;
  41. NORMAL = vec3(0.0, 1.0, 0.0);
  42. }
  43.  
  44. float fresnel(float amount, vec3 normal, vec3 view) {
  45. return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0)), amount);
  46. }
  47.  
  48. float get_front_wave_height(vec2 mapwide_uv) {
  49. return get_wave_height(0.2/wave_frequency, mapwide_uv);
  50. }
  51.  
  52. float get_rear_wave_height(vec2 mapwide_uv) {
  53. return get_wave_height(-0.2/wave_frequency, mapwide_uv);
  54. }
  55.  
  56. bool vertex_height_correct_for_foam(float y, vec2 mapwide_uv) {
  57. float wave_midpoint_height = max_sea_height-wave_amplitude;
  58. float front_wave_height = get_front_wave_height(mapwide_uv);
  59. float rear_wave_height = get_rear_wave_height(mapwide_uv);
  60.  
  61. bool vertex_is_in_wave_region = (y > wave_midpoint_height+rear_wave_height) && (y < wave_midpoint_height+front_wave_height);
  62.  
  63. return vertex_is_in_wave_region;
  64. }
  65.  
  66. float get_position_within_wave(float y, vec2 mapwide_uv) {
  67. float front_wave_height = get_front_wave_height(mapwide_uv);
  68. float rear_wave_height = get_rear_wave_height(mapwide_uv);
  69. float relative_pos = abs(abs(y)-rear_wave_height) / (front_wave_height-rear_wave_height);
  70. return relative_pos;
  71. }
  72.  
  73. vec3 get_wave_colour(float y, vec2 mapwide_uv, vec3 water_surface_colour) {
  74. float current_height = get_wave_height(0.0, mapwide_uv);
  75. vec2 time_sample_point = current_height*vec2(0.5, 0.5)*5.0; // Since height has a time component, this works
  76. vec2 sample_point = mapwide_uv*500.0+time_sample_point;
  77. float water_colour_bias = 1.2*get_position_within_wave(y, mapwide_uv);
  78. float foam_factor = clamp(texture(foam_texture, sample_point).r-water_colour_bias, 0.0, 1.0);
  79. vec3 foam_white = vec3(1, 0.960784, 0.933333);
  80. return mix(water_surface_colour, foam_white, foam_factor);
  81. }
  82.  
  83. void fragment() {
  84. vec2 mapwide_uv = UV; // Goes from 0->1 across the whole map
  85.  
  86. if (vertex_y <= 0.0) {
  87. // Waves via normal maps
  88. vec2 wave_motion_0 = vec2(0.2, 0.0);
  89. vec2 wave_motion_1 = vec2(0.0, 0.2);
  90. vec2 nm0_uv = (mapwide_uv*10.0) + (TIME*wave_motion_0*wave_time_scale);
  91. vec2 nm1_uv = (mapwide_uv*10.0) + (TIME*wave_motion_1*wave_time_scale);
  92. vec3 nm0 = texture(texture_nm_0, nm0_uv).rgb;
  93. vec3 nm1 = texture(texture_nm_1, nm1_uv).rgb;
  94. NORMAL_MAP = mix(nm0, nm1, 0.5);
  95.  
  96. // Alpha being used to pretend its depth
  97. ALPHA = water_alpha;
  98.  
  99. vec3 albd;
  100.  
  101. // Actual water colour
  102. // Allow water colour to only change once we pass the visible depth
  103. float fresnel_f = fresnel(5.0, NORMAL, VIEW);
  104. vec3 water_colour = texture(sea_texture, vec2(0.0, 0.0)).rgb;
  105. vec3 surface_colour = mix(water_colour, fresnel_sea_colour, fresnel_f);
  106. albd = surface_colour;
  107.  
  108. // Foam on edges of waves
  109. if (vertex_height_correct_for_foam(vertex_y, mapwide_uv)) {
  110. albd = get_wave_colour(vertex_y, mapwide_uv, surface_colour);
  111. }
  112. ALBEDO = albd;
  113. } else {
  114. discard;
  115. }
  116. }
Advertisement
Add Comment
Please, Sign In to add comment