#version 450
// Rusting shader packs, version 1: the cloud layer. A pack's `clouds`
// program with `"scale": 0.5` or `0.25` runs here at that fraction of the
// screen instead of inline in sky.frag; sky.frag then puts the layer over
// the sky before fog: `sky * layer.a + layer.rgb`. Fields are only ever
// added at the end of CloudLayerInput.
#define RUSTING_CLOUD_LAYER 1
layout(location = 0) out vec4 out_layer;
// The scene's ambient hemisphere, for sky_lut_lod without a map.
layout(push_constant) uniform CloudLayerCamera {
vec4 ambient;
vec4 ground_ambient;
} camera;
// The scene's shadow upload, laid out as in sky.frag; only `environment`
// and `sky` are read.
layout(set = 0, binding = 1) readonly buffer Shadow {
vec4 environment;
vec4 scene_color;
vec4 viewport;
vec4 probes[8];
mat4 inverse_view_projection;
vec4 fog;
vec4 fog_shape;
vec4 ambient_occlusion;
mat4 cascades[6];
vec4 cascade_far;
vec4 cascade_forward;
vec4 cascade_info;
vec4 cluster_view;
vec4 cluster_depth;
vec4 fog_shafts;
mat4 fog_volumes[8];
vec4 fog_volume_colors[8];
vec4 sky[4];
} shadow;
layout(set = 0, binding = 2) uniform sampler2D environment_map;
layout(set = 0, binding = 3) uniform sampler2D cloud_layer_previous;
// Tiling 3D cloud noise, 64^3 RGBA8, repeat and linear (cloud_layer.rs).
layout(set = 0, binding = 4) uniform sampler3D cloud_noise_map;
#include "frame.glsl"
#include "sky_access.glsl"
// What the engine knows about the layer texel before the hook runs.
struct CloudLayerInput {
// Unit world-space direction through the texel centre.
vec3 direction;
// Seconds since start, the same as SkyInput.time.
float time;
// Texel centre, 0..1, oriented as composite uv.
vec2 uv;
// 1 / layer size in texels.
vec2 texel;
};
// Last frame's layer at `uv`, bilinear and clamped; vec4(0, 0, 0, 1) on
// the first frame and after a resize.
vec4 cloud_layer_history(vec2 uv) {
return textureLod(cloud_layer_previous, clamp(uv, 0.0, 1.0), 0.0);
}
// Where `direction`, a point at infinity, was in last frame's layer: the
// camera's rotation only. Off 0..1 when it was behind or off screen.
vec2 cloud_layer_previous_uv(vec3 direction) {
vec4 clip = frame.previous_view_projection * vec4(direction, 0.0);
if (clip.w <= 1e-6) {
return vec2(-1.0);
}
return clip.xy / clip.w * 0.5 + 0.5;
}
// The tiling cloud noise at `p`, one tile per unit: r Perlin-Worley (the
// base shape of Nubis-style clouds), g, b, a Worley fbm with 4, 8 and 16
// cells per tile, all 0..1, trilinear.
#define RUSTING_CLOUD_NOISE 1
vec4 cloud_noise(vec3 p) {
return textureLod(cloud_noise_map, p, 0.0);
}
#include "cloud_layer_shader.glsl"
void main() {
vec2 texel = 1.0 / vec2(textureSize(cloud_layer_previous, 0));
vec2 uv = gl_FragCoord.xy * texel;
vec2 ndc = uv * 2.0 - 1.0;
vec4 near = frame.inverse_view * (frame.inverse_projection * vec4(ndc, 0.0, 1.0));
vec4 far = frame.inverse_view * (frame.inverse_projection * vec4(ndc, 0.5, 1.0));
vec3 direction = normalize(far.xyz / far.w - near.xyz / near.w);
vec4 layer = vec4(0.0, 0.0, 0.0, 1.0);
cloud_layer(CloudLayerInput(direction, camera.ambient.w, uv, texel), layer);
out_layer = vec4(max(layer.rgb, vec3(0.0)), clamp(layer.a, 0.0, 1.0));
}