diff options
Diffstat (limited to 'servers/rendering')
21 files changed, 441 insertions, 284 deletions
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 0c191fe2f7..80d843227b 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -759,7 +759,7 @@ void EffectsRD::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuff RD::get_singleton()->draw_list_end(); } -void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) { +void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) { CopyToDPPushConstant push_constant; push_constant.screen_rect[0] = p_rect.position.x; push_constant.screen_rect[1] = p_rect.position.y; @@ -767,7 +767,9 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe push_constant.screen_rect[3] = p_rect.size.height; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; - push_constant.z_flip = p_dp_flip; + push_constant.texel_size[0] = 1.0f / p_dst_size.x; + push_constant.texel_size[1] = 1.0f / p_dst_size.y; + push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); @@ -2169,10 +2171,8 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { for (int pass = 0; pass < 4; pass++) { for (int subPass = 0; subPass < sub_pass_count; subPass++) { int a = pass; - int b = subPass; - int spmap[5]{ 0, 1, 4, 3, 2 }; - b = spmap[subPass]; + int b = spmap[subPass]; float ca, sa; float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 0c9b2efb7f..c8d4cb7ad4 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -321,8 +321,7 @@ private: struct CopyToDPPushConstant { float z_far; float z_near; - uint32_t z_flip; - uint32_t pad; + float texel_size[2]; float screen_rect[4]; }; @@ -770,7 +769,7 @@ public: void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index d81c216f37..8496ef631b 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -860,7 +860,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool shadow_atlas->shadow_owners.clear(); shadow_atlas->size = p_size; - shadow_atlas->use_16_bits = p_size; + shadow_atlas->use_16_bits = p_16_bits; } void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { @@ -935,7 +935,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, //look for an empty space int sc = shadow_atlas->quadrants[qidx].shadows.size(); - ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw(); + const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); int found_free_idx = -1; //found a free one int found_used_idx = -1; //found existing one, must steal it @@ -980,6 +980,78 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, return false; } +bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { + for (int i = p_quadrant_count - 1; i >= 0; i--) { + int qidx = p_in_quadrants[i]; + + if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { + return false; + } + + //look for an empty space + int sc = shadow_atlas->quadrants[qidx].shadows.size(); + const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); + + int found_idx = -1; + uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair + + for (int j = 0; j < sc - 1; j++) { + uint64_t pass = 0; + + if (sarr[j].owner.is_valid()) { + LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass == scene_pass) { + continue; + } + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { + continue; + } + pass += sli->last_scene_pass; + } + + if (sarr[j + 1].owner.is_valid()) { + LightInstance *sli = light_instance_owner.getornull(sarr[j + 1].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass == scene_pass) { + continue; + } + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) { + continue; + } + pass += sli->last_scene_pass; + } + + if (found_idx == -1 || pass < min_pass) { + found_idx = j; + min_pass = pass; + + // we found two empty spots, no need to check the rest + if (pass == 0) { + break; + } + } + } + + if (found_idx == -1) { + continue; //nothing found + } + + r_quadrant = qidx; + r_shadow = found_idx; + + return true; + } + + return false; +} + bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); @@ -1025,94 +1097,104 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i uint64_t tick = OS::get_singleton()->get_ticks_msec(); - //see if it already exists + uint32_t old_key = ShadowAtlas::SHADOW_INVALID; + uint32_t old_quadrant = ShadowAtlas::SHADOW_INVALID; + uint32_t old_shadow = ShadowAtlas::SHADOW_INVALID; + int old_subdivision = -1; + + bool should_realloc = false; + bool should_redraw = false; if (shadow_atlas->shadow_owners.has(p_light_intance)) { - //it does! - uint32_t key = shadow_atlas->shadow_owners[p_light_intance]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; + old_key = shadow_atlas->shadow_owners[p_light_intance]; + old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK; - bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); - bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; + should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version; if (!should_realloc) { - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version; //already existing, see if it should redraw or it's just OK return should_redraw; } - int new_quadrant, new_shadow; + old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision; + } - //find a better place - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) { - //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - //is taken, but is invalid, erasing it - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.getornull(sh->owner); - sli->shadow_atlases.erase(p_atlas); - } + bool is_omni = li->light_type == RS::LIGHT_OMNI; + bool found_shadow = false; + int new_quadrant = -1; + int new_shadow = -1; - //erase previous - shadow_atlas->quadrants[q].shadows.write[s].version = 0; - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + if (is_omni) { + found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); + } else { + found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow); + } - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; - li->shadow_atlases.insert(p_atlas); - - //make new key - key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; - //update it in map - shadow_atlas->shadow_owners[p_light_intance] = key; - //make it dirty, as it should redraw anyway - return true; + if (found_shadow) { + if (old_quadrant != ShadowAtlas::SHADOW_INVALID) { + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0; + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID(); + + if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) { + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0; + shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID(); + } } - //no better place for this shadow found, keep current + uint32_t new_key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; + new_key |= new_shadow; - //already existing, see if it should redraw or it's just OK + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; + _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow); - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; + sh->owner = p_light_intance; + sh->alloc_tick = tick; + sh->version = p_light_version; - return should_redraw; - } + if (is_omni) { + new_key |= ShadowAtlas::OMNI_LIGHT_FLAG; - int new_quadrant, new_shadow; + int new_omni_shadow = new_shadow + 1; + ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow]; + _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow); - //find a better place - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) { - //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - //is taken, but is invalid, erasing it - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.getornull(sh->owner); - sli->shadow_atlases.erase(p_atlas); + extra_sh->owner = p_light_intance; + extra_sh->alloc_tick = tick; + extra_sh->version = p_light_version; } - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; li->shadow_atlases.insert(p_atlas); - //make new key - uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; //update it in map - shadow_atlas->shadow_owners[p_light_intance] = key; + shadow_atlas->shadow_owners[p_light_intance] = new_key; //make it dirty, as it should redraw anyway - return true; } - //no place to allocate this light, apologies + return should_redraw; +} - return false; +void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) { + if (p_shadow->owner.is_valid()) { + LightInstance *sli = light_instance_owner.getornull(p_shadow->owner); + uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner]; + + if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) { + uint32_t s = old_key & ShadowAtlas::SHADOW_INDEX_MASK; + uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1); + RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx]; + omni_shadow->version = 0; + omni_shadow->owner = RID(); + } + + p_shadow->version = 0; + p_shadow->owner = RID(); + sli->shadow_atlases.erase(p_atlas); + p_shadow_atlas->shadow_owners.erase(p_shadow->owner); + } } void RendererSceneRenderRD::_update_directional_shadow_atlas() { @@ -1137,6 +1219,7 @@ void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p } directional_shadow.size = p_size; + directional_shadow.use_16_bits = p_16_bits; if (directional_shadow.depth.is_valid()) { RD::get_singleton()->free(directional_shadow.depth); @@ -3120,18 +3203,19 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.shadow_enabled = true; - if (type == RS::LIGHT_SPOT) { - light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0); + float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0; - } else { //omni + if (type == RS::LIGHT_SPOT) { light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0; - float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); - light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space + } else { //omni + light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS); } light_data.transmittance_bias = storage->light_get_transmittance_bias(base); - Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas); + Vector2i omni_offset; + Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas, omni_offset); light_data.atlas_rect[0] = rect.position.x; light_data.atlas_rect[1] = rect.position.y; @@ -3142,7 +3226,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base); if (type == RS::LIGHT_OMNI) { - light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another Transform3D proj = (inverse_transform * light_transform).inverse(); RendererStorageRD::store_transform(proj, light_data.shadow_matrix); @@ -3154,6 +3237,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF } + light_data.direction[0] = omni_offset.x * float(rect.size.width); + light_data.direction[1] = omni_offset.y * float(rect.size.height); } else if (type == RS::LIGHT_SPOT) { Transform3D modelview = (inverse_transform * light_transform).inverse(); CameraMatrix bias; @@ -4139,6 +4224,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, bool using_dual_paraboloid = false; bool using_dual_paraboloid_flip = false; + Vector2i dual_paraboloid_offset; RID render_fb; RID render_texture; float zfar; @@ -4232,6 +4318,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) { + bool wrap = (shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision == 0; + dual_paraboloid_offset = wrap ? Vector2i(1 - shadow_atlas->quadrants[quadrant].subdivision, 1) : Vector2i(1, 0); + if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2); @@ -4251,12 +4340,16 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, } } else { + atlas_rect.position.x += 1; + atlas_rect.position.y += 1; + atlas_rect.size.x -= 2; + atlas_rect.size.y -= 2; + + atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset; + light_projection = light_instance->shadow_transform[0].camera; light_transform = light_instance->shadow_transform[0].transform; - atlas_rect.size.height /= 2; - atlas_rect.position.y += p_pass * atlas_rect.size.height; - using_dual_paraboloid = true; using_dual_paraboloid_flip = p_pass == 1; render_fb = shadow_atlas->fb; @@ -4285,10 +4378,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, atlas_rect_norm.position.y /= float(atlas_size); atlas_rect_norm.size.x /= float(atlas_size); atlas_rect_norm.size.y /= float(atlas_size); - atlas_rect_norm.size.height /= 2; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false); - atlas_rect_norm.position.y += atlas_rect_norm.size.height; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true); + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false); + atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true); //restore transform so it can be properly used light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0); @@ -4390,6 +4482,12 @@ bool RendererSceneRenderRD::free(RID p_rid) { uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + + if (key & ShadowAtlas::OMNI_LIGHT_FLAG) { + // Omni lights use two atlas spots, make sure to clear the other as well + shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID(); + } + shadow_atlas->shadow_owners.erase(p_rid); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index a7cc27be4a..37533baecf 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -255,7 +255,8 @@ private: struct ShadowAtlas { enum { QUADRANT_SHIFT = 27, - SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1, + OMNI_LIGHT_FLAG = 1 << 26, + SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1, SHADOW_INVALID = 0xFFFFFFFF }; @@ -299,7 +300,9 @@ private: void _update_shadow_atlas(ShadowAtlas *shadow_atlas); + void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx); bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX; @@ -379,10 +382,6 @@ private: uint32_t cull_mask = 0; uint32_t light_directional_index = 0; - uint32_t current_shadow_atlas_key = 0; - - Vector2 dp; - Rect2 directional_rect; Set<RID> shadow_atlases; //shadow atlases where this light is registered @@ -575,7 +574,7 @@ private: struct LightData { float position[3]; float inv_radius; - float direction[3]; + float direction[3]; // in omni, x and y are used for dual paraboloid offset float size; float color[3]; @@ -964,7 +963,7 @@ public: return li->transform; } - _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) { + _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); LightInstance *li = light_instance_owner.getornull(p_light_instance); uint32_t key = shadow_atlas->shadow_owners[li->self]; @@ -984,6 +983,16 @@ public: x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + if (key & ShadowAtlas::OMNI_LIGHT_FLAG) { + if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) { + r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision); + r_omni_offset.y = 1; + } else { + r_omni_offset.x = 1; + r_omni_offset.y = 0; + } + } + uint32_t width = shadow_size; uint32_t height = shadow_size; diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 8aa03b6426..bad37f5c25 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -213,7 +213,7 @@ static String _interpstr(SL::DataInterpolation p_interp) { return ""; } -static String _prestr(SL::DataPrecision p_pres) { +static String _prestr(SL::DataPrecision p_pres, bool p_force_highp = false) { switch (p_pres) { case SL::PRECISION_LOWP: return "lowp "; @@ -222,7 +222,7 @@ static String _prestr(SL::DataPrecision p_pres) { case SL::PRECISION_HIGHP: return "highp "; case SL::PRECISION_DEFAULT: - return ""; + return p_force_highp ? "highp " : ""; } return ""; } @@ -617,7 +617,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge //this is an integer to index the global table ucode += _typestr(ShaderLanguage::TYPE_UINT); } else { - ucode += _prestr(uniform.precision); + ucode += _prestr(uniform.precision, ShaderLanguage::is_float_type(uniform.type)); ucode += _typestr(uniform.type); } @@ -742,7 +742,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge String vcode; String interp_mode = _interpstr(varying.interpolation); - vcode += _prestr(varying.precision); + vcode += _prestr(varying.precision, ShaderLanguage::is_float_type(varying.type)); vcode += _typestr(varying.type); vcode += " " + _mkid(varying_name); if (varying.array_size > 0) { @@ -777,7 +777,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge const SL::ShaderNode::Constant &cnode = pnode->vconstants[i]; String gcode; gcode += "const "; - gcode += _prestr(cnode.precision); + gcode += _prestr(cnode.precision, ShaderLanguage::is_float_type(cnode.type)); if (cnode.type == SL::TYPE_STRUCT) { gcode += _mkid(cnode.type_str); } else { diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl index 43a2a29616..a3b3938ee9 100644 --- a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl @@ -47,7 +47,7 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight; #endif //DOF -// Bokeh single pass implementation based on http://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html +// Bokeh single pass implementation based on https://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html #ifdef MODE_GEN_BLUR_SIZE diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl index da7d189281..6d95722a57 100644 --- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl @@ -117,7 +117,7 @@ void main() { uint cluster_thread_group_index; if (!gl_HelperInvocation) { - //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf + //https://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf uvec4 mask; diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl index dfbce29119..69b895ed29 100644 --- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl @@ -7,8 +7,7 @@ layout(push_constant, binding = 1, std430) uniform Params { float z_far; float z_near; - bool z_flip; - uint pad; + vec2 texel_size; vec4 screen_rect; } params; @@ -35,22 +34,23 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube; layout(push_constant, binding = 1, std430) uniform Params { float z_far; float z_near; - bool z_flip; - uint pad; + vec2 texel_size; vec4 screen_rect; } params; void main() { vec2 uv = uv_interp; + vec2 texel_size = abs(params.texel_size); - vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + uv = clamp(uv * (1.0 + 2.0 * texel_size) - texel_size, vec2(0.0), vec2(1.0)); - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + normal.z = 0.5 * (1.0 - dot(normal.xy, normal.xy)); // z = 1/2 - 1/2 * (x^2 + y^2) normal = normalize(normal); normal.y = -normal.y; //needs to be flipped to match projection matrix - if (!params.z_flip) { + if (params.texel_size.x >= 0.0) { // Sign is used to encode Z flip normal.z = -normal.z; } diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl index 80c0ac4fb4..be12be5dec 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl @@ -69,13 +69,13 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { return TangentX * H.x + TangentY * H.y + N * H.z; } -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html float GGX(float NdotV, float a) { float k = a / 2.0; return NdotV / (NdotV * (1.0 - k) + k); } -// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html float G_Smith(float a, float nDotV, float nDotL) { return GGX(nDotL, a * a) * GGX(nDotV, a * a); } diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl index ccaad13311..158096d3c7 100644 --- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl @@ -1,18 +1,18 @@ struct DecalData { - mat4 xform; //to decal transform - vec3 inv_extents; - float albedo_mix; - vec4 albedo_rect; - vec4 normal_rect; - vec4 orm_rect; - vec4 emission_rect; - vec4 modulate; - float emission_energy; + highp mat4 xform; //to decal transform + highp vec3 inv_extents; + mediump float albedo_mix; + highp vec4 albedo_rect; + highp vec4 normal_rect; + highp vec4 orm_rect; + highp vec4 emission_rect; + highp vec4 modulate; + mediump float emission_energy; uint mask; - float upper_fade; - float lower_fade; - mat3x4 normal_xform; - vec3 normal; - float normal_fade; + mediump float upper_fade; + mediump float lower_fade; + mediump mat3x4 normal_xform; + mediump vec3 normal; + mediump float normal_fade; }; diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl index 9155216d7e..fdc7729338 100644 --- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl @@ -4,28 +4,28 @@ struct LightData { //this structure needs to be as packed as possible highp vec3 position; - float inv_radius; + highp float inv_radius; - vec3 direction; - float size; + mediump vec3 direction; + highp float size; - vec3 color; - float attenuation; + mediump vec3 color; + mediump float attenuation; - float cone_attenuation; - float cone_angle; - float specular_amount; + mediump float cone_attenuation; + mediump float cone_angle; + mediump float specular_amount; bool shadow_enabled; highp vec4 atlas_rect; // rect in the shadow atlas highp mat4 shadow_matrix; - float shadow_bias; - float shadow_normal_bias; - float transmittance_bias; - float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle - float soft_shadow_scale; // scales the shadow kernel for blurrier shadows + highp float shadow_bias; + highp float shadow_normal_bias; + highp float transmittance_bias; + highp float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle + highp float soft_shadow_scale; // scales the shadow kernel for blurrier shadows uint mask; - float shadow_volumetric_fog_fade; + mediump float shadow_volumetric_fog_fade; uint bake_mode; highp vec4 projector_rect; //projector rect in srgb decal atlas }; @@ -35,53 +35,53 @@ struct LightData { //this structure needs to be as packed as possible #define REFLECTION_AMBIENT_COLOR 2 struct ReflectionData { - vec3 box_extents; - float index; - vec3 box_offset; + highp vec3 box_extents; + mediump float index; + highp vec3 box_offset; uint mask; - vec3 ambient; // ambient color - float intensity; + mediump vec3 ambient; // ambient color + mediump float intensity; bool exterior; bool box_project; uint ambient_mode; uint pad; //0-8 is intensity,8-9 is ambient, mode - mat4 local_matrix; // up to here for spot and omni, rest is for directional + highp mat4 local_matrix; // up to here for spot and omni, rest is for directional // notes: for ambientblend, use distance to edge to blend between already existing global environment }; struct DirectionalLightData { - vec3 direction; - float energy; - vec3 color; - float size; - float specular; + mediump vec3 direction; + mediump float energy; + mediump vec3 color; + mediump float size; + mediump float specular; uint mask; - float softshadow_angle; - float soft_shadow_scale; + highp float softshadow_angle; + highp float soft_shadow_scale; bool blend_splits; bool shadow_enabled; - float fade_from; - float fade_to; + highp float fade_from; + highp float fade_to; uvec2 pad; uint bake_mode; - float shadow_volumetric_fog_fade; - vec4 shadow_bias; - vec4 shadow_normal_bias; - vec4 shadow_transmittance_bias; + mediump float shadow_volumetric_fog_fade; + highp vec4 shadow_bias; + highp vec4 shadow_normal_bias; + highp vec4 shadow_transmittance_bias; highp vec4 shadow_z_range; highp vec4 shadow_range_begin; - vec4 shadow_split_offsets; + highp vec4 shadow_split_offsets; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; highp mat4 shadow_matrix3; highp mat4 shadow_matrix4; - vec4 shadow_color1; - vec4 shadow_color2; - vec4 shadow_color3; - vec4 shadow_color4; - vec2 uv_scale1; - vec2 uv_scale2; - vec2 uv_scale3; - vec2 uv_scale4; + mediump vec4 shadow_color1; + mediump vec4 shadow_color2; + mediump vec4 shadow_color3; + mediump vec4 shadow_color4; + highp vec2 uv_scale1; + highp vec2 uv_scale2; + highp vec2 uv_scale3; + highp vec2 uv_scale4; }; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index 4f140dd10d..7a11f8904e 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -118,7 +118,7 @@ void main() { mat3 world_normal_matrix; if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { - world_normal_matrix = inverse(mat3(world_matrix)); + world_normal_matrix = transpose(inverse(mat3(world_matrix))); } else { world_normal_matrix = mat3(world_matrix); } @@ -881,7 +881,7 @@ void main() { #ifdef NORMAL_USED if (scene_data.roughness_limiter_enabled) { - //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf + //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; vec3 dndu = dFdx(normal), dndv = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); @@ -1601,7 +1601,7 @@ void main() { continue; // Statically baked light and object uses lightmap, skip } - float shadow = light_process_omni_shadow(light_index, vertex, view); + float shadow = light_process_omni_shadow(light_index, vertex, normal); shadow = blur_shadow(shadow); @@ -1677,7 +1677,7 @@ void main() { continue; // Statically baked light and object uses lightmap, skip } - float shadow = light_process_spot_shadow(light_index, vertex, view); + float shadow = light_process_spot_shadow(light_index, vertex, normal); shadow = blur_shadow(shadow); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 4a41c66ef3..9fa5d3280d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -279,7 +279,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); #endif #endif //defined(LIGHT_CODE_USED) @@ -288,7 +288,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #ifndef USE_NO_SHADOWS // Interleaved Gradient Noise -// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare +// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare float quick_hash(vec2 pos) { const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); return fract(magic.z * fract(dot(pos, magic.xy))); @@ -320,7 +320,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve return avg * (1.0 / float(sc_directional_soft_shadow_samples)); } -float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) { vec2 pos = coord.xy; float depth = coord.z; @@ -346,6 +346,49 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { return avg * (1.0 / float(sc_soft_shadow_samples)); } +float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth) { + //if only one sample is taken, take it from the center + if (sc_soft_shadow_samples == 1) { + vec2 pos = coord * 0.5 + 0.5; + pos = uv_rect.xy + pos * uv_rect.zw; + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + vec2 offset_scale = blur_scale * 2.0 * scene_data.shadow_atlas_pixel_size / uv_rect.zw; + + for (uint i = 0; i < sc_soft_shadow_samples; i++) { + vec2 offset = offset_scale * (disk_rotation * scene_data.soft_shadow_kernel[i].xy); + vec2 sample_coord = coord + offset; + + float sample_coord_length_sqaured = dot(sample_coord, sample_coord); + bool do_flip = sample_coord_length_sqaured > 1.0; + + if (do_flip) { + float len = sqrt(sample_coord_length_sqaured); + sample_coord = sample_coord * (2.0 / len - 1.0); + } + + sample_coord = sample_coord * 0.5 + 0.5; + sample_coord = uv_rect.xy + sample_coord * uv_rect.zw; + + if (do_flip) { + sample_coord += flip_offset; + } + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(sample_coord, depth, 1.0)); + } + + return avg * (1.0 / float(sc_soft_shadow_samples)); +} + float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { //find blocker float blocker_count = 0.0; @@ -403,15 +446,21 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS if (omni_lights.data[idx].shadow_enabled) { // there is a shadowmap + vec2 texel_size = scene_data.shadow_atlas_pixel_size; + vec4 base_uv_rect = omni_lights.data[idx].atlas_rect; + base_uv_rect.xy += texel_size; + base_uv_rect.zw -= texel_size * 2.0; - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); + // Omni lights use direction.xy to store to store the offset between the two paraboloid regions + vec2 flip_offset = omni_lights.data[idx].direction.xy; - vec4 v = vec4(vertex, 1.0); + vec3 local_vert = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - vec4 splane = (omni_lights.data[idx].shadow_matrix * v); + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_dir = normalize(local_vert); - float shadow_len = length(splane.xyz); //need to remember shadow len from here + vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal); + vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir))); float shadow; @@ -431,10 +480,10 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } - vec3 normal = normalize(splane.xyz); - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(v0, normal)); - vec3 bitangent = normalize(cross(tangent, normal)); + vec3 basis_normal = shadow_dir; + vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, basis_normal)); + vec3 bitangent = normalize(cross(tangent, basis_normal)); float z_norm = shadow_len * omni_lights.data[idx].inv_radius; tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; @@ -443,18 +492,17 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { for (uint i = 0; i < sc_penumbra_shadow_samples; i++) { vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; + + vec4 uv_rect = base_uv_rect; if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; + uv_rect.xy += flip_offset; } + pos.z = 1.0 + abs(pos.z); pos.xy /= pos.z; pos.xy = pos.xy * 0.5 + 0.5; @@ -479,18 +527,18 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { shadow = 0.0; for (uint i = 0; i < sc_penumbra_shadow_samples; i++) { vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; + pos = normalize(pos + normal_bias); + + vec4 uv_rect = base_uv_rect; if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; + uv_rect.xy += flip_offset; } + pos.z = 1.0 + abs(pos.z); pos.xy /= pos.z; pos.xy = pos.xy * 0.5 + 0.5; @@ -505,26 +553,19 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { shadow = 1.0; } } else { - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - - if (splane.z >= 0.0) { - splane.z += 1.0; + vec4 uv_rect = base_uv_rect; - clamp_rect.y += clamp_rect.w; - - } else { - splane.z = 1.0 - splane.z; + vec3 shadow_sample = normalize(shadow_dir + normal_bias); + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + flip_offset *= -1.0; } - splane.xy /= splane.z; - - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * omni_lights.data[idx].inv_radius; - splane.z -= omni_lights.data[idx].shadow_bias; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec2 pos = shadow_sample.xy / shadow_sample.z; + float depth = shadow_len - omni_lights.data[idx].shadow_bias; + depth *= omni_lights.data[idx].inv_radius; + shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth); } return shadow; @@ -608,13 +649,11 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec4 atlas_rect = omni_lights.data[idx].projector_rect; if (local_v.z >= 0.0) { - local_v.z += 1.0; atlas_rect.y += atlas_rect.w; - - } else { - local_v.z = 1.0 - local_v.z; } + local_v.z = 1.0 + abs(local_v.z); + local_v.xy /= local_v.z; local_v.xy = local_v.xy * 0.5 + 0.5; vec2 proj_uv = local_v.xy * atlas_rect.zw; @@ -694,15 +733,18 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { vec3 light_rel_vec = spot_lights.data[idx].position - vertex; float light_length = length(light_rel_vec); vec3 spot_dir = spot_lights.data[idx].direction; - //there is a shadowmap - vec4 v = vec4(vertex, 1.0); - float shadow; + vec3 shadow_dir = light_rel_vec / light_length; + vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir))); + + //there is a shadowmap + vec4 v = vec4(vertex + normal_bias, 1.0); vec4 splane = (spot_lights.data[idx].shadow_matrix * v); + splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); splane /= splane.w; - splane.z -= spot_lights.data[idx].shadow_bias; + float shadow; if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow @@ -753,11 +795,9 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { //no blockers found, so no shadow shadow = 1.0; } - } else { //hard shadow - vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); - + vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z); shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 663100a0b3..7e2cc8fe01 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -92,7 +92,7 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms #ifdef MODE_DUAL_PARABOLOID -layout(location = 8) out float dp_clip; +layout(location = 8) out highp float dp_clip; #endif @@ -124,7 +124,7 @@ void main() { mat3 world_normal_matrix; if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { - world_normal_matrix = inverse(mat3(world_matrix)); + world_normal_matrix = transpose(inverse(mat3(world_matrix))); } else { world_normal_matrix = mat3(world_matrix); } @@ -370,11 +370,6 @@ void main() { #VERSION_DEFINES -//use medium precision for floats on mobile. - -precision mediump float; -precision highp int; - /* Specialization Constants */ #if !defined(MODE_RENDER_DEPTH) @@ -498,7 +493,7 @@ layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) #else -layout(location = 0) out vec4 frag_color; +layout(location = 0) out mediump vec4 frag_color; #endif // MODE_MULTIPLE_RENDER_TARGETS #endif // RENDER DEPTH @@ -852,7 +847,7 @@ void main() { #ifdef NORMAL_USED if (scene_data.roughness_limiter_enabled) { - //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf + //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; vec3 dndu = dFdx(normal), dndv = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); @@ -1392,7 +1387,7 @@ void main() { break; } - float shadow = light_process_omni_shadow(light_index, vertex, view); + float shadow = light_process_omni_shadow(light_index, vertex, normal); shadow = blur_shadow(shadow); @@ -1440,7 +1435,7 @@ void main() { break; } - float shadow = light_process_spot_shadow(light_index, vertex, view); + float shadow = light_process_spot_shadow(light_index, vertex, normal); shadow = blur_shadow(shadow); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index f1e554d01c..dd8879acb4 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -93,7 +93,7 @@ directional_lights; #define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2 struct Lightmap { - mat3 normal_xform; + mediump mat3 normal_xform; }; layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps { @@ -102,7 +102,7 @@ layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps { lightmaps; struct LightmapCapture { - vec4 sh[9]; + mediump vec4 sh[9]; }; layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures { @@ -110,8 +110,8 @@ layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures } lightmap_captures; -layout(set = 0, binding = 11) uniform texture2D decal_atlas; -layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb; +layout(set = 0, binding = 11) uniform mediump texture2D decal_atlas; +layout(set = 0, binding = 12) uniform mediump texture2D decal_atlas_srgb; layout(set = 0, binding = 13, std430) restrict readonly buffer Decals { DecalData data[]; @@ -119,7 +119,7 @@ layout(set = 0, binding = 13, std430) restrict readonly buffer Decals { decals; layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData { - vec4 data[]; + highp vec4 data[]; } global_variables; @@ -135,56 +135,56 @@ layout(set = 1, binding = 0, std140) uniform SceneData { highp mat4 projection_matrix_view[MAX_VIEWS]; highp mat4 inv_projection_matrix_view[MAX_VIEWS]; - vec2 viewport_size; - vec2 screen_pixel_size; + highp vec2 viewport_size; + highp vec2 screen_pixel_size; // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted. - vec4 directional_penumbra_shadow_kernel[32]; - vec4 directional_soft_shadow_kernel[32]; - vec4 penumbra_shadow_kernel[32]; - vec4 soft_shadow_kernel[32]; + highp vec4 directional_penumbra_shadow_kernel[32]; + highp vec4 directional_soft_shadow_kernel[32]; + highp vec4 penumbra_shadow_kernel[32]; + highp vec4 soft_shadow_kernel[32]; - vec4 ambient_light_color_energy; + mediump vec4 ambient_light_color_energy; - float ambient_color_sky_mix; + mediump float ambient_color_sky_mix; bool use_ambient_light; bool use_ambient_cubemap; bool use_reflection_cubemap; - mat3 radiance_inverse_xform; + mediump mat3 radiance_inverse_xform; - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; + highp vec2 shadow_atlas_pixel_size; + highp vec2 directional_shadow_pixel_size; uint directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; + mediump float dual_paraboloid_side; + highp float z_far; + highp float z_near; bool ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; + mediump float ssao_light_affect; + mediump float ssao_ao_affect; bool roughness_limiter_enabled; - float roughness_limiter_amount; - float roughness_limiter_limit; + mediump float roughness_limiter_amount; + mediump float roughness_limiter_limit; uvec2 roughness_limiter_pad; - vec4 ao_color; + mediump vec4 ao_color; bool fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; + highp float fog_density; + highp float fog_height; + highp float fog_height_density; - vec3 fog_light_color; - float fog_sun_scatter; + mediump vec3 fog_light_color; + mediump float fog_sun_scatter; - float fog_aerial_perspective; + mediump float fog_aerial_perspective; bool material_uv2_mode; - float time; - float reflection_multiplier; // one normally, zero when rendering reflections + highp float time; + mediump float reflection_multiplier; // one normally, zero when rendering reflections bool pancake_shadows; uint pad1; @@ -195,30 +195,30 @@ scene_data; #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap; #else -layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; +layout(set = 1, binding = 2) uniform mediump textureCube radiance_cubemap; #endif -layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 3) uniform mediump textureCubeArray reflection_atlas; -layout(set = 1, binding = 4) uniform texture2D shadow_atlas; +layout(set = 1, binding = 4) uniform highp texture2D shadow_atlas; -layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; +layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas; // this needs to change to providing just the lightmap we're using.. layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; -layout(set = 1, binding = 9) uniform texture2D depth_buffer; -layout(set = 1, binding = 10) uniform texture2D color_buffer; +layout(set = 1, binding = 9) uniform highp texture2D depth_buffer; +layout(set = 1, binding = 10) uniform mediump texture2D color_buffer; /* Set 2 Skeleton & Instancing (can change per item) */ layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { - vec4 data[]; + highp vec4 data[]; } transforms; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl index 0eacbc5363..4290d5b869 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl @@ -24,7 +24,7 @@ layout(push_constant, binding = 0, std430) uniform Params { } params; -// http://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm +// https://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm vec3 get_sphere_vertex(uint p_vertex_id) { float x_angle = float(p_vertex_id & 1u) + (p_vertex_id >> params.band_power); diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 3c685c25b9..f997101183 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -37,15 +37,15 @@ layout(location = 0) in vec2 uv_interp; #ifdef SUBPASS layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color; -#else -#if MULTIVIEW +#elif defined(MULTIVIEW) layout(set = 0, binding = 0) uniform sampler2DArray source_color; #else layout(set = 0, binding = 0) uniform sampler2D source_color; #endif -#endif + layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; + #ifdef USE_1D_LUT layout(set = 3, binding = 0) uniform sampler2D source_color_correction; #else @@ -349,7 +349,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { } #endif // !SUBPASS -// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// From https://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) { @@ -365,7 +365,7 @@ void main() { #ifdef SUBPASS // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer vec3 color = subpassLoad(input_color).rgb; -#elif MULTIVIEW +#elif defined(MULTIVIEW) vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb; #else vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 4a4976718c..cd8014632d 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -2180,8 +2180,6 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); - Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); - RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { @@ -2215,7 +2213,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, radius); + cm.set_perspective(90, 1, radius * 0.005f, radius); for (int i = 0; i < 6; i++) { RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); @@ -2301,7 +2299,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; - cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); + cm.set_perspective(angle * 2.0, 1.0, 0.005f * radius, radius); Vector<Plane> planes = cm.get_projection_planes(light_transform); @@ -2794,12 +2792,9 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c //rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal); - Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform); - - Plane near_plane(p_camera_data->main_transform.origin, -p_camera_data->main_transform.basis.get_axis(2).normalized()); - /* STEP 2 - CULL */ + Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform); cull.frustum = Frustum(planes); Vector<RID> directional_lights; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 20fcb1396d..4218214fda 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -2877,6 +2877,27 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) { return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT; } +bool ShaderLanguage::is_float_type(DataType p_type) { + switch (p_type) { + case TYPE_FLOAT: + case TYPE_VEC2: + case TYPE_VEC3: + case TYPE_VEC4: + case TYPE_MAT2: + case TYPE_MAT3: + case TYPE_MAT4: + case TYPE_SAMPLER2D: + case TYPE_SAMPLER2DARRAY: + case TYPE_SAMPLER3D: + case TYPE_SAMPLERCUBE: + case TYPE_SAMPLERCUBEARRAY: { + return true; + } + default: { + return false; + } + } +} bool ShaderLanguage::is_sampler_type(DataType p_type) { return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 9e0a63f0f7..18525e054e 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -774,6 +774,7 @@ public: static DataType get_scalar_type(DataType p_type); static int get_cardinality(DataType p_type); static bool is_scalar_type(DataType p_type); + static bool is_float_type(DataType p_type); static bool is_sampler_type(DataType p_type); static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 4488069698..0bfcccef28 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -342,7 +342,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; - shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); |