diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd/shaders')
12 files changed, 434 insertions, 201 deletions
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl index e33b3face9..4a40584e16 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl @@ -101,7 +101,7 @@ void main() { offset += 1; } else { instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3)); - offser += 4; + offset += 4; } color *= instance_color; diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index e565bd8e3d..355a2b9d75 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -58,12 +58,20 @@ layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buff layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #endif +#ifdef MODE_GAUSSIAN_GLOW +shared vec4 local_cache[256]; +shared vec4 temp_cache[128]; +#endif + void main() { // Pixel being shaded ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + +#ifndef MODE_GAUSSIAN_GLOW // Glow needs the extra threads if (any(greaterThanEqual(pos, params.section.zw))) { //too large, do nothing return; } +#endif #ifdef MODE_MIPMAP @@ -104,70 +112,69 @@ void main() { #ifdef MODE_GAUSSIAN_GLOW - //Glow uses larger sigma 1 for a more rounded blur effect + // First pass copy texture into 16x16 local memory for every 8x8 thread block + vec2 quad_center_uv = clamp(vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.5) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); + uint dest_index = gl_LocalInvocationID.x * 2 + gl_LocalInvocationID.y * 2 * 16; + + if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { + vec2 quad_offset_uv = clamp((vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.0)) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); -#define GLOW_ADD(m_ofs, m_mult) \ - { \ - ivec2 ofs = base_pos + m_ofs; \ - if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ - color += texelFetch(source_color, ofs, 0) * m_mult; \ - } \ + local_cache[dest_index] = (textureLod(source_color, quad_center_uv, 0) + textureLod(source_color, quad_offset_uv, 0)) * 0.5; + local_cache[dest_index + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.z, 0.0), 0)) * 0.5; + local_cache[dest_index + 16] = (textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0) + textureLod(source_color, quad_offset_uv + vec2(0.0, 1.0 / params.section.w), 0)) * 0.5; + local_cache[dest_index + 16 + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.zw), 0)) * 0.5; + } else { + local_cache[dest_index] = textureLod(source_color, quad_center_uv, 0); + local_cache[dest_index + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); + local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); + local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); } + memoryBarrierShared(); + barrier(); + + // Horizontal pass. Needs to copy into 8x16 chunk of local memory so vertical pass has full resolution + uint read_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 32 + 4; + vec4 color_top = vec4(0.0); + color_top += local_cache[read_index] * 0.174938; + color_top += local_cache[read_index + 1] * 0.165569; + color_top += local_cache[read_index + 2] * 0.140367; + color_top += local_cache[read_index + 3] * 0.106595; + color_top += local_cache[read_index - 1] * 0.165569; + color_top += local_cache[read_index - 2] * 0.140367; + color_top += local_cache[read_index - 3] * 0.106595; + + vec4 color_bottom = vec4(0.0); + color_bottom += local_cache[read_index + 16] * 0.174938; + color_bottom += local_cache[read_index + 1 + 16] * 0.165569; + color_bottom += local_cache[read_index + 2 + 16] * 0.140367; + color_bottom += local_cache[read_index + 3 + 16] * 0.106595; + color_bottom += local_cache[read_index - 1 + 16] * 0.165569; + color_bottom += local_cache[read_index - 2 + 16] * 0.140367; + color_bottom += local_cache[read_index - 3 + 16] * 0.106595; + + // rotate samples to take advantage of cache coherency + uint write_index = gl_LocalInvocationID.y * 2 + gl_LocalInvocationID.x * 16; + + temp_cache[write_index] = color_top; + temp_cache[write_index + 1] = color_bottom; + + memoryBarrierShared(); + barrier(); + + // Vertical pass + uint index = gl_LocalInvocationID.y + gl_LocalInvocationID.x * 16 + 4; vec4 color = vec4(0.0); - if (bool(params.flags & FLAG_HORIZONTAL)) { - ivec2 base_pos = ((pos + params.section.xy) << 1) + ivec2(1); - ivec2 section_begin = params.section.xy << 1; - ivec2 section_end = section_begin + (params.section.zw << 1); - - if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { - //Sample from two lines to capture single pixel features - GLOW_ADD(ivec2(0, 0), 0.152781); - GLOW_ADD(ivec2(1, 0), 0.144599); - GLOW_ADD(ivec2(2, 0), 0.122589); - GLOW_ADD(ivec2(3, 0), 0.093095); - GLOW_ADD(ivec2(4, 0), 0.063327); - GLOW_ADD(ivec2(-1, 0), 0.144599); - GLOW_ADD(ivec2(-2, 0), 0.122589); - GLOW_ADD(ivec2(-3, 0), 0.093095); - GLOW_ADD(ivec2(-4, 0), 0.063327); - - GLOW_ADD(ivec2(0, 1), 0.152781); - GLOW_ADD(ivec2(1, 1), 0.144599); - GLOW_ADD(ivec2(2, 1), 0.122589); - GLOW_ADD(ivec2(3, 1), 0.093095); - GLOW_ADD(ivec2(4, 1), 0.063327); - GLOW_ADD(ivec2(-1, 1), 0.144599); - GLOW_ADD(ivec2(-2, 1), 0.122589); - GLOW_ADD(ivec2(-3, 1), 0.093095); - GLOW_ADD(ivec2(-4, 1), 0.063327); - color *= 0.5; - } else { - GLOW_ADD(ivec2(0, 0), 0.174938); - GLOW_ADD(ivec2(1, 0), 0.165569); - GLOW_ADD(ivec2(2, 0), 0.140367); - GLOW_ADD(ivec2(3, 0), 0.106595); - GLOW_ADD(ivec2(-1, 0), 0.165569); - GLOW_ADD(ivec2(-2, 0), 0.140367); - GLOW_ADD(ivec2(-3, 0), 0.106595); - } - - color *= params.glow_strength; - } else { - ivec2 base_pos = pos + params.section.xy; - ivec2 section_begin = params.section.xy; - ivec2 section_end = section_begin + params.section.zw; - - GLOW_ADD(ivec2(0, 0), 0.288713); - GLOW_ADD(ivec2(0, 1), 0.233062); - GLOW_ADD(ivec2(0, 2), 0.122581); - GLOW_ADD(ivec2(0, -1), 0.233062); - GLOW_ADD(ivec2(0, -2), 0.122581); - color *= params.glow_strength; - } + color += temp_cache[index] * 0.174938; + color += temp_cache[index + 1] * 0.165569; + color += temp_cache[index + 2] * 0.140367; + color += temp_cache[index + 3] * 0.106595; + color += temp_cache[index - 1] * 0.165569; + color += temp_cache[index - 2] * 0.140367; + color += temp_cache[index - 3] * 0.106595; -#undef GLOW_ADD + color *= params.glow_strength; if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { #ifdef GLOW_USE_AUTO_EXPOSURE diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl index 3de807b57c..926c7ef9fc 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles.glsl +++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl @@ -31,6 +31,40 @@ global_variables; /* Set 1: FRAME AND PARTICLE DATA */ // a frame history is kept for trail deterministic behavior + +#define MAX_ATTRACTORS 32 + +#define ATTRACTOR_TYPE_SPHERE 0 +#define ATTRACTOR_TYPE_BOX 1 +#define ATTRACTOR_TYPE_VECTOR_FIELD 2 + +struct Attractor { + mat4 transform; + vec3 extents; //exents or radius + uint type; + uint texture_index; //texture index for vector field + float strength; + float attenuation; + float directionality; +}; + +#define MAX_COLLIDERS 32 + +#define COLLIDER_TYPE_SPHERE 0 +#define COLLIDER_TYPE_BOX 1 +#define COLLIDER_TYPE_SDF 2 +#define COLLIDER_TYPE_HEIGHT_FIELD 3 + +struct Collider { + mat4 transform; + vec3 extents; //exents or radius + uint type; + + uint texture_index; //texture index for vector field + float scale; + uint pad[2]; +}; + struct FrameParams { bool emitting; float system_phase; @@ -43,9 +77,14 @@ struct FrameParams { float delta; uint random_seed; - uint pad[3]; + uint attractor_count; + uint collider_count; + float particle_size; mat4 emission_transform; + + Attractor attractors[MAX_ATTRACTORS]; + Collider colliders[MAX_COLLIDERS]; }; layout(set = 1, binding = 0, std430) restrict buffer FrameHistory { @@ -80,7 +119,7 @@ struct ParticleEmission { vec4 custom; }; -layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmission { +layout(set = 1, binding = 2, std430) restrict buffer SourceEmission { int particle_count; uint pad0; uint pad1; @@ -89,7 +128,7 @@ layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmi } src_particles; -layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmission { +layout(set = 1, binding = 3, std430) restrict buffer DestEmission { int particle_count; int particle_max; uint pad1; @@ -98,10 +137,17 @@ layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmiss } dst_particles; -/* SET 2: MATERIAL */ +/* SET 2: COLLIDER/ATTRACTOR TEXTURES */ + +#define MAX_3D_TEXTURES 7 + +layout(set = 2, binding = 0) uniform texture3D sdf_vec_textures[MAX_3D_TEXTURES]; +layout(set = 2, binding = 1) uniform texture2D height_field_texture; + +/* SET 3: MATERIAL */ #ifdef USE_MATERIAL_UNIFORMS -layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ +layout(set = 3, binding = 0, std140) uniform MaterialUniforms{ /* clang-format off */ MATERIAL_UNIFORMS /* clang-format on */ @@ -140,29 +186,7 @@ bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, u atomicAdd(dst_particles.particle_count, -1); return false; } - /* - valid = true; - - int attempts = 256; // never trust compute - while(attempts-- > 0) { - dst_index = dst_particles.particle_count; - if (dst_index == dst_particles.particle_max) { - return false; //cant emit anymore - } - - if (atomicCompSwap(dst_particles.particle_count, dst_index, dst_index +1 ) != dst_index) { - continue; - } - valid=true; - break; - } - barrier(); - - if (!valid) { - return false; //gave up (attempts exhausted) - } -*/ dst_particles.data[dst_index].xform = p_xform; dst_particles.data[dst_index].velocity = p_velocity; dst_particles.data[dst_index].color = p_color; @@ -217,6 +241,199 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); } + bool collided = false; + vec3 collision_normal = vec3(0.0); + float collision_depth = 0.0; + + vec3 attractor_force = vec3(0.0); + +#if !defined(DISABLE_VELOCITY) + + if (PARTICLE.is_active) { + PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; + } +#endif + + /* Process physics if active */ + + if (PARTICLE.is_active) { + for (uint i = 0; i < FRAME.attractor_count; i++) { + vec3 dir; + float amount; + vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.attractors[i].transform[3].xyz; + vec3 local_pos = rel_vec * mat3(FRAME.attractors[i].transform); + + switch (FRAME.attractors[i].type) { + case ATTRACTOR_TYPE_SPHERE: { + dir = normalize(rel_vec); + float d = length(local_pos) / FRAME.attractors[i].extents.x; + if (d > 1.0) { + continue; + } + amount = max(0.0, 1.0 - d); + } break; + case ATTRACTOR_TYPE_BOX: { + dir = normalize(rel_vec); + + vec3 abs_pos = abs(local_pos / FRAME.attractors[i].extents); + float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z)); + if (d > 1.0) { + continue; + } + amount = max(0.0, 1.0 - d); + + } break; + case ATTRACTOR_TYPE_VECTOR_FIELD: { + vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents) * 2.0 - 1.0; + if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) { + continue; + } + vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz; + dir = mat3(FRAME.attractors[i].transform) * normalize(s); //revert direction + amount = length(s); + + } break; + } + amount = pow(amount, FRAME.attractors[i].attenuation); + dir = normalize(mix(dir, FRAME.attractors[i].transform[2].xyz, FRAME.attractors[i].directionality)); + attractor_force -= amount * dir * FRAME.attractors[i].strength; + } + + float particle_size = FRAME.particle_size; + +#ifdef USE_COLLISON_SCALE + + particle_size *= dot(vec3(length(PARTICLE.xform[0].xyz), length(PARTICLE.xform[1].xyz), length(PARTICLE.xform[2].xyz)), vec3(0.33333333333)); + +#endif + + for (uint i = 0; i < FRAME.collider_count; i++) { + vec3 normal; + float depth; + bool col = false; + + vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz; + vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform); + + switch (FRAME.colliders[i].type) { + case COLLIDER_TYPE_SPHERE: { + float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x); + + if (d < 0.0) { + col = true; + depth = -d; + normal = normalize(rel_vec); + } + + } break; + case COLLIDER_TYPE_BOX: { + vec3 abs_pos = abs(local_pos); + vec3 sgn_pos = sign(local_pos); + + if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) { + //point outside box + + vec3 closest = min(abs_pos, FRAME.colliders[i].extents); + vec3 rel = abs_pos - closest; + depth = length(rel) - particle_size; + if (depth < 0.0) { + col = true; + normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos); + depth = -depth; + } + } else { + //point inside box + vec3 axis_len = FRAME.colliders[i].extents - abs_pos; + // there has to be a faster way to do this? + if (all(lessThan(axis_len.xx, axis_len.yz))) { + normal = vec3(1, 0, 0); + } else if (all(lessThan(axis_len.yy, axis_len.xz))) { + normal = vec3(0, 1, 0); + } else { + normal = vec3(0, 0, 1); + } + + col = true; + depth = dot(normal * axis_len, vec3(1)) + particle_size; + normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos); + } + + } break; + case COLLIDER_TYPE_SDF: { + vec3 apos = abs(local_pos); + float extra_dist = 0.0; + if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside + vec3 mpos = min(apos, FRAME.colliders[i].extents); + extra_dist = distance(mpos, apos); + } + + if (extra_dist > particle_size) { + continue; + } + + vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5; + float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r; + s *= FRAME.colliders[i].scale; + s += extra_dist; + if (s < particle_size) { + col = true; + depth = particle_size - s; + const float EPSILON = 0.001; + normal = mat3(FRAME.colliders[i].transform) * + normalize( + vec3( + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); + } + + } break; + case COLLIDER_TYPE_HEIGHT_FIELD: { + vec3 local_pos_bottom = local_pos; + local_pos_bottom.y -= particle_size; + + if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) { + continue; + } + + const float DELTA = 1.0 / 8192.0; + + vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5; + + float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r; + + if (y > uvw_pos.y) { + //inside heightfield + + vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; + vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; + vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents; + + normal = normalize(cross(pos1 - pos2, pos1 - pos3)); + float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y; + + col = true; + depth = dot(normal, pos1) - dot(normal, local_pos_bottom); + } + + } break; + } + + if (col) { + if (!collided) { + collided = true; + collision_normal = normal; + collision_depth = depth; + } else { + vec3 c = collision_normal * collision_depth; + c += normal * max(0.0, depth - dot(normal, c)); + collision_normal = normalize(c); + collision_depth = length(c); + } + } + } + } + if (params.sub_emitter_mode) { if (!PARTICLE.is_active) { int src_index = atomicAdd(src_particles.particle_count, -1) - 1; @@ -329,66 +546,4 @@ COMPUTE_SHADER_CODE /* clang-format on */ } - -#if !defined(DISABLE_VELOCITY) - - if (PARTICLE.is_active) { - PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; - } -#endif - -#if 0 - if (PARTICLE.is_active) { - //execute shader - - - - - //!defined(DISABLE_FORCE) - - if (false) { - vec3 force = vec3(0.0); - for (int i = 0; i < attractor_count; i++) { - vec3 rel_vec = xform[3].xyz - attractors[i].pos; - float dist = length(rel_vec); - if (attractors[i].radius < dist) - continue; - if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) { - out_velocity_active.a = 0.0; - } - - rel_vec = normalize(rel_vec); - - float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation); - - if (attractors[i].dir == vec3(0.0)) { - //towards center - force += attractors[i].strength * rel_vec * attenuation * mass; - } else { - force += attractors[i].strength * attractors[i].dir * attenuation * mass; - } - } - - out_velocity_active.xyz += force * local_delta; - } - -#if !defined(DISABLE_VELOCITY) - - if (true) { - xform[3].xyz += out_velocity_active.xyz * local_delta; - } -#endif - } else { - xform = mat4(0.0); - } - - - xform = transpose(xform); - - out_velocity_active.a = mix(0.0, 1.0, shader_active); - - out_xform_1 = xform[0]; - out_xform_2 = xform[1]; - out_xform_3 = xform[2]; -#endif } diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 2a7b73d9aa..455a3d4a3a 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -681,7 +681,7 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -// Produces cheap white noise, optmized for window-space +// Produces cheap white noise, optimized for window-space // Comes from: https://www.shadertoy.com/view/4djSRW // Copyright: Dave Hoskins, MIT License float quick_hash(vec2 pos) { @@ -1621,6 +1621,22 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; + if (scene_data.fog_aerial_perspective > 0.0) { + vec3 sky_fog_color = vec3(0.0); + vec3 cube_view = scene_data.radiance_inverse_xform * vertex; + // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred + float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + float lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); + sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); +#else + sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); + } + if (scene_data.fog_sun_scatter > 0.001) { vec4 sun_scatter = vec4(0.0); float sun_total = 0.0; @@ -1676,6 +1692,15 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); +#if defined(CUSTOM_FOG_USED) + vec4 custom_fog = vec4(0.0); +#endif +#if defined(CUSTOM_RADIANCE_USED) + vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) + vec4 custom_irradiance = vec4(0.0); +#endif #if defined(AO_USED) float ao = 1.0; @@ -1893,6 +1918,10 @@ FRAGMENT_SHADER_CODE specular_light *= scene_data.ambient_light_color_energy.a; } +#if defined(CUSTOM_RADIANCE_USED) + specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif + #ifndef USE_LIGHTMAP //lightmap overrides everything if (scene_data.use_ambient_light) { @@ -1910,7 +1939,9 @@ FRAGMENT_SHADER_CODE } } #endif // USE_LIGHTMAP - +#if defined(CUSTOM_IRRADIANCE_USED) + ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); +#endif #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) //radiance @@ -2726,18 +2757,24 @@ FRAGMENT_SHADER_CODE specular_buffer = vec4(specular_light, metallic); #endif - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(vertex); diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); + if (scene_data.volumetric_fog_enabled) { + vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } +#if defined(CUSTOM_FOG_USED) + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), custom_fog.a); +#endif //CUSTOM_FOG_USED + #else //MODE_MULTIPLE_RENDER_TARGETS #ifdef MODE_UNSHADED @@ -2747,16 +2784,21 @@ FRAGMENT_SHADER_CODE //frag_color = vec4(1.0); #endif //USE_NO_SHADING - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(vertex); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); + if (scene_data.volumetric_fog_enabled) { + vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } +#if defined(CUSTOM_FOG_USED) + frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); +#endif //CUSTOM_FOG_USED + #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index 66bfefbe89..e29a490ca1 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -43,12 +43,6 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec2 viewport_size; vec2 screen_pixel_size; - float time; - float reflection_multiplier; // one normally, zero when rendering reflections - - bool pancake_shadows; - uint pad; - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted vec4 directional_penumbra_shadow_kernel[32]; vec4 directional_soft_shadow_kernel[32]; @@ -108,6 +102,13 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec3 fog_light_color; float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + + bool pancake_shadows; } scene_data; @@ -252,7 +253,7 @@ layout(set = 1, binding = 0) uniform textureCube radiance_cubemap; #endif -/* Set 2, Reflection and Shadow Atlases (view dependant) */ +/* Set 2, Reflection and Shadow Atlases (view dependent) */ layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl index a8ee33a664..06dc4b13de 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl @@ -155,18 +155,14 @@ void main() { depth = imageLoad(source_depth, ivec2(pos - 0.5)).r; - if (-depth >= params.camera_z_far) { //went beyond camera - break; - } - z_from = z_to; z_to = z / w; if (depth > z_to) { // if depth was surpassed - if (depth <= max(z_to, z_from) + params.depth_tolerance) { - // check the depth tolerance - //check that normal is valid + if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far) { + // check the depth tolerance and far clip + // check that normal is valid found = true; } break; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl index c4b29216d5..61e4bf5e18 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl @@ -22,7 +22,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl index 1ec471d204..d516ab22c3 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl @@ -336,7 +336,7 @@ void main() { #ifdef MODE_STORE - // converting to octahedral in this step is requiered because + // converting to octahedral in this step is required because // octahedral is much faster to read from the screen than spherical harmonics, // despite the very slight quality loss @@ -512,7 +512,7 @@ void main() { imageStore(lightprobe_average_scroll_texture, dst_pos, value); } } else if (params.cascade < params.max_cascades - 1) { - //cant scroll, must look for position in parent cascade + //can't scroll, must look for position in parent cascade //to global coords float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl index dd0ca5c506..916c60ac89 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl @@ -103,7 +103,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; @@ -136,7 +136,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; @@ -274,7 +274,7 @@ void main() { #ifdef MODE_JUMPFLOOD - //regular jumpflood, efficent for large steps, inefficient for small steps + //regular jumpflood, efficient for large steps, inefficient for small steps ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); vec3 posf = vec3(pos); diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 7b6de6a555..6c985e1f5c 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -62,7 +62,8 @@ layout(set = 0, binding = 2, std140) uniform SceneData { bool volumetric_fog_enabled; float volumetric_fog_inv_length; float volumetric_fog_detail_spread; - uint volumetric_fog_pad; + + float fog_aerial_perspective; vec3 fog_light_color; float fog_sun_scatter; @@ -140,8 +141,8 @@ vec4 volumetric_fog_process(vec2 screen_uv) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } -vec4 fog_process(vec3 view) { - vec3 fog_color = scene_data.fog_light_color; +vec4 fog_process(vec3 view, vec3 sky_color) { + vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective); if (scene_data.fog_sun_scatter > 0.001) { vec4 sun_scatter = vec4(0.0); @@ -181,6 +182,7 @@ void main() { float alpha = 1.0; // Only available to subpasses vec4 half_res_color = vec4(1.0); vec4 quarter_res_color = vec4(1.0); + vec4 custom_fog = vec4(0.0); #ifdef USE_CUBEMAP_PASS vec3 inverted_cube_normal = cube_normal; @@ -223,14 +225,19 @@ FRAGMENT_SHADER_CODE #if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS) + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(cube_normal, frag_color.rgb); + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + } + if (scene_data.volumetric_fog_enabled) { vec4 fog = volumetric_fog_process(uv); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(cube_normal); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + if (custom_fog.a > 0.0) { + frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); } #endif // DISABLE_FOG diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index b7c46a7d0e..ee66de4192 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -37,16 +37,18 @@ layout(push_constant, binding = 1, std430) uniform Params { uvec2 glow_texture_size; float glow_intensity; - uint glow_level_flags; + uint pad3; uint glow_mode; + float glow_levels[7]; float exposure; float white; float auto_exposure_grey; + uint pad2; vec2 pixel_size; bool use_fxaa; - uint pad; + bool use_debanding; } params; @@ -155,6 +157,10 @@ vec3 tonemap_aces(vec3 color, float white) { } vec3 tonemap_reinhard(vec3 color, float white) { + // Ensure color values are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. + color = max(vec3(0.0), color); + return (white * color + color) / (color * white + white); } @@ -186,32 +192,32 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels vec3 glow = vec3(0.0f); - if (bool(params.glow_level_flags & (1 << 0))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb; + if (params.glow_levels[0] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb * params.glow_levels[0]; } - if (bool(params.glow_level_flags & (1 << 1))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb; + if (params.glow_levels[1] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb * params.glow_levels[1]; } - if (bool(params.glow_level_flags & (1 << 2))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb; + if (params.glow_levels[2] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb * params.glow_levels[2]; } - if (bool(params.glow_level_flags & (1 << 3))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb; + if (params.glow_levels[3] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb * params.glow_levels[3]; } - if (bool(params.glow_level_flags & (1 << 4))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb; + if (params.glow_levels[4] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb * params.glow_levels[4]; } - if (bool(params.glow_level_flags & (1 << 5))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb; + if (params.glow_levels[5] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb * params.glow_levels[5]; } - if (bool(params.glow_level_flags & (1 << 6))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb; + if (params.glow_levels[6] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6]; } return glow; @@ -299,6 +305,20 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { } } +#define QUARTER_COLOR 1.0 / 1024.0 + +// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) +// NOTE: `frag_coord` is in pixels (i.e. not normalized UV). +vec3 screen_space_dither(vec2 frag_coord) { + // Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR. + vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord)); + dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); + + // Subtract 0.5 to avoid slightly brightening the whole viewport. + return (dither.rgb - 0.5) / 255.0; +} + void main() { vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; @@ -322,6 +342,11 @@ void main() { if (params.use_fxaa) { color = do_fxaa(color, exposure, uv_interp); } + if (params.use_debanding) { + // For best results, debanding should be done before tonemapping. + // Otherwise, we're adding noise to an already-quantized image. + color += screen_space_dither(gl_FragCoord.xy); + } color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl index cb19fb0b69..13b162f0c9 100644 --- a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl @@ -485,7 +485,7 @@ void main() { //get depth at cell pos float z = get_depth_at_pos(fog_cell_size.z, i); - //get distance from previos pos + //get distance from previous pos float d = abs(prev_z - z); //compute exinction based on beer's float extinction = t * exp(-d * fog.a); |