aboutsummaryrefslogtreecommitdiff
path: root/res/shaders/framebuffer.fs
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
commit1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (patch)
tree222dfcd07a1e40716127a347bbfd7119ce3d0984 /res/shaders/framebuffer.fs
initial commit
Diffstat (limited to 'res/shaders/framebuffer.fs')
-rw-r--r--res/shaders/framebuffer.fs100
1 files changed, 100 insertions, 0 deletions
diff --git a/res/shaders/framebuffer.fs b/res/shaders/framebuffer.fs
new file mode 100644
index 0000000..b644980
--- /dev/null
+++ b/res/shaders/framebuffer.fs
@@ -0,0 +1,100 @@
+#version 420 core
+
+in vec2 _f_texture;
+
+layout(binding = 2) uniform sampler2D main_colour;
+layout(binding = 3) uniform sampler2D main_depth;
+layout(binding = 4) uniform sampler2D water_colour;
+layout(binding = 5) uniform sampler2D water_depth;
+
+layout(std140, binding = 0) uniform _u_globals {
+ mat4 proj;
+ mat4 view;
+ vec4 frustum[6];
+ float znear;
+ float zfar;
+ float xfov;
+ float yfov;
+ int time;
+ float xwindow;
+ float ywindow;
+};
+
+uniform bool _u_is_underwater;
+
+const vec3 fog_colour = vec3(0.5f, 0.7f, 0.9f);
+const vec3 underwater_fog_colour = vec3(0.137f, 0.275f, 0.694f);
+
+out vec4 _o_colour;
+
+vec4 texture_sample(const sampler2D sampler, const vec2 coord) {
+ return texture(sampler, coord);
+}
+
+float depth_sample(const sampler2D sampler, const vec2 coord) {
+ return texture(sampler, coord).r;
+}
+
+float linearise_depth(const float depth) {
+ const float z = depth * 2.0f - 1.0f; // normalised device coordinates
+ const float linear_depth =
+ (2.0 * znear * zfar) / (zfar + znear - (z * (zfar - znear)));
+ // Usually we would just return linear depth, but this is incorrect! We need
+ // to account for the additional distance of the frustum away from the
+ // center of the screen. Just some trigonomety
+
+ const float xsigma = tan(xfov * 0.5) * zfar * _f_texture.x;
+ const float ysigma = tan(yfov * 0.5) * zfar * _f_texture.y;
+ const float dist = sqrt(xsigma * xsigma + ysigma * ysigma) / zfar;
+
+ const float o_dist = linear_depth * dist;
+ return sqrt(o_dist * o_dist + linear_depth * linear_depth);
+}
+
+float get_fog_intensity(const float distance) {
+ return clamp(pow((1.0f / (zfar * 0.6f)) * distance, 3.0f), 0.0f, 1.0f);
+}
+
+float get_water_intensity(const float distance) {
+ return 1.0f - exp(0.5 * distance);
+}
+
+void main() {
+ // We recycle the coordinates of our position into our texture coordinates.
+ const vec2 coords =
+ vec2((_f_texture.x + 1.0f) / 2.0f, (_f_texture.y + 1.0f) / 2.0f);
+
+ const float main_depth = depth_sample(main_depth, coords);
+ const float main_distance = linearise_depth(main_depth);
+ const float water_depth = depth_sample(water_depth, coords);
+ const float water_distance = linearise_depth(water_depth);
+
+ _o_colour = texture_sample(main_colour, coords);
+ if (!_u_is_underwater) {
+ if (water_depth < main_depth) {
+ _o_colour =
+ vec4(mix(vec3(_o_colour.rgb),
+ texture_sample(water_colour, coords).rgb,
+ get_water_intensity(water_distance - main_distance)),
+ 1.0f);
+ }
+ _o_colour =
+ vec4(mix(vec3(_o_colour.rgb), fog_colour,
+ get_fog_intensity(min(main_distance, water_distance))),
+ 1.0f);
+ } else {
+ _o_colour = vec4(mix(vec3(_o_colour.rgb), fog_colour,
+ get_fog_intensity(main_distance)),
+ 1.0f);
+ if (water_depth < main_depth) {
+ _o_colour = vec4(mix(vec3(_o_colour.rgb),
+ texture_sample(water_colour, coords).rgb,
+ get_water_intensity(-water_distance)),
+ 1.0f);
+ } else {
+ _o_colour = vec4(mix(vec3(_o_colour.rgb), underwater_fog_colour,
+ get_water_intensity(-main_distance)),
+ 1.0f);
+ }
+ }
+}