So, I'm currently working on a water shader for some boat stuff, and you can't have boats without buoyancy. I've got an idea of how I can implement it, but for it to work I need to either now when an object is touching the water, or I need the height of a vertex in the given location.
I'm quite new to shaders in Godot, so I have no idea of how to get said information. I know it's possible to make variables uniform so that I can access them in a script, but I can't really see a way to use that.
Also, here's my shader if it's needed...
shader_type spatial;
render_mode cull_back, diffuse_toon, specular_toon, depth_draw_always, blend_mix;
const float PI = 3.14159265359;
uniform vec4 _WaterColor : hint_color = vec4(0.1, 0.3, 0.5, 1.0);
uniform vec4 _FoamColor : hint_color = vec4(1.0);
uniform float _FoamStrength : hint_range(0, 10) = 1;
uniform float _Speed = 0.25;
// Direction, steepness, wavelength
uniform vec4 _WaveA = vec4(1, 0, 0.5, 10);
uniform vec4 _WaveB = vec4(0, 1, 0.25, 20);
uniform vec4 _WaveC = vec4(1, 1, 0.15, 10);
uniform float _Metallic : hint_range(0, 1);
uniform float _Roughness = 0.01;
uniform float _Rim = 0.2;
uniform float _PlaneScale = 10;
uniform float _NoiseSpeed = 0.1;
uniform float _HeightScale = 0.5;
uniform float _NormalStrength = 1.25;
uniform sampler2D _FoamNoise;
uniform sampler2D _Noise;
uniform sampler2D _NormalMap;
varying vec2 tex_position;
varying float vertex_height;
vec3 GerstnerWave(vec4 wave, vec3 v, inout vec3 tangent, inout vec3 binormal, float _Time) {
float steepness = wave.z;
float wavelength = wave.w;
float k = 2.0 * PI / wavelength;
float c = sqrt(9.8 / k) * _Speed;
vec2 d = normalize(wave.xy);
float f = k * (dot(d, v.xz) + c * _Time);
float a = steepness / k;
tangent += vec3 (
-d.x * d.x * (steepness * sin(f)),
d.x * (steepness * cos(f)),
-d.x * d.y * (steepness * sin(f))
);
binormal += vec3 (
-d.x * d.y * (steepness * sin(f)),
d.y * (steepness * cos(f)),
-d.y * d.y * (steepness * sin(f))
);
return vec3 (
d.x * (a * cos(f)),
a * sin(f),
d.y * (a * cos(f))
);
}
float calc_height(vec2 position, float time) {
vec2 offset = _NoiseSpeed * cos(position + time);
return texture(_Noise, (position / _PlaneScale) - offset).x;
}
void vertex() {
vec3 gridPoint = VERTEX.xyz;
vec3 tangent = vec3(1, 0, 0);
vec3 binormal = vec3(0, 0, 1);
vec3 v = gridPoint;
v += GerstnerWave(_WaveA, gridPoint, tangent, binormal, TIME);
v += GerstnerWave(_WaveB, gridPoint, tangent, binormal, TIME);
v += GerstnerWave(_WaveC, gridPoint, tangent, binormal, TIME);
tex_position = VERTEX.xz / 2.0 + 0.5;
vec2 pos = VERTEX.xz;
float h = calc_height(pos, TIME) * _HeightScale;
vertex_height = h;
v.y += h;
vec3 normal = normalize(cross(binormal, tangent));
VERTEX.xyz = v;
NORMAL = normal;
}
void fragment() {
float fresnel = sqrt(1.0 - dot(NORMAL, VIEW));
vec3 water_color = _WaterColor.rgb + (0.1 * fresnel);
float depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
vec3 ndc = vec3(SCREEN_UV, depth) * 2.0 - 1.0;
vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
view.xyz /= view.w;
float linear_depth = -view.z;
if (linear_depth + VERTEX.z < vertex_height-0.1) {
vec2 offset = _PlaneScale * cos(tex_position + TIME);
float foam_noise = clamp(pow(texture(_FoamNoise, (tex_position / _NoiseSpeed) - offset).r, 30.0) * 40.0, 0.0, 0.2);
float foam_mix = clamp(pow((1.0-(depth + VERTEX.z) + foam_noise), _FoamStrength*10.0) * foam_noise * 0.4, 0.0, 1.0);
water_color = mix(water_color, _FoamColor.rgb, foam_mix);
}
ALBEDO = water_color;
ALPHA = _WaterColor.a;
NORMALMAP = texture(_NormalMap, tex_position).xyz;
NORMALMAP_DEPTH = _NormalStrength;
METALLIC = _Metallic;
ROUGHNESS = _Roughness * (1.0 - fresnel);
RIM = _Rim;
}
Now, I know I could (in theory) recreate all the math in a script and calculate it from that, but if was lazy then I would be making this post.
Also I want to emphasize that I'm fairly new to Godot, and therefore I could be tackling this problem in a different way.
And of course, thank you beforehand for taking your time to read my post.