diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 5fd90744a42..5d7ce6418d2 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1636,7 +1636,7 @@ void RasterizerCanvasGLES3::light_set_use_shadow(RID p_rid, bool p_enable) { cl->shadow.enabled = p_enable; } -void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { +void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) { GLES3::Config *config = GLES3::Config::get_singleton(); CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index e099fd0cc02..25e72106152 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -343,7 +343,7 @@ public: RID light_create() override; void light_set_texture(RID p_rid, RID p_texture) override; void light_set_use_shadow(RID p_rid, bool p_enable) override; - void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override; + void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) override; void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override; void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override; diff --git a/servers/rendering/dummy/rasterizer_canvas_dummy.h b/servers/rendering/dummy/rasterizer_canvas_dummy.h index d61ee1bdb6e..93f517828a9 100644 --- a/servers/rendering/dummy/rasterizer_canvas_dummy.h +++ b/servers/rendering/dummy/rasterizer_canvas_dummy.h @@ -43,7 +43,7 @@ public: RID light_create() override { return RID(); } void light_set_texture(RID p_rid, RID p_texture) override {} void light_set_use_shadow(RID p_rid, bool p_enable) override {} - void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override {} + void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) override {} void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override {} void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override {} diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 328fe32ea6c..e91eb768343 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -531,7 +531,7 @@ public: virtual RID light_create() = 0; virtual void light_set_texture(RID p_rid, RID p_texture) = 0; virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0; - virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; + virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) = 0; virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0; virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 85b0a0763b8..8940c1d110c 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -985,7 +985,34 @@ void RendererCanvasRenderRD::_update_shadow_atlas() { } } -void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { +void RendererCanvasRenderRD::_update_occluder_buffer(uint32_t p_size) { + bool needs_update = state.shadow_occluder_buffer.is_null(); + + if (p_size > state.shadow_occluder_buffer_size) { + needs_update = true; + state.shadow_occluder_buffer_size = next_power_of_2(p_size); + if (state.shadow_occluder_buffer.is_valid()) { + RD::get_singleton()->free(state.shadow_occluder_buffer); + } + } + + if (needs_update) { + state.shadow_occluder_buffer = RD::get_singleton()->storage_buffer_create(state.shadow_occluder_buffer_size); + + Vector uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.append_id(state.shadow_occluder_buffer); + uniforms.push_back(u); + } + state.shadow_ocluder_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_POSITIONAL_SHADOW), 0); + } +} + +void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) { CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); @@ -996,75 +1023,97 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, Vector cc; cc.push_back(Color(p_far, p_far, p_far, 1.0)); - Projection projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; + // First, do a culling pass and record what occluders need to be drawn for this light. + static thread_local LocalVector occluders; + static thread_local LocalVector occluder_indices; + occluders.clear(); + occluder_indices.clear(); - real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; + uint32_t occluder_count = 0; - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + LightOccluderInstance *instance = p_occluders; + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); + + if (!co || co->index_array.is_null()) { + instance = instance->next; + continue; + } + + occluder_count++; + + if (!(p_light_mask & instance->light_mask) || !p_light_rect.intersects(instance->aabb_cache)) { + instance = instance->next; + continue; + } + + occluders.push_back(co); + occluder_indices.push_back(occluder_count - 1); + + instance = instance->next; } - // Precomputed: - // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); - // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); - const Projection projections[4] = { - projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - - projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - - projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)), - - projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)) - - }; - - for (int i = 0; i < 4; i++) { - Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::DRAW_CLEAR_ALL, cc, 1.0f, 0, rect); - - ShadowRenderPushConstant push_constant; - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - push_constant.projection[y * 4 + x] = projections[i].columns[y][x]; - } - } - static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; - push_constant.direction[0] = directions[i].x; - push_constant.direction[1] = directions[i].y; - push_constant.z_far = p_far; - push_constant.pad = 0; - - LightOccluderInstance *instance = p_occluders; + // Then, upload all the occluder transforms to a shared buffer. + // We only do this for the first light so we can avoid uploading the same + // Transforms over and over again. + if (p_shadow_index == 0) { + static thread_local LocalVector transforms; + transforms.clear(); + transforms.resize(occluder_count * 8); + instance = p_occluders; + uint32_t index = 0; while (instance) { - OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); - - if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { - instance = instance->next; - continue; - } - - _update_transform_2d_to_mat2x4(p_light_xform * instance->xform_cache, push_constant.modelview); - - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]); - RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); - RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); - - RD::get_singleton()->draw_list_draw(draw_list, true); - + _update_transform_2d_to_mat2x4(instance->xform_cache, &transforms[index * 8]); + index++; instance = instance->next; } - RD::get_singleton()->draw_list_end(); + _update_occluder_buffer(occluder_count * 8 * sizeof(float)); + RD::get_singleton()->buffer_update(state.shadow_occluder_buffer, 0, transforms.size() * sizeof(float), transforms.ptr()); } + + Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::DRAW_CLEAR_ALL, cc, 1.0f, 0, rect); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[SHADOW_RENDER_MODE_POSITIONAL_SHADOW]); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.shadow_ocluder_uniform_set, 0); + + for (int i = 0; i < 4; i++) { + Rect2i sub_rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); + RD::get_singleton()->draw_list_set_viewport(draw_list, sub_rect); + + static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) }; + static const Vector4 rotations[4] = { Vector4(0, -1, 1, 0), Vector4(-1, 0, 0, -1), Vector4(0, 1, -1, 0), Vector4(1, 0, 0, 1) }; + + PositionalShadowRenderPushConstant push_constant; + _update_transform_2d_to_mat2x4(p_light_xform, push_constant.modelview); + push_constant.direction[0] = directions[i].x; + push_constant.direction[1] = directions[i].y; + push_constant.rotation[0] = rotations[i].x; + push_constant.rotation[1] = rotations[i].y; + push_constant.rotation[2] = rotations[i].z; + push_constant.rotation[3] = rotations[i].w; + push_constant.z_far = p_far; + push_constant.z_near = p_near; + + for (uint32_t j = 0; j < occluders.size(); j++) { + OccluderPolygon *co = occluders[j]; + + push_constant.pad = occluder_indices[j]; + push_constant.cull_mode = uint32_t(co->cull_mode); + + // The slowest part about this whole function is that we have to draw the occluders one by one, 4 times. + // We can optimize this so that all occluders draw at once if we store vertices and indices in a giant + // SSBO and just save an index into that SSBO for each occluder. + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PositionalShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + } + } + RD::get_singleton()->draw_list_end(); } void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { @@ -1099,6 +1148,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::DRAW_CLEAR_ALL, cc, 1.0f, 0, rect); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[SHADOW_RENDER_MODE_DIRECTIONAL_SHADOW]); Projection projection; projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); @@ -1114,7 +1164,6 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh push_constant.direction[0] = 0.0; push_constant.direction[1] = 1.0; push_constant.z_far = distance; - push_constant.pad = 0; LightOccluderInstance *instance = p_occluders; @@ -1127,8 +1176,8 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh } _update_transform_2d_to_mat2x4(to_light_xform * instance->xform_cache, push_constant.modelview); + push_constant.cull_mode = uint32_t(co->cull_mode); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]); RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); @@ -1182,7 +1231,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan push_constant.direction[0] = 0.0; push_constant.direction[1] = 0.0; push_constant.z_far = 0; - push_constant.pad = 0; + push_constant.cull_mode = 0; LightOccluderInstance *instance = p_occluders; @@ -1791,8 +1840,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { { //shadow rendering Vector versions; - versions.push_back("\n#define MODE_SHADOW\n"); //shadow - versions.push_back("\n#define MODE_SDF\n"); //sdf + versions.push_back("\n#define MODE_SHADOW\n"); // Shadow. + versions.push_back("\n#define MODE_SHADOW\n#define POSITIONAL_SHADOW\n"); // Positional shadow. + versions.push_back("\n#define MODE_SDF\n"); // SDF. shadow_render.shader.initialize(versions); { @@ -1843,14 +1893,13 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { shadow_render.shader_version = shadow_render.shader.version_create(); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 2; i++) { RD::PipelineRasterizationState rs; - rs.cull_mode = i == 0 ? RD::POLYGON_CULL_DISABLED : (i == 1 ? RD::POLYGON_CULL_FRONT : RD::POLYGON_CULL_BACK); RD::PipelineDepthStencilState ds; ds.enable_depth_write = true; ds.enable_depth_test = true; ds.depth_compare_operator = RD::COMPARE_OP_LESS; - shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, ShadowRenderMode(i)), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } for (int i = 0; i < 2; i++) { @@ -1858,7 +1907,8 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { } // Unload shader modules to save memory. - RD::get_singleton()->shader_destroy_modules(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW)); + RD::get_singleton()->shader_destroy_modules(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_DIRECTIONAL_SHADOW)); + RD::get_singleton()->shader_destroy_modules(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_POSITIONAL_SHADOW)); RD::get_singleton()->shader_destroy_modules(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SDF)); } @@ -3251,6 +3301,10 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() { } RD::get_singleton()->free(state.shadow_texture); + if (state.shadow_occluder_buffer.is_valid()) { + RD::get_singleton()->free(state.shadow_occluder_buffer); + } + memdelete_arr(state.instance_data_array); for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) { for (uint32_t j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index e4f1779b09a..1749cb5e346 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -268,12 +268,23 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID_Owner canvas_light_owner; + struct PositionalShadowRenderPushConstant { + float modelview[8]; + float rotation[4]; + float direction[2]; + float z_far; + uint32_t pad; + float z_near; + uint32_t cull_mode; + float pad2[2]; + }; + struct ShadowRenderPushConstant { float projection[16]; float modelview[8]; float direction[2]; float z_far; - float pad; + uint32_t cull_mode; }; struct OccluderPolygon { @@ -313,7 +324,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID_Owner occluder_polygon_owner; enum ShadowRenderMode { - SHADOW_RENDER_MODE_SHADOW, + SHADOW_RENDER_MODE_DIRECTIONAL_SHADOW, + SHADOW_RENDER_MODE_POSITIONAL_SHADOW, SHADOW_RENDER_MODE_SDF, }; @@ -325,7 +337,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct { CanvasOcclusionShaderRD shader; RID shader_version; - RID render_pipelines[3]; + RID render_pipelines[2]; RID sdf_render_pipelines[2]; RD::VertexFormatID vertex_format; RD::VertexFormatID sdf_vertex_format; @@ -564,6 +576,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID shadow_fb; int shadow_texture_size = 2048; + RID shadow_occluder_buffer; + uint32_t shadow_occluder_buffer_size; + RID shadow_ocluder_uniform_set; + RID default_transforms_uniform_set; uint32_t max_lights_per_render; @@ -617,6 +633,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { _FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4); void _update_shadow_atlas(); + void _update_occluder_buffer(uint32_t p_size); public: PolygonID request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()) override; @@ -625,7 +642,7 @@ public: RID light_create() override; void light_set_texture(RID p_rid, RID p_texture) override; void light_set_use_shadow(RID p_rid, bool p_enable) override; - void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override; + void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) override; void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override; virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override; diff --git a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl index 930cf792cbb..c3162a9c1f8 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl @@ -6,26 +6,69 @@ layout(location = 0) in highp vec3 vertex; +#ifdef POSITIONAL_SHADOW +layout(push_constant, std430) uniform Constants { + mat2x4 modelview; + vec4 rotation; + vec2 direction; + float z_far; + uint pad; + float z_near; + uint cull_mode; + float pad3; + float pad4; +} +constants; + +layout(set = 0, binding = 0, std430) restrict readonly buffer OccluderTransforms { + mat2x4 transforms[]; +} +occluder_transforms; + +#else + layout(push_constant, std430) uniform Constants { mat4 projection; mat2x4 modelview; vec2 direction; float z_far; - float pad; + uint cull_mode; } constants; +#endif + #ifdef MODE_SHADOW layout(location = 0) out highp float depth; #endif void main() { - highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); +#ifdef POSITIONAL_SHADOW + float c = -(constants.z_far + constants.z_near) / (constants.z_far - constants.z_near); + float d = -2.0 * constants.z_far * constants.z_near / (constants.z_far - constants.z_near); + + mat4 projection = mat4(vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, c, -1.0), + vec4(0.0, 0.0, d, 0.0)); + + // Precomputed: + // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); + // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse()); + projection *= mat4(vec4(constants.rotation.x, 0.0, constants.rotation.y, 0.0), vec4(constants.rotation.z, 0.0, constants.rotation.w, 0.0), vec4(0.0, -1.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + mat4 modelview = mat4(occluder_transforms.transforms[constants.pad]) * mat4(constants.modelview); +#else + mat4 projection = constants.projection; + mat4 modelview = mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); +#endif + + highp vec4 vtx = vec4(vertex, 1.0) * modelview; #ifdef MODE_SHADOW depth = dot(constants.direction, vtx.xy); #endif - gl_Position = constants.projection * vtx; + + gl_Position = projection * vtx; } #[fragment] @@ -34,15 +77,33 @@ void main() { #VERSION_DEFINES +#ifdef POSITIONAL_SHADOW +layout(push_constant, std430) uniform Constants { + mat2x4 modelview; + vec4 rotation; + vec2 direction; + float z_far; + uint pad; + float z_near; + uint cull_mode; + float pad3; + float pad4; +} +constants; + +#else + layout(push_constant, std430) uniform Constants { mat4 projection; mat2x4 modelview; vec2 direction; float z_far; - float pad; + uint cull_mode; } constants; +#endif + #ifdef MODE_SHADOW layout(location = 0) in highp float depth; layout(location = 0) out highp float distance_buf; @@ -50,8 +111,18 @@ layout(location = 0) out highp float distance_buf; layout(location = 0) out highp float sdf_buf; #endif +#define POLYGON_CULL_DISABLED 0 +#define POLYGON_CULL_FRONT 1 +#define POLYGON_CULL_BACK 2 + void main() { #ifdef MODE_SHADOW + bool front_facing = gl_FrontFacing; + if (constants.cull_mode == POLYGON_CULL_BACK && !front_facing) { + discard; + } else if (constants.cull_mode == POLYGON_CULL_FRONT && front_facing) { + discard; + } distance_buf = depth / constants.z_far; #else sdf_buf = 1.0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 4d6435f48a5..5251a7ece62 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -498,7 +498,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { while (light) { RENDER_TIMESTAMP("Render PointLight2D Shadow"); - RSG::canvas_render->light_update_shadow(light->light_internal, shadow_count++, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders); + RSG::canvas_render->light_update_shadow(light->light_internal, shadow_count++, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, light->rect_cache); light = light->shadows_next_ptr; }