Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-08-22 18:14:16 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-08-22 21:55:09 +0300
commit46dc57af82e629b854ad4af12ccb3e43ea509b0e (patch)
tree8745e248d93efcabc822d9b965dc786c6438af7d
parentacfce5c4eb77e225ae1465c7043f5ec724abc314 (diff)
Add View support with visibility culling
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/intern/draw_defines.h7
-rw-r--r--source/blender/draw/intern/draw_handle.hh15
-rw-r--r--source/blender/draw/intern/draw_manager.cc15
-rw-r--r--source/blender/draw/intern/draw_manager.hh30
-rw-r--r--source/blender/draw/intern/draw_resource.hh73
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h12
-rw-r--r--source/blender/draw/intern/draw_view.cc292
-rw-r--r--source/blender/draw/intern/draw_view.hh44
-rw-r--r--source/blender/draw/intern/shaders/common_intersect_lib.glsl68
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh11
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh47
-rw-r--r--source/blender/draw/intern/shaders/draw_visibility_comp.glsl30
13 files changed, 548 insertions, 99 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 3aef9f776b6..377baeb8361 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -232,8 +232,9 @@ set(SRC
intern/draw_shader.h
intern/draw_subdivision.h
intern/draw_texture_pool.h
- intern/draw_view.h
intern/draw_view_data.h
+ intern/draw_view.cc
+ intern/draw_view.h
intern/mesh_extractors/extract_mesh.hh
intern/smaa_textures.h
engines/basic/basic_engine.h
diff --git a/source/blender/draw/intern/draw_defines.h b/source/blender/draw/intern/draw_defines.h
index 9ab57284f8c..a8731dedaf8 100644
--- a/source/blender/draw/intern/draw_defines.h
+++ b/source/blender/draw/intern/draw_defines.h
@@ -11,8 +11,13 @@
#pragma once
+#define DRW_VIEW_UBO_SLOT 0
+
#define DRW_OBJ_MAT_SLOT 7
-#define DRW_OBJ_ATTR_SLOT 6
+#define DRW_COMMAND_SLOT 6
+#define DRW_OBJ_INFOS_SLOT 5
+#define DRW_OBJ_ATTR_SLOT 4
#define DRW_FINALIZE_GROUP_SIZE 64
+/* Must be multiple of 32. Set to 64 for optimal scheduling on GCN hardware. */
#define DRW_VISIBILITY_GROUP_SIZE 64 \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_handle.hh b/source/blender/draw/intern/draw_handle.hh
index 3696a578ea7..48f3391c9ed 100644
--- a/source/blender/draw/intern/draw_handle.hh
+++ b/source/blender/draw/intern/draw_handle.hh
@@ -18,11 +18,11 @@
* the origin.
*/
-#include "BKE_duplilist.h"
-#include "DNA_object_types.h"
-
#include "draw_shader_shared.h"
+struct Object;
+struct DupliObject;
+
namespace blender::draw {
struct ResourceHandle {
@@ -47,4 +47,13 @@ struct ResourceHandle {
}
};
+/* TODO(fclem): Move to somewhere more appropriated after cleaning up the header dependencies. */
+struct ObjectRef {
+ Object *object;
+ /** Dupli object that corresponds to the current object. */
+ DupliObject *dupli_object;
+ /** Object that created the dupli-list the current object is part of. */
+ Object *dupli_parent;
+};
+
}; // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc
index 45597ea8e42..b30fae953b8 100644
--- a/source/blender/draw/intern/draw_manager.cc
+++ b/source/blender/draw/intern/draw_manager.cc
@@ -54,16 +54,21 @@ void Manager::submit(const PassSimple &pass)
pass.submit(state);
}
-#if 0
-void Manager::submit(const PassMain &pass, const View &view)
+void Manager::submit(const PassMain &pass, View &view)
{
- view.compute_visilibity(bounds_buf, resource_len);
+ view.bind();
- GPU_uniformbuf_bind(view);
+ view.compute_visibility(bounds_buf, resource_len);
+
+ // GPU_storagebuf_bind(pass.commands_, DRW_COMMAND_SLOT);
+ GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
+ GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
+ // GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */
+
+ // pass.generate_commands(state);
command::RecordingState state;
pass.submit(state);
}
-#endif
} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh
index c5160a81a5c..d84f4de8ca1 100644
--- a/source/blender/draw/intern/draw_manager.hh
+++ b/source/blender/draw/intern/draw_manager.hh
@@ -11,19 +11,13 @@
#include "BLI_sys_types.h"
#include "draw_pass.hh"
+#include "draw_resource.hh"
+#include "draw_view.hh"
#include <string>
namespace blender::draw {
-struct ObjectRef {
- Object *object;
- /** Dupli object that corresponds to the current object. */
- DupliObject *dupli_object;
- /** Object that created the dupli-list the current object is part of. */
- Object *dupli_parent;
-};
-
class Manager {
using ObjectMatricesBuf = StorageArrayBuffer<ObjectMatrices, 128>;
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
@@ -59,14 +53,16 @@ class Manager {
/**
* Populate additional per resource data on demand.
*/
- void object_attributes(ResourceHandle handle, Object &object, Span<GPUMaterial *> materials);
+ void extract_object_attributes(ResourceHandle handle,
+ Object &object,
+ Span<GPUMaterial *> materials);
/**
* Submit a pass for drawing. All resource reference will be dereferenced and commands will be
* sent to GPU.
*/
void submit(const PassSimple &pass);
- void submit(const PassMain &pass);
+ void submit(const PassMain &pass, View &view);
private:
/**
@@ -83,21 +79,21 @@ class Manager {
inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
{
bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
- matrix_buf.get_or_resize(resource_len).init(*ref.object);
- bounds_buf.get_or_resize(resource_len).init(*ref.object);
- infos_buf.get_or_resize(resource_len).init(ref, is_active_object);
+ matrix_buf.get_or_resize(resource_len).sync(*ref.object);
+ bounds_buf.get_or_resize(resource_len).sync(*ref.object);
+ infos_buf.get_or_resize(resource_len).sync(ref, is_active_object);
return ResourceHandle(resource_len++, (ref.object->transflag & OB_NEG_SCALE) != 0);
}
inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix)
{
- matrix_buf.get_or_resize(resource_len).init(model_matrix);
+ matrix_buf.get_or_resize(resource_len).sync(model_matrix);
return ResourceHandle(resource_len++, false);
}
-inline void Manager::object_attributes(ResourceHandle handle,
- Object &object,
- Span<GPUMaterial *> materials)
+inline void Manager::extract_object_attributes(ResourceHandle handle,
+ Object &object,
+ Span<GPUMaterial *> materials)
{
/* TODO */
(void)handle;
diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh
index 9761c83f964..68e3076d5fa 100644
--- a/source/blender/draw/intern/draw_resource.hh
+++ b/source/blender/draw/intern/draw_resource.hh
@@ -10,27 +10,34 @@
* Each of them are reference by resource index (#ResourceHandle).
*/
+#include "BKE_curve.h"
#include "BKE_duplilist.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_volume.h"
+#include "BLI_hash.h"
+#include "DNA_curve_types.h"
+#include "DNA_meta_types.h"
#include "DNA_object_types.h"
+#include "draw_handle.hh"
+#include "draw_manager.hh"
#include "draw_shader_shared.h"
-namespace blender::draw {
-
/* -------------------------------------------------------------------- */
/** \name ObjectMatrices
* \{ */
-void ObjectMatrices::sync(const Object &object)
+inline void ObjectMatrices::sync(const Object &object)
{
- model = object->obmat;
- model_inverse = object->imat;
+ model = object.obmat;
+ model_inverse = object.imat;
}
-void ObjectMatrices::sync(const float4x4 &object_mat)
+inline void ObjectMatrices::sync(const float4x4 &model_matrix)
{
- model = object_mat;
- model_inverse = object_mat.inverted();
+ model = model_matrix;
+ model_inverse = model_matrix.inverted();
}
/** \} */
@@ -39,53 +46,59 @@ void ObjectMatrices::sync(const float4x4 &object_mat)
/** \name ObjectInfos
* \{ */
-void ObjectInfos::sync(const draw::ObjectRef ref, bool is_active_object)
+ENUM_OPERATORS(eObjectInfoFlag, OBJECT_NEGATIVE_SCALE)
+
+inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active_object)
{
- color = ref.object.color;
- index = ref.object.index;
- SET_FLAG_FROM_TEST(flag, is_active_object, DRW_OBJECT_ACTIVE);
- SET_FLAG_FROM_TEST(flag, ref.object.base_flag & BASE_SELECTED, DRW_OBJECT_SELECTED);
- SET_FLAG_FROM_TEST(flag, ref.object.base_flag & BASE_FROM_DUPLI, DRW_OBJECT_FROM_DUPLI);
- SET_FLAG_FROM_TEST(flag, ref.object.base_flag & BASE_FROM_SET, DRW_OBJECT_FROM_SET);
- SET_FLAG_FROM_TEST(flag, ref.object.transflag & OB_NEG_SCALE, DRW_OBJECT_NEGATIVE_SCALE);
-
- if (ref.dupli == nullptr) {
- /* TODO(fclem): this is rather costly to do at runtime. Maybe we can
+ color = ref.object->color;
+ index = ref.object->index;
+ SET_FLAG_FROM_TEST(flag, is_active_object, eObjectInfoFlag::OBJECT_ACTIVE);
+ SET_FLAG_FROM_TEST(
+ flag, ref.object->base_flag & BASE_SELECTED, eObjectInfoFlag::OBJECT_SELECTED);
+ SET_FLAG_FROM_TEST(
+ flag, ref.object->base_flag & BASE_FROM_DUPLI, eObjectInfoFlag::OBJECT_FROM_DUPLI);
+ SET_FLAG_FROM_TEST(
+ flag, ref.object->base_flag & BASE_FROM_SET, eObjectInfoFlag::OBJECT_FROM_SET);
+ SET_FLAG_FROM_TEST(
+ flag, ref.object->transflag & OB_NEG_SCALE, eObjectInfoFlag::OBJECT_NEGATIVE_SCALE);
+
+ if (ref.dupli_object == nullptr) {
+ /* TODO(fclem): this is rather costly to do at draw time. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
- random = BLI_hash_int_2d(BLI_hash_string(ref.object.id.name + 2), 0) * (1.0f / 0xFFFFFFFF);
+ random = BLI_hash_int_2d(BLI_hash_string(ref.object->id.name + 2), 0) * (1.0f / 0xFFFFFFFF);
}
else {
- random = ref.dupli.random_id * (1.0f / 0xFFFFFFFF);
+ random = ref.dupli_object->random_id * (1.0f / 0xFFFFFFFF);
}
/* Default values. Set if needed. */
random = 0.0f;
- if (ref.object.data == nullptr) {
+ if (ref.object->data == nullptr) {
orco_add = float3(0.0f);
orco_mul = float3(1.0f);
return;
}
- switch (GS(ref.object.data->name)) {
+ switch (GS(reinterpret_cast<ID *>(ref.object->data)->name)) {
case ID_VO: {
- BoundBox &bbox = *BKE_volume_boundbox_get(object);
+ BoundBox &bbox = *BKE_volume_boundbox_get(ref.object);
orco_add = (float3(bbox.vec[6]) + float3(bbox.vec[0])) * 0.5f; /* Center. */
orco_mul = float3(bbox.vec[6]) - float3(bbox.vec[0]); /* Size. */
break;
}
case ID_ME: {
- BKE_mesh_texspace_get((Mesh *)ref.object.data, orco_add, orco_mul);
+ BKE_mesh_texspace_get((Mesh *)ref.object->data, orco_add, orco_mul);
break;
}
case ID_CU_LEGACY: {
- Curve &cu = *(Curve *)ref.object.data;
+ Curve &cu = *(Curve *)ref.object->data;
BKE_curve_texspace_ensure(&cu);
orco_add = cu.loc;
orco_mul = cu.size;
break;
}
case ID_MB: {
- MetaBall &mb = *(MetaBall *)ref.object.data;
+ MetaBall &mb = *(MetaBall *)ref.object->data;
orco_add = mb.loc;
orco_mul = mb.size;
break;
@@ -103,9 +116,9 @@ void ObjectInfos::sync(const draw::ObjectRef ref, bool is_active_object)
/** \name ObjectBounds
* \{ */
-void ObjectBounds::sync(const Object &ob)
+inline void ObjectBounds::sync(Object &ob)
{
- const BoundBox *bbox = BKE_object_boundbox_get(ob);
+ const BoundBox *bbox = BKE_object_boundbox_get(&ob);
if (bbox == nullptr) {
bounding_sphere.w = -1.0f; /* Disable test. */
return;
@@ -118,5 +131,3 @@ void ObjectBounds::sync(const Object &ob)
}
/** \} */
-
-}; // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 9ef5601f566..e343098aaf3 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -103,8 +103,8 @@ struct ObjectMatrices {
float4x4 model_inverse;
#if !defined(GPU_SHADER) && defined(__cplusplus)
- void init(const Object &object);
- void init(const float4x4 &object_mat);
+ void sync(const Object &object);
+ void sync(const float4x4 &model_matrix);
#endif
};
BLI_STATIC_ASSERT_ALIGN(ObjectMatrices, 16)
@@ -138,15 +138,11 @@ struct ObjectInfos {
#endif
#if !defined(GPU_SHADER) && defined(__cplusplus)
- void init(const blender::draw::ObjectRef ref, bool is_active_object);
+ void sync(const blender::draw::ObjectRef ref, bool is_active_object);
#endif
};
BLI_STATIC_ASSERT_ALIGN(ObjectInfos, 16)
-#define OrcoTexCoFactors (drw_infos[resource_id].orco_mul_bias)
-#define ObjectInfo (drw_infos[resource_id].infos)
-#define ObjectColor (drw_infos[resource_id].color)
-
struct ObjectBounds {
/**
* Uploaded as vertex (0, 4, 3, 1) of the bbox in local space, matching XYZ axis order.
@@ -157,7 +153,7 @@ struct ObjectBounds {
float4 bounding_sphere;
#if !defined(GPU_SHADER) && defined(__cplusplus)
- void init(const Object &object);
+ void sync(Object &ob);
#endif
};
BLI_STATIC_ASSERT_ALIGN(ObjectBounds, 16)
diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc
index 43147202e71..61e70df23e9 100644
--- a/source/blender/draw/intern/draw_view.cc
+++ b/source/blender/draw/intern/draw_view.cc
@@ -5,8 +5,300 @@
* \ingroup draw
*/
+#include "BLI_math_geom.h"
+#include "GPU_compute.h"
+
+#include "draw_shader.h"
#include "draw_view.hh"
namespace blender::draw {
+void View::bind()
+{
+ update_viewport_size();
+
+ if (dirty_) {
+ dirty_ = false;
+ data_.push_update();
+ }
+
+ GPU_uniformbuf_bind(data_, DRW_VIEW_UBO_SLOT);
+}
+
+void View::sync(const float4x4 &view_mat, const float4x4 &win_mat)
+{
+ data_.viewmat = view_mat;
+ data_.viewinv = view_mat.inverted();
+ data_.winmat = win_mat;
+ data_.wininv = win_mat.inverted();
+ data_.persmat = data_.winmat * data_.viewmat;
+ data_.persinv = data_.persmat.inverted();
+ /* Should not be used anymore. */
+ data_.viewcamtexcofac = float4(1.0f, 1.0f, 0.0f, 0.0f);
+
+ update_view_vectors();
+
+ BoundBox &bound_box = *reinterpret_cast<BoundBox *>(&data_.frustum_corners);
+ BoundSphere &bound_sphere = *reinterpret_cast<BoundSphere *>(&data_.frustum_bound_sphere);
+ frustum_boundbox_calc(bound_box);
+ frustum_culling_planes_calc();
+ frustum_culling_sphere_calc(bound_box, bound_sphere);
+
+ dirty_ = true;
+}
+
+void View::frustum_boundbox_calc(BoundBox &bbox)
+{
+ /* Extract the 8 corners from a Projection Matrix. */
+#if 0 /* Equivalent to this but it has accuracy problems. */
+ BKE_boundbox_init_from_minmax(&bbox, float3(-1.0f),float3(1.0f));
+ for (int i = 0; i < 8; i++) {
+ mul_project_m4_v3(data_.wininv.ptr(), bbox.vec[i]);
+ }
+#endif
+
+ float left, right, bottom, top, near, far;
+ bool is_persp = data_.winmat[3][3] == 0.0f;
+
+ projmat_dimensions(data_.winmat.ptr(), &left, &right, &bottom, &top, &near, &far);
+
+ bbox.vec[0][2] = bbox.vec[3][2] = bbox.vec[7][2] = bbox.vec[4][2] = -near;
+ bbox.vec[0][0] = bbox.vec[3][0] = left;
+ bbox.vec[4][0] = bbox.vec[7][0] = right;
+ bbox.vec[0][1] = bbox.vec[4][1] = bottom;
+ bbox.vec[7][1] = bbox.vec[3][1] = top;
+
+ /* Get the coordinates of the far plane. */
+ if (is_persp) {
+ float sca_far = far / near;
+ left *= sca_far;
+ right *= sca_far;
+ bottom *= sca_far;
+ top *= sca_far;
+ }
+
+ bbox.vec[1][2] = bbox.vec[2][2] = bbox.vec[6][2] = bbox.vec[5][2] = -far;
+ bbox.vec[1][0] = bbox.vec[2][0] = left;
+ bbox.vec[6][0] = bbox.vec[5][0] = right;
+ bbox.vec[1][1] = bbox.vec[5][1] = bottom;
+ bbox.vec[2][1] = bbox.vec[6][1] = top;
+
+ /* Transform into world space. */
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(data_.viewinv.ptr(), bbox.vec[i]);
+ }
+}
+
+void View::frustum_culling_planes_calc()
+{
+ planes_from_projmat(data_.persmat.ptr(),
+ data_.frustum_planes[0],
+ data_.frustum_planes[5],
+ data_.frustum_planes[1],
+ data_.frustum_planes[3],
+ data_.frustum_planes[4],
+ data_.frustum_planes[2]);
+
+ /* Normalize. */
+ for (int p = 0; p < 6; p++) {
+ data_.frustum_planes[p].w /= normalize_v3(data_.frustum_planes[p]);
+ }
+}
+
+void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere)
+{
+ /* Extract Bounding Sphere */
+ if (data_.winmat[3][3] != 0.0f) {
+ /* Orthographic */
+ /* The most extreme points on the near and far plane. (normalized device coords). */
+ const float *nearpoint = bbox.vec[0];
+ const float *farpoint = bbox.vec[6];
+
+ /* just use median point */
+ mid_v3_v3v3(bsphere.center, farpoint, nearpoint);
+ bsphere.radius = len_v3v3(bsphere.center, farpoint);
+ }
+ else if (data_.winmat[2][0] == 0.0f && data_.winmat[2][1] == 0.0f) {
+ /* Perspective with symmetrical frustum. */
+
+ /* We obtain the center and radius of the circumscribed circle of the
+ * isosceles trapezoid composed by the diagonals of the near and far clipping plane */
+
+ /* center of each clipping plane */
+ float mid_min[3], mid_max[3];
+ mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]);
+ mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]);
+
+ /* square length of the diagonals of each clipping plane */
+ float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]);
+ float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]);
+
+ /* distance squared between clipping planes */
+ float h_sq = len_squared_v3v3(mid_min, mid_max);
+
+ float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq);
+
+ /* The goal is to get the smallest sphere,
+ * not the sphere that passes through each corner */
+ CLAMP(fac, 0.0f, 1.0f);
+
+ interp_v3_v3v3(bsphere.center, mid_min, mid_max, fac);
+
+ /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
+ bsphere.radius = len_v3v3(bsphere.center, bbox.vec[1]);
+ }
+ else {
+ /* Perspective with asymmetrical frustum. */
+
+ /* We put the sphere center on the line that goes from origin
+ * to the center of the far clipping plane. */
+
+ /* Detect which of the corner of the far clipping plane is the farthest to the origin */
+ float nfar[4]; /* most extreme far point in NDC space */
+ float farxy[2]; /* far-point projection onto the near plane */
+ float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */
+ float nearpoint[3]; /* most extreme near point in camera coordinate */
+ float farcenter[3] = {0.0f}; /* center of far clipping plane in camera coordinate */
+ float F = -1.0f, N; /* square distance of far and near point to origin */
+ float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */
+ float e, s; /* far and near clipping distance (<0) */
+ float c; /* slope of center line = distance of far clipping center
+ * to z axis / far clipping distance. */
+ float z; /* projection of sphere center on z axis (<0) */
+
+ /* Find farthest corner and center of far clip plane. */
+ float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */
+ for (int i = 0; i < 4; i++) {
+ float point[3];
+ mul_v3_project_m4_v3(point, data_.wininv.ptr(), corner);
+ float len = len_squared_v3(point);
+ if (len > F) {
+ copy_v3_v3(nfar, corner);
+ copy_v3_v3(farpoint, point);
+ F = len;
+ }
+ add_v3_v3(farcenter, point);
+ /* rotate by 90 degree to walk through the 4 points of the far clip plane */
+ float tmp = corner[0];
+ corner[0] = -corner[1];
+ corner[1] = tmp;
+ }
+
+ /* the far center is the average of the far clipping points */
+ mul_v3_fl(farcenter, 0.25f);
+ /* the extreme near point is the opposite point on the near clipping plane */
+ copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f);
+ mul_v3_project_m4_v3(nearpoint, data_.wininv.ptr(), nfar);
+ /* this is a frustum projection */
+ N = len_squared_v3(nearpoint);
+ e = farpoint[2];
+ s = nearpoint[2];
+ /* distance to view Z axis */
+ f = len_v2(farpoint);
+ /* get corresponding point on the near plane */
+ mul_v2_v2fl(farxy, farpoint, s / e);
+ /* this formula preserve the sign of n */
+ sub_v2_v2(nearpoint, farxy);
+ n = f * s / e - len_v2(nearpoint);
+ c = len_v2(farcenter) / e;
+ /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */
+ z = (F - N) / (2.0f * (e - s + c * (f - n)));
+
+ bsphere.center[0] = farcenter[0] * z / e;
+ bsphere.center[1] = farcenter[1] * z / e;
+ bsphere.center[2] = z;
+
+ /* For XR, the view matrix may contain a scale factor. Then, transforming only the center
+ * into world space after calculating the radius will result in incorrect behavior. */
+ mul_m4_v3(data_.viewinv.ptr(), bsphere.center); /* Transform to world space. */
+ mul_m4_v3(data_.viewinv.ptr(), farpoint);
+ bsphere.radius = len_v3v3(bsphere.center, farpoint);
+ }
+}
+
+void View::set_clip_planes(Span<float4> planes)
+{
+ BLI_assert(planes.size() <= ARRAY_SIZE(data_.clip_planes));
+ int i = 0;
+ for (const auto &plane : planes) {
+ data_.clip_planes[i++] = plane;
+ }
+}
+
+void View::update_viewport_size()
+{
+ float4 viewport;
+ GPU_viewport_size_get_f(viewport);
+ float2 viewport_size = float2(viewport.z, viewport.w);
+ if (assign_if_different(data_.viewport_size, viewport_size)) {
+ dirty_ = true;
+ }
+}
+
+void View::update_view_vectors()
+{
+ bool is_persp = data_.winmat[3][3] == 0.0f;
+
+ /* Near clip distance. */
+ data_.viewvecs[0][3] = (is_persp) ? -data_.winmat[3][2] / (data_.winmat[2][2] - 1.0f) :
+ -(data_.winmat[3][2] + 1.0f) / data_.winmat[2][2];
+
+ /* Far clip distance. */
+ data_.viewvecs[1][3] = (is_persp) ? -data_.winmat[3][2] / (data_.winmat[2][2] + 1.0f) :
+ -(data_.winmat[3][2] - 1.0f) / data_.winmat[2][2];
+
+ /* View vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ float3 view_vecs[4] = {
+ {-1.0f, -1.0f, -1.0f},
+ {1.0f, -1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, -1.0f, 1.0f},
+ };
+
+ /* Convert the view vectors to view space */
+ for (int i = 0; i < 4; i++) {
+ mul_project_m4_v3(data_.wininv.ptr(), view_vecs[i]);
+ /* Normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ if (is_persp) {
+ view_vecs[i].x /= view_vecs[i].z;
+ view_vecs[i].y /= view_vecs[i].z;
+ }
+ }
+
+ /**
+ * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
+ * view_vecs[1] is the vector going from the near-bottom-left corner to
+ * the far-top-right corner.
+ * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
+ * when Z = 1, and top-left corner if Z = 1.
+ * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
+ * distance from the near plane to the far clip plane.
+ */
+ copy_v3_v3(data_.viewvecs[0], view_vecs[0]);
+
+ /* we need to store the differences */
+ data_.viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
+ data_.viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
+ data_.viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
+}
+
+void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len)
+{
+ object_visibility_buf.resize(divide_ceil_u(resource_len, sizeof(uint4)));
+
+ if (do_visibility_ == false) {
+ uint32_t data = 0xFFFFFFFFu;
+ GPU_storagebuf_clear(object_visibility_buf, GPU_R32UI, GPU_DATA_UINT, &data);
+ return;
+ }
+
+ GPUShader *shader = DRW_shader_draw_visibility_compute_get();
+ GPU_shader_bind(shader);
+ GPU_shader_uniform_1i(shader, "resource_len", resource_len);
+ GPU_storagebuf_bind(bounds, 0);
+ GPU_compute_dispatch(shader, divide_ceil_u(resource_len, DRW_VISIBILITY_GROUP_SIZE), 1, 1);
+}
+
} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh
index 678c81afdb7..e5d7a834dbf 100644
--- a/source/blender/draw/intern/draw_view.hh
+++ b/source/blender/draw/intern/draw_view.hh
@@ -13,40 +13,42 @@
namespace blender::draw {
+class Manager;
+
+/* TODO deduplicate. */
+using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
+
class View {
- public:
- UniformBuffer<ViewInfos> data_;
+ friend Manager;
private:
+ UniformBuffer<ViewInfos> data_;
/** Result of the visibility computation. 1 bit per resource ID. */
StorageArrayBuffer<uint4, 1, true> object_visibility_buf;
const char *debug_name;
- View *parent = nullptr;
- bool do_visibility = true;
+ bool do_visibility_ = true;
+ bool dirty_ = true;
public:
- View(const char *name) : debug_name(name), object_visibility_buf(name){};
+ View(const char *name) : object_visibility_buf(name), debug_name(name){};
+
+ void set_clip_planes(Span<float4> planes);
- void sync();
+ void sync(const float4x4 &view_mat, const float4x4 &win_mat);
private:
- void compute_visibility(Manager::ObjectBoundsBuf &bounds, uint resource_len)
- {
- object_visibility_buf.resize(divide_ceil_u(resource_len, 128));
-
- if (do_visibility == false) {
- object_visibility_buf.clear(0xFFFFFFFFu);
- return;
- }
-
- uint thread_groups = divide_ceil_u(resource_len, DRW_VISIBILITY_GROUP_SIZE);
- GPUShader *shader = draw_shader_visibility_get();
- GPU_shader_bind(shader);
- GPU_storagebuf_bind(bounds, 0);
- GPU_compute_dispatch(shader, thread_groups, 1, 1);
- }
+ /** Called from draw manager. */
+ void bind();
+ void compute_visibility(ObjectBoundsBuf &bounds, uint resource_len);
+
+ void update_view_vectors();
+ void update_viewport_size();
+
+ void frustum_boundbox_calc(BoundBox &bbox);
+ void frustum_culling_planes_calc();
+ void frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere);
};
} // namespace blender::draw
diff --git a/source/blender/draw/intern/shaders/common_intersect_lib.glsl b/source/blender/draw/intern/shaders/common_intersect_lib.glsl
index 708d361029a..8fa3bd3d373 100644
--- a/source/blender/draw/intern/shaders/common_intersect_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_intersect_lib.glsl
@@ -70,6 +70,30 @@ IsectBox isect_data_setup(Box shape)
return data;
}
+/* Construct box from 1 corner point + 3 side vectors. */
+IsectBox isect_data_setup(vec3 origin, vec3 side_x, vec3 side_y, vec3 side_z)
+{
+ IsectBox data;
+ data.corners[0] = origin;
+ data.corners[1] = origin + side_x;
+ data.corners[2] = origin + side_y + side_x;
+ data.corners[3] = origin + side_y;
+ data.corners[4] = data.corners[0] + side_z;
+ data.corners[5] = data.corners[1] + side_z;
+ data.corners[6] = data.corners[2] + side_z;
+ data.corners[7] = data.corners[3] + side_z;
+
+ data.planes[0] = isect_plane_setup(data.corners[0], side_y, side_z);
+ data.planes[1] = isect_plane_setup(data.corners[0], side_x, side_y);
+ data.planes[2] = isect_plane_setup(data.corners[0], side_z, side_x);
+ /* Assumes that the box is actually a box! */
+ data.planes[3] = vec4(-data.planes[0].xyz, -dot(-data.planes[0].xyz, data.corners[6]));
+ data.planes[4] = vec4(-data.planes[1].xyz, -dot(-data.planes[1].xyz, data.corners[6]));
+ data.planes[5] = vec4(-data.planes[2].xyz, -dot(-data.planes[2].xyz, data.corners[6]));
+
+ return data;
+}
+
struct IsectFrustum {
vec3 corners[8];
vec4 planes[6];
@@ -194,6 +218,50 @@ bool intersect_view(Box box)
return intersects;
}
+bool intersect_view(IsectBox i_box)
+{
+ bool intersects = true;
+
+ /* Do Box vertices vs Frustum planes. */
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(drw_view.frustum_planes[p], vec4(i_box.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_box.planes[p], vec4(drw_view.frustum_corners[v].xyz, 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ return intersects;
+}
+
bool intersect_view(Sphere sphere)
{
bool intersects = true;
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index 8fd55ea351f..de96e86b67a 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -1,10 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "draw_defines.h"
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(draw_object_infos)
.typedef_source("draw_shader_shared.h")
.define("OBINFO_LIB")
+ .define("OrcoTexCoFactors", "(drw_infos[resource_id].orco_mul_bias)")
+ .define("ObjectInfo", "(drw_infos[resource_id].infos)")
+ .define("ObjectColor", "(drw_infos[resource_id].color)")
.uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH);
GPU_SHADER_CREATE_INFO(draw_volume_infos)
@@ -14,3 +18,10 @@ GPU_SHADER_CREATE_INFO(draw_volume_infos)
GPU_SHADER_CREATE_INFO(draw_curves_infos)
.typedef_source("draw_shader_shared.h")
.uniform_buf(2, "CurvesInfos", "drw_curves", Frequency::BATCH);
+
+GPU_SHADER_CREATE_INFO(draw_object_infos_new)
+ .typedef_source("draw_shader_shared.h")
+ .storage_buf(DRW_OBJ_INFOS_SLOT, Qualifier::READ, "ObjectMatrices", "drw_matrix_buf[]")
+ .define("drw_ModelMatrixInverse", "drw_matrix_buf[drw_ResourceIndex].model")
+ .define("drw_ModelMatrix", "drw_matrix_buf[drw_ResourceIndex].model_inverse")
+ .additional_info("draw_resource_id_new"); \ No newline at end of file
diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh
index 72154b1a1ae..6149812a644 100644
--- a/source/blender/draw/intern/shaders/draw_view_info.hh
+++ b/source/blender/draw/intern/shaders/draw_view_info.hh
@@ -45,7 +45,7 @@ GPU_SHADER_CREATE_INFO(draw_resource_handle)
* \{ */
GPU_SHADER_CREATE_INFO(draw_view)
- .uniform_buf(0, "ViewInfos", "drw_view", Frequency::PASS)
+ .uniform_buf(DRW_VIEW_UBO_SLOT, "ViewInfos", "drw_view", Frequency::PASS)
.typedef_source("draw_shader_shared.h");
GPU_SHADER_CREATE_INFO(draw_modelmat)
@@ -154,10 +154,49 @@ GPU_SHADER_CREATE_INFO(draw_resource_finalize)
.compute_source("draw_resource_finalize_comp.glsl");
GPU_SHADER_CREATE_INFO(draw_visibility_compute)
- .local_group_size(128) /* Number of bits in a uvec4. */
+ .do_static_compilation(true)
+ .local_group_size(DRW_VISIBILITY_GROUP_SIZE)
.storage_buf(0, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
- .storage_buf(1, Qualifier::WRITE, "uint4", "visibility_buf[]")
+ .storage_buf(1, Qualifier::WRITE, "uint", "visibility_buf[]")
.push_constant(Type::UINT, "resource_len")
- .compute_source("draw_visibility_comp.glsl");
+ .compute_source("draw_visibility_comp.glsl")
+ .additional_info("draw_view");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Resource ID
+ * New implementation using gl_DrawID and storage buffers.
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_resource_id_draw_id).define("drw_DrawIndex", "gl_DrawID");
+
+/**
+ * Workaround the lack of gl_DrawID using our own emulation.
+ */
+GPU_SHADER_CREATE_INFO(draw_resource_id_fallback).vertex_in(15, Type::UINT, "drw_DrawIndex");
+
+GPU_SHADER_CREATE_INFO(draw_resource_id_new)
+ .typedef_source("draw_shader_shared.h")
+ .storage_buf(DRW_COMMAND_SLOT, Qualifier::READ, "DrawCommand", "drw_command_buf[]")
+ .define("drw_EngineInstanceCount", "drw_command_buf[drw_DrawIndex].engine_instance_count")
+ .define("drw_EngineInstanceIndex", "(gl_InstanceID % drw_EngineInstanceCount)")
+ .define("drw_ObjectInstanceIndex", "(gl_InstanceID / drw_EngineInstanceCount)")
+ .define("drw_ResourceIndexStart", "drw_command_buf[drw_DrawIndex].resource_id")
+ .define("drw_ResourceIndex", "(drw_ResourceIndexStart + drw_ObjectInstanceIndex)")
+ .additional_info("draw_resource_id_draw_id");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Object Resources
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_modelmat_new)
+ .typedef_source("draw_shader_shared.h")
+ .storage_buf(DRW_OBJ_MAT_SLOT, Qualifier::READ, "ObjectMatrices", "drw_matrix_buf[]")
+ .define("drw_ModelMatrixInverse", "drw_matrix_buf[drw_ResourceIndex].drw_modelMatrix")
+ .define("drw_ModelMatrix", "drw_matrix_buf[drw_ResourceIndex].drw_modelMatrixInverse")
+ .additional_info("draw_resource_id_new");
/** \} */
diff --git a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
index 885e77af7ed..7d38338fc6e 100644
--- a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
+++ b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
@@ -5,26 +5,40 @@
/* 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[4];
+const uint uint_len_per_group = gl_WorkGroupSize.x / 32u;
+shared uint shared_result[uint_len_per_group];
void main()
{
if (gl_LocalInvocationID.x == 0) {
- shared_result[0] = 0u;
- shared_result[1] = 0u;
- shared_result[2] = 0u;
- shared_result[3] = 0u;
+ for (uint i = 0; i < uint_len_per_group; i++) {
+ shared_result[i] = 0u;
+ }
}
barrier();
- uint resource_id = gl_GlobalInvocationID.x;
+ uint resource_id = min(gl_GlobalInvocationID.x, resource_len - 1u);
+
+ ObjectBounds bounds = bounds_buf[resource_id];
+ 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);
+ if (intersect_view(box)) {
+ uint result = 1u << (gl_LocalInvocationID.x % 32u);
+ atomicOr(shared_result[gl_LocalInvocationID.x / 32u], result);
+ }
+ }
barrier();
if (gl_LocalInvocationID.x == 0) {
- visibility_buf[gl_WorkGroupID.x] = uvec4(
- shared_result[0], shared_result[1], shared_result[2], shared_result[3]);
+ for (uint i = 0; i < uint_len_per_group; i++) {
+ visibility_buf[gl_WorkGroupID.x * uint_len_per_group + i] = shared_result[i];
+ }
}
} \ No newline at end of file