Commit: 97b0719f7dc10159ca45fabc54496647ff070e6f Author: Miguel Pozo Date: Mon Dec 12 12:33:50 2022 +0100 Branches: tmp-workbench-rewrite2 https://developer.blender.org/rB97b0719f7dc10159ca45fabc54496647ff070e6f
WIP: Compute based culling for workbench shadows =================================================================== M source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh A source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl M source/blender/draw/engines/workbench/workbench_shadow.cc M source/blender/draw/intern/draw_view.hh =================================================================== diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh index a77af467ec8..ad6b3560117 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "draw_defines.h" + #include "gpu_shader_create_info.hh" /* -------------------------------------------------------------------- */ @@ -29,6 +31,20 @@ GPU_SHADER_CREATE_INFO(workbench_next_shadow_common) .additional_info("draw_modelmat_new") .additional_info("draw_resource_handle_new"); +GPU_SHADER_CREATE_INFO(workbench_next_shadow_visibility_compute) + .do_static_compilation(true) + .local_group_size(DRW_VISIBILITY_GROUP_SIZE) + .define("DRW_VIEW_LEN", "64") + .storage_buf(0, Qualifier::READ, "ObjectBounds", "bounds_buf[]") + .storage_buf(1, Qualifier::READ_WRITE, "uint", "visibility_buf[]") + .storage_buf(2, Qualifier::READ, "uint", "pass_technique_buf[]") + .push_constant(Type::INT, "resource_len") + .push_constant(Type::INT, "view_len") + .push_constant(Type::INT, "visibility_word_per_draw") + .push_constant(Type::VEC3, "shadow_direction") + .compute_source("draw_visibility_comp.glsl") + .additional_info("draw_view", "draw_view_culling"); + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl new file mode 100644 index 00000000000..7e89120a79f --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl @@ -0,0 +1,53 @@ + +/** + * Compute visibility of each resource bounds for a given view. + */ +/* TODO(fclem): This could be augmented by a 2 pass occlusion culling system. */ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_intersect_lib.glsl) + +shared uint shared_result; + +void mask_visibility_bit(uint view_id) +{ + if (view_len > 1) { + uint index = gl_GlobalInvocationID.x * uint(visibility_word_per_draw) + (view_id / 32u); + visibility_buf[index] &= ~(1u << view_id); + } + else { + atomicAnd(visibility_buf[gl_WorkGroupID.x], ~(1u << gl_LocalInvocationID.x)); + } +} + +void main() +{ + if (gl_GlobalInvocationID.x >= resource_len) { + return; + } + + ObjectBounds bounds = bounds_buf[gl_GlobalInvocationID.x]; + + if (bounds.bounding_sphere.w != -1.0) { + IsectBox box = isect_data_setup(bounds.bounding_corners[0].xyz, + bounds.bounding_corners[1].xyz, + bounds.bounding_corners[2].xyz, + bounds.bounding_corners[3].xyz); + Sphere bounding_sphere = Sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); + Sphere inscribed_sphere = Sphere(bounds.bounding_sphere.xyz, bounds._inner_sphere_radius); + + for (drw_view_id = 0; drw_view_id < view_len; drw_view_id++) { + if (intersect_view(inscribed_sphere) == true) { + /* Visible. */ + } + else if (intersect_view(bounding_sphere) == false) { + /* Not visible. */ + mask_visibility_bit(drw_view_id); + } + else if (intersect_view(box) == false) { + /* Not visible. */ + mask_visibility_bit(drw_view_id); + } + } + } +} diff --git a/source/blender/draw/engines/workbench/workbench_shadow.cc b/source/blender/draw/engines/workbench/workbench_shadow.cc index 3632cc54f5a..21d092eaba9 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.cc +++ b/source/blender/draw/engines/workbench/workbench_shadow.cc @@ -17,13 +17,117 @@ #include "BKE_object.h" #include "BLI_math.h" #include "DRW_render.h" +#include "GPU_compute.h" #include "workbench_private.hh" +#include "draw_shader.h" //REMOVE! + #define DEBUG_SHADOW_VOLUME 0 +#define GPU_CULLING 0 namespace blender::workbench { +class ShadowView : public View { + float3 direction_; + + public: + ShadowView(const char *name, View &view, float3 direction) : View(name) + { + // TODO(Miguel Pozo): view_len_ ? + direction = direction_; + sync(view.viewmat(), view.winmat()); + } + + protected: + std::array<float3, 8> frustum_corners(float4x4 view_from_world_matrix, float near, float far) + { + float4x4 matrix = view_from_world_matrix.inverted(); + std::array<float3, 8> corners = {}; + + int i = 0; + for (float x : {-1, 1}) { + for (float y : {-1, 1}) { + for (float z : {near, far}) { + float4 corner = float4(x, y, z, 1); + mul_m4_v4(matrix.ptr(), corner); + corner /= corner.w; + corners[i++] = float3(corner); + } + } + } + + return corners; + } + + float4x4 shadow_projection_matrix(float4x4 light_from_world_matrix, + float4x4 view_from_world_matrix, + float near, + float far) + { + /* WIP: Should be replaced with an extruded frustum */ + float3 min, max; + INIT_MINMAX(min, max); + + BoundBox frustum_corners; + DRW_culling_frustum_corners_get(nullptr, &frustum_corners); + + for (float3 corner : frustum_corners.vec) { + corner = light_from_world_matrix * corner; + math::min_max(corner, min, max); + } + + float4x4 world_from_light_space = light_from_world_matrix.inverted(); + + float3 size = max - min; + float3 scale = 1.0 / (size / 2.0); + + float4x4 scale_matrix; + size_to_mat4(scale_matrix.ptr(), scale); + + min = world_from_light_space * min; + max = world_from_light_space * max; + float3 center = (min + max) / 2.0; + + float4x4 translate_matrix = float4x4::from_location(-center); + + return scale_matrix * translate_matrix * light_from_world_matrix; + } + + virtual void compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze) + { + GPU_debug_group_begin("ShadowView.compute_visibility"); + + uint word_per_draw = this->visibility_word_per_draw(); + /* Switch between tightly packed and set of whole word per instance. */ + uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) : + resource_len * word_per_draw; + words_len = ceil_to_multiple_u(max_ii(1, words_len), 4); + /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ + visibility_buf_.resize(words_len); + + uint32_t data = 0xFFFFFFFFu; + GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + + if (do_visibility_) { + static GPUShader *shader = GPU_shader_create_from_info_name( + "workbench_next_shadow_visibility_compute"); + GPU_shader_bind(shader); + GPU_shader_uniform_1i(shader, "resource_len", resource_len); + GPU_shader_uniform_1i(shader, "view_len", view_len_); + GPU_shader_uniform_1i(shader, "visibility_word_per_draw", word_per_draw); + GPU_shader_uniform_3fv(shader, "shadow_direction", direction_); + GPU_storagebuf_bind(bounds, GPU_shader_get_ssbo(shader, "bounds_buf")); + GPU_storagebuf_bind(visibility_buf_, GPU_shader_get_ssbo(shader, "visibility_buf")); + GPU_uniformbuf_bind(data_, DRW_VIEW_UBO_SLOT); + GPU_compute_dispatch(shader, divide_ceil_u(resource_len, DRW_VISIBILITY_GROUP_SIZE), 1, 1); + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); + } + + GPU_debug_group_end(); + } +}; + static void compute_parallel_lines_nor_and_dist(const float2 v1, const float2 v2, const float2 v3, @@ -206,6 +310,18 @@ void ShadowPass::object_sync(Manager &manager, return; } +#if GPU_CULLING + /* WIP: Everything is drawn with the Pass method */ + PassMain::Sub &ps = *get_pass_ptr(true, is_manifold); + ps.push_constant("lightDirection", float4x4(ob->world_to_object).ref_3x3() * direction_ws); + ps.push_constant("lightDistance", 1e5f); + ResourceHandle handle = manager.resource_handle(ob_ref); + ps.draw(geom_shadow, handle); +# if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&object_data.bbox, float4(1.0f, 0.0f, 0.0f, 1.0f)); +# endif +#else + ObjectData *engine_object_data = (ObjectData *)DRW_drawdata_ensure( &ob->id, &draw_engine_workbench_next, sizeof(ObjectData), &ObjectData::init, nullptr); @@ -236,9 +352,9 @@ void ShadowPass::object_sync(Manager &manager, ps.push_constant("lightDistance", 1e5f); ResourceHandle handle = manager.resource_handle(ob_ref); ps.draw(geom_shadow, handle); -#if DEBUG_SHADOW_VOLUME +# if DEBUG_SHADOW_VOLUME DRW_debug_bbox(&object_data.bbox, float4(1.0f, 0.0f, 0.0f, 1.0f)); -#endif +# endif } else { float extrude_distance = object_data.shadow_distance(ob, *this); @@ -258,11 +374,12 @@ void ShadowPass::object_sync(Manager &manager, ps.push_constant("lightDistance", extrude_distance); ResourceHandle handle = manager.resource_handle(ob_ref); ps.draw(geom_shadow, handle); -#if DEBUG_SHADOW_VOLUME +# if DEBUG_SHADOW_VOLUME DRW_debug_bbox(&object_data.bbox, float4(1.0f, 0.0f, 0.0f, 1.0f)); -#endif +# endif } } +#endif } void ShadowPass::draw(Manager &manager, View &view, SceneResources &resources, int2 resolution) @@ -276,8 +393,15 @@ void ShadowPass::draw(Manager &manager, View &view, SceneResources &resources, i GPU_ATTACHMENT_TEXTURE(resources.color_tx)); fb.bind(); +#if GPU_CULLING + ShadowView shadow_view = ShadowView("ShadowView", view, direction_ws); + + manager.submit(pass_ps, shadow_view); + manager.submit(fail_ps, shadow_view); +#else manager.submit(pass_ps, view); manager.submit(fail_ps, view); +#endif } void ObjectShadowData::init() diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh index 5c5f20df1c3..fb21be511ad 100644 --- a/source/blend @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs