[Bf-blender-cvs] [97b0719f7dc] tmp-workbench-rewrite2: WIP: Compute based culling for workbench shadows

Miguel Pozo noreply at git.blender.org
Mon Dec 12 12:34:53 CET 2022


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. @@



More information about the Bf-blender-cvs mailing list