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:
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c5
-rw-r--r--source/blender/draw/intern/DRW_render.h54
-rw-r--r--source/blender/draw/intern/draw_manager.c87
-rw-r--r--source/blender/draw/intern/draw_manager.h84
-rw-r--r--source/blender/draw/intern/draw_manager_data.c535
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c484
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c3
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl5
-rw-r--r--source/blender/gpu/GPU_viewport.h2
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c6
10 files changed, 775 insertions, 490 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 44e9b98e8e2..6e0bd7f31d3 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -1130,11 +1130,10 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \
do { \
if (oedata) { \
- DRW_shgroup_call_object_with_callback( \
- shgrp, geom, ob, EEVEE_lightprobes_obj_visibility_cb, oedata); \
+ DRW_shgroup_call_object_with_callback(shgrp, geom, ob, oedata); \
} \
else { \
- DRW_shgroup_call_object_ex(shgrp, geom, ob, false); \
+ DRW_shgroup_call_object(shgrp, geom, ob); \
} \
} while (0)
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 6d290f9a2d3..391d041e408 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -81,6 +81,7 @@ struct rcti;
typedef struct DRWInterface DRWInterface;
typedef struct DRWPass DRWPass;
+typedef struct DRWView DRWView;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
@@ -411,10 +412,10 @@ void DRW_shgroup_call_object_ex(DRWShadingGroup *shgroup,
DRW_shgroup_call_object_ex(shgroup, geom, ob, true)
/* TODO(fclem) remove this when we have DRWView */
+/* user_data is used by DRWCallVisibilityFn defined in DRWView. */
void DRW_shgroup_call_object_with_callback(DRWShadingGroup *shgroup,
struct GPUBatch *geom,
struct Object *ob,
- DRWCallVisibilityFn *callback,
void *user_data);
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
@@ -520,6 +521,7 @@ bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
+/* TODO Replace with passes inheritance. */
void DRW_pass_state_set(DRWPass *pass, DRWState state);
void DRW_pass_state_add(DRWPass *pass, DRWState state);
void DRW_pass_state_remove(DRWPass *pass, DRWState state);
@@ -532,6 +534,50 @@ bool DRW_pass_is_empty(DRWPass *pass);
#define DRW_PASS_CREATE(pass, state) (pass = DRW_pass_create(#pass, state))
+/* Views */
+DRWView *DRW_view_create(const float viewmat[4][4],
+ const float winmat[4][4],
+ const float (*culling_viewmat)[4],
+ const float (*culling_winmat)[4],
+ DRWCallVisibilityFn *visibility_fn);
+DRWView *DRW_view_create_sub(const DRWView *parent_view,
+ const float viewmat[4][4],
+ const float winmat[4][4]);
+
+void DRW_view_update(DRWView *view,
+ const float viewmat[4][4],
+ const float winmat[4][4],
+ const float (*culling_viewmat)[4],
+ const float (*culling_winmat)[4]);
+void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]);
+
+const DRWView *DRW_view_default_get(void);
+void DRW_view_default_set(DRWView *view);
+
+void DRW_view_set_active(DRWView *view);
+
+void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
+
+/* For all getters, if view is NULL, default view is assumed. */
+void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse);
+void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse);
+void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse);
+
+void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners);
+void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]);
+
+/* These are in view-space, so negative if in perspective.
+ * Extract near and far clip distance from the projection matrix. */
+float DRW_view_near_distance_get(const DRWView *view);
+float DRW_view_far_distance_get(const DRWView *view);
+bool DRW_view_is_persp_get(const DRWView *view);
+
+/* Culling, return true if object is inside view frustum. */
+/* TODO */
+// bool DRW_culling_sphere_test(DRWView *view, BoundSphere *bsphere);
+// bool DRW_culling_box_test(DRWView *view, BoundBox *bbox);
+// bool DRW_culling_plane_test(DRWView *view, float plane[4]);
+
/* Viewport */
typedef enum {
/* keep in sync with the union struct DRWMatrixState. */
@@ -645,9 +691,9 @@ void DRW_state_clip_planes_reset(void);
void DRW_state_clip_planes_set_from_rv3d(struct RegionView3D *rv3d);
/* Culling, return true if object is inside view frustum. */
-bool DRW_culling_sphere_test(BoundSphere *bsphere);
-bool DRW_culling_box_test(BoundBox *bbox);
-bool DRW_culling_plane_test(float plane[4]);
+bool DRW_culling_sphere_test(const BoundSphere *bsphere);
+bool DRW_culling_box_test(const BoundBox *bbox);
+bool DRW_culling_plane_test(const float plane[4]);
void DRW_culling_frustum_corners_get(BoundBox *corners);
void DRW_culling_frustum_planes_get(float planes[6][4]);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 8ded73aa678..90e1ff708d9 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -538,9 +538,11 @@ static void drw_viewport_cache_resize(void)
BLI_memblock_clear(DST.vmempool->calls, NULL);
BLI_memblock_clear(DST.vmempool->states, NULL);
+ BLI_memblock_clear(DST.vmempool->cullstates, NULL);
BLI_memblock_clear(DST.vmempool->shgroups, NULL);
BLI_memblock_clear(DST.vmempool->uniforms, NULL);
BLI_memblock_clear(DST.vmempool->passes, NULL);
+ BLI_memblock_clear(DST.vmempool->views, NULL);
BLI_memblock_clear(DST.vmempool->images, NULL);
}
@@ -611,12 +613,18 @@ static void drw_viewport_var_init(void)
if (DST.vmempool->states == NULL) {
DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState), false);
}
+ if (DST.vmempool->cullstates == NULL) {
+ DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState), false);
+ }
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup), false);
}
if (DST.vmempool->uniforms == NULL) {
DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform), false);
}
+ if (DST.vmempool->views == NULL) {
+ DST.vmempool->views = BLI_memblock_create(sizeof(DRWView), false);
+ }
if (DST.vmempool->passes == NULL) {
DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass), false);
}
@@ -638,31 +646,38 @@ static void drw_viewport_var_init(void)
DST.vmempool = NULL;
}
+ DST.primary_view_ct = 0;
+
if (rv3d != NULL) {
- /* Refresh DST.screenvecs */
- copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]);
- copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]);
- normalize_v3(DST.screenvecs[0]);
- normalize_v3(DST.screenvecs[1]);
+ normalize_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]);
+ normalize_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]);
- /* Refresh DST.pixelsize */
DST.pixsize = rv3d->pixsize;
+ DST.view_default = DRW_view_create(rv3d->viewmat, rv3d->winmat, NULL, NULL, NULL);
+ copy_v4_v4(DST.view_default->storage.viewcamtexcofac, rv3d->viewcamtexcofac);
- copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERS], rv3d->persmat);
- copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERSINV], rv3d->persinv);
- copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEW], rv3d->viewmat);
- copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEWINV], rv3d->viewinv);
- copy_m4_m4(DST.original_mat.mat[DRW_MAT_WIN], rv3d->winmat);
- invert_m4_m4(DST.original_mat.mat[DRW_MAT_WININV], rv3d->winmat);
-
- memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DST.original_mat.mat));
+ if (DST.draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) {
+ int plane_len = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
+ DRW_view_clip_planes_set(DST.view_default, rv3d->clip, plane_len);
+ }
- copy_v4_v4(DST.view_data.viewcamtexcofac, rv3d->viewcamtexcofac);
+ /* TODO should be set to NULL. */
+ DST.view_active = DRW_view_create(rv3d->viewmat, rv3d->winmat, NULL, NULL, NULL);
}
else {
- copy_v4_fl4(DST.view_data.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f);
+ zero_v3(DST.screenvecs[0]);
+ zero_v3(DST.screenvecs[1]);
+
+ DST.pixsize = 1.0f;
+ DST.view_default = NULL;
+
+ /* TODO should be set to NULL. */
+ float mat[4][4];
+ unit_m4(mat);
+ DST.view_active = DRW_view_create(mat, mat, NULL, NULL, NULL);
}
+ /* fclem: Is this still needed ? */
if (DST.draw_ctx.object_edit) {
ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d);
}
@@ -674,61 +689,49 @@ static void drw_viewport_var_init(void)
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(ViewUboStorage), NULL);
}
- DST.override_mat = 0;
- DST.dirty_mat = true;
- DST.state_cache_id = 1;
-
- DST.clipping.updated = false;
-
memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
}
+/* TODO remove all of the DRW_viewport_matrix_* functions. */
+
void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
{
BLI_assert(type >= 0 && type < DRW_MAT_COUNT);
/* Can't use this in render mode. */
- BLI_assert(((DST.override_mat & (1 << type)) != 0) || DST.draw_ctx.rv3d != NULL);
+ // BLI_assert(((DST.override_mat & (1 << type)) != 0) || DST.draw_ctx.rv3d != NULL);
- copy_m4_m4(mat, DST.view_data.matstate.mat[type]);
+ copy_m4_m4(mat, DST.view_active->storage.matstate.mat[type]);
}
void DRW_viewport_matrix_get_all(DRWMatrixState *state)
{
- memcpy(state, DST.view_data.matstate.mat, sizeof(DRWMatrixState));
+ memcpy(state, DST.view_active->storage.matstate.mat, sizeof(DRWMatrixState));
}
void DRW_viewport_matrix_override_set(const float mat[4][4], DRWViewportMatrixType type)
{
BLI_assert(type < DRW_MAT_COUNT);
- copy_m4_m4(DST.view_data.matstate.mat[type], mat);
- DST.override_mat |= (1 << type);
- DST.dirty_mat = true;
- DST.clipping.updated = false;
+ copy_m4_m4(DST.view_active->storage.matstate.mat[type], mat);
+ DST.view_active->is_dirty = true;
}
void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type)
{
BLI_assert(type < DRW_MAT_COUNT);
- copy_m4_m4(DST.view_data.matstate.mat[type], DST.original_mat.mat[type]);
- DST.override_mat &= ~(1 << type);
- DST.dirty_mat = true;
- DST.clipping.updated = false;
+ copy_m4_m4(DST.view_active->storage.matstate.mat[type],
+ DST.view_default->storage.matstate.mat[type]);
+ DST.view_active->is_dirty = true;
}
void DRW_viewport_matrix_override_set_all(DRWMatrixState *state)
{
- memcpy(DST.view_data.matstate.mat, state, sizeof(DRWMatrixState));
- DST.override_mat = 0xFFFFFF;
- DST.dirty_mat = true;
- DST.clipping.updated = false;
+ memcpy(DST.view_active->storage.matstate.mat, state, sizeof(DRWMatrixState));
+ DST.view_active->is_dirty = true;
}
void DRW_viewport_matrix_override_unset_all(void)
{
- memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DRWMatrixState));
- DST.override_mat = 0;
- DST.dirty_mat = true;
- DST.clipping.updated = false;
+ DRW_viewport_matrix_override_set_all(&DST.view_default->storage.matstate);
}
bool DRW_viewport_is_persp_get(void)
@@ -738,7 +741,7 @@ bool DRW_viewport_is_persp_get(void)
return rv3d->is_persp;
}
else {
- return DST.view_data.matstate.mat[DRW_MAT_WIN][3][3] == 0.0f;
+ return DST.view_active->storage.matstate.winmat[3][3] == 0.0f;
}
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 96dcfb9d07d..0ccffceb37a 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -43,6 +43,7 @@
/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
#define USE_GPU_SELECT
+#define DRW_DEBUG_CULLING
#define DRW_DEBUG_USE_UNIFORM_NAME 0
#define DRW_UNIFORM_BUFFER_NAME 64
@@ -91,9 +92,7 @@
/* Used by DRWCallState.flag */
enum {
- DRW_CALL_CULLED = (1 << 0),
DRW_CALL_NEGSCALE = (1 << 1),
- DRW_CALL_BYPASS_CULLING = (1 << 2),
};
/* Used by DRWCallState.matflag */
@@ -104,22 +103,24 @@ enum {
DRW_CALL_OBJECTINFO = (1 << 3),
};
-typedef struct DRWCallState {
- DRWCallVisibilityFn *visibility_cb;
+typedef struct DRWCullingState {
+ uint32_t mask;
+ /* Culling: Using Bounding Sphere for now for faster culling.
+ * Not ideal for planes. Could be extended. */
+ BoundSphere bsphere;
+ /* Grrr only used by EEVEE. */
void *user_data;
+} DRWCullingState;
+typedef struct DRWCallState {
+ DRWCullingState *culling;
uchar flag;
- uchar cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */
- uchar matflag; /* Which matrices to compute. */
+ uchar matflag; /* Which matrices to compute. */
short ob_index;
- /* Culling: Using Bounding Sphere for now for faster culling.
- * Not ideal for planes. */
- BoundSphere bsphere;
/* Matrices */
float model[4][4];
float modelinverse[4][4];
- float modelviewprojection[4][4];
- float orcotexfac[2][3]; /* Not view dependent */
+ float orcotexfac[2][3];
float ob_random;
} DRWCallState;
@@ -213,24 +214,43 @@ struct DRWPass {
char name[MAX_PASS_NAME];
};
+/* keep in sync with viewBlock */
+typedef struct ViewUboStorage {
+ DRWMatrixState matstate;
+ float clipplanes[6][4];
+ /* Should not be here. Not view dependant (only main view). */
+ float viewcamtexcofac[4];
+} ViewUboStorage;
+
+#define MAX_CULLED_VIEWS 32
+
+struct DRWView {
+ /** Parent view if this is a sub view. NULL otherwise. */
+ struct DRWView *parent;
+
+ ViewUboStorage storage;
+ /** Number of active clipplanes. */
+ int clip_planes_len;
+ /** Does culling result needs to be updated. */
+ bool is_dirty;
+ /** Culling */
+ uint32_t culling_mask;
+ BoundBox frustum_corners;
+ BoundSphere frustum_bsphere;
+ float frustum_planes[6][4];
+ /** Custom visibility function. */
+ DRWCallVisibilityFn *visibility_fn;
+ void *user_data;
+};
+
/* TODO(fclem): Future awaits */
#if 0
-typedef struct DRWView {
- /* Culling function, culling result etc...*/
-} DRWView;
-
typedef struct ModelUboStorage {
float model[4][4];
float modelinverse[4][4];
} ModelUboStorage;
#endif
-typedef struct ViewUboStorage {
- DRWMatrixState matstate;
- float viewcamtexcofac[4];
- float clipplanes[2][4];
-} ViewUboStorage;
-
/* ------------- DRAW DEBUG ------------ */
typedef struct DRWDebugLine {
@@ -258,7 +278,6 @@ typedef struct DRWManager {
DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
/* State of the object being evaluated if already allocated. */
DRWCallState *ob_state;
- uchar state_cache_id; /* Could be larger but 254 view changes is already a lot! */
struct DupliObject *dupli_source;
struct Object *dupli_parent;
struct Object *dupli_origin;
@@ -302,21 +321,12 @@ typedef struct DRWManager {
bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */
- /* View dependent uniforms. */
- DRWMatrixState original_mat; /* Original rv3d matrices. */
- int override_mat; /* Bitflag of which matrices are overridden. */
- int clip_planes_len; /* Number of active clipplanes. */
- bool dirty_mat;
-
- /* keep in sync with viewBlock */
- ViewUboStorage view_data;
-
- struct {
- float frustum_planes[6][4];
- BoundBox frustum_corners;
- BoundSphere frustum_bsphere;
- bool updated;
- } clipping;
+ DRWView *view_default;
+ DRWView *view_active;
+ uint primary_view_ct;
+ /** TODO(fclem) Remove this. Only here to support
+ * shaders without common_view_lib.glsl */
+ ViewUboStorage view_storage_cpy;
#ifdef USE_GPU_SELECT
uint select_id;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 837b68ccb56..12f60b5386c 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -39,6 +39,10 @@
#include "BLI_mempool.h"
#include "BLI_memblock.h"
+#ifdef DRW_DEBUG_CULLING
+# include "BLI_math_bits.h"
+#endif
+
#include "GPU_buffers.h"
#include "intern/gpu_codegen.h"
@@ -389,8 +393,6 @@ static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obm
{
DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
state->flag = 0;
- state->cache_id = 0;
- state->visibility_cb = NULL;
state->matflag = 0;
/* Matrices */
@@ -407,18 +409,23 @@ static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obm
drw_call_state_update_matflag(state, shgroup, ob);
+ DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates);
+ state->culling = cull;
+
if (ob != NULL) {
float corner[3];
BoundBox *bbox = BKE_object_boundbox_get(ob);
/* Get BoundSphere center and radius from the BoundBox. */
- mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]);
+ mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]);
mul_v3_m4v3(corner, obmat, bbox->vec[0]);
- mul_m4_v3(obmat, state->bsphere.center);
- state->bsphere.radius = len_v3v3(state->bsphere.center, corner);
+ mul_m4_v3(obmat, cull->bsphere.center);
+ cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner);
}
else {
+ /* TODO(fclem) Bypass alloc if we can (see if eevee's
+ * probe visibility collection still works). */
/* Bypass test. */
- state->bsphere.radius = -1.0f;
+ cull->bsphere.radius = -1.0f;
}
return state;
@@ -531,8 +538,6 @@ void DRW_shgroup_call_object_ex(DRWShadingGroup *shgroup,
BLI_LINKS_APPEND(&shgroup->calls, call);
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
- /* NOTE this will disable culling for the whole object. */
- call->state->flag |= (bypass_culling) ? DRW_CALL_BYPASS_CULLING : 0;
call->batch = geom;
call->vert_first = 0;
call->vert_count = 0; /* Auto from batch. */
@@ -541,12 +546,15 @@ void DRW_shgroup_call_object_ex(DRWShadingGroup *shgroup,
call->select_id = DST.select_id;
call->inst_selectid = NULL;
#endif
+ if (bypass_culling) {
+ /* NOTE this will disable culling for the whole object. */
+ call->state->culling->bsphere.radius = -1.0f;
+ }
}
void DRW_shgroup_call_object_with_callback(DRWShadingGroup *shgroup,
GPUBatch *geom,
Object *ob,
- DRWCallVisibilityFn *callback,
void *user_data)
{
BLI_assert(geom != NULL);
@@ -555,8 +563,7 @@ void DRW_shgroup_call_object_with_callback(DRWShadingGroup *shgroup,
BLI_LINKS_APPEND(&shgroup->calls, call);
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
- call->state->visibility_cb = callback;
- call->state->user_data = user_data;
+ call->state->culling->user_data = user_data;
call->batch = geom;
call->vert_first = 0;
call->vert_count = 0; /* Auto from batch. */
@@ -859,23 +866,16 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
}
else {
/* Only here to support builtin shaders. This should not be used by engines. */
+ /* TODO remove. */
+ DRWMatrixState *matstate = &DST.view_storage_cpy.matstate;
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, matstate->viewmat, 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, matstate->viewinv, 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, matstate->persmat, 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, matstate->persinv, 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, matstate->winmat, 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, matstate->wininv, 16, 1);
drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1);
- drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1);
- drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1);
- drw_shgroup_builtin_uniform(shgroup,
- GPU_UNIFORM_VIEWPROJECTION_INV,
- DST.view_data.matstate.mat[DRW_MAT_PERSINV],
- 16,
- 1);
- drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1);
- drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1);
- drw_shgroup_builtin_uniform(
- shgroup, GPU_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2);
+ shgroup, GPU_UNIFORM_CAMERATEXCO, DST.view_storage_cpy.viewcamtexcofac, 4, 1);
}
/* Not supported. */
@@ -1066,6 +1066,480 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name View (DRW_view)
+ * \{ */
+
+/* Extract the 8 corners from a Projection Matrix.
+ * Although less accurate, this solution can be simplified as follows:
+ * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const
+ * float[3]){1.0f, 1.0f, 1.0f}); for (int i = 0; i < 8; i++) {mul_project_m4_v3(projinv,
+ * bbox.vec[i]);}
+ */
+static void draw_frustum_boundbox_calc(const float (*viewinv)[4],
+ const float (*projmat)[4],
+ BoundBox *r_bbox)
+{
+ float left, right, bottom, top, near, far;
+ bool is_persp = projmat[3][3] == 0.0f;
+
+#if 0 /* Equivalent to this but it has accuracy problems. */
+ BKE_boundbox_init_from_minmax(
+ &bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f});
+ for (int i = 0; i < 8; i++) {
+ mul_project_m4_v3(projinv, bbox.vec[i]);
+ }
+#endif
+
+ projmat_dimensions(projmat, &left, &right, &bottom, &top, &near, &far);
+
+ if (is_persp) {
+ left *= near;
+ right *= near;
+ bottom *= near;
+ top *= near;
+ }
+
+ r_bbox->vec[0][2] = r_bbox->vec[3][2] = r_bbox->vec[7][2] = r_bbox->vec[4][2] = -near;
+ r_bbox->vec[0][0] = r_bbox->vec[3][0] = left;
+ r_bbox->vec[4][0] = r_bbox->vec[7][0] = right;
+ r_bbox->vec[0][1] = r_bbox->vec[4][1] = bottom;
+ r_bbox->vec[7][1] = r_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;
+ }
+
+ r_bbox->vec[1][2] = r_bbox->vec[2][2] = r_bbox->vec[6][2] = r_bbox->vec[5][2] = -far;
+ r_bbox->vec[1][0] = r_bbox->vec[2][0] = left;
+ r_bbox->vec[6][0] = r_bbox->vec[5][0] = right;
+ r_bbox->vec[1][1] = r_bbox->vec[5][1] = bottom;
+ r_bbox->vec[2][1] = r_bbox->vec[6][1] = top;
+
+ /* Transform into world space. */
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(viewinv, r_bbox->vec[i]);
+ }
+}
+
+static void draw_frustum_culling_planes_calc(const BoundBox *bbox, float (*frustum_planes)[4])
+{
+ /* TODO See if planes_from_projmat cannot do the job. */
+
+ /* Compute clip planes using the world space frustum corners. */
+ for (int p = 0; p < 6; p++) {
+ int q, r, s;
+ switch (p) {
+ case 0:
+ q = 1;
+ r = 2;
+ s = 3;
+ break; /* -X */
+ case 1:
+ q = 0;
+ r = 4;
+ s = 5;
+ break; /* -Y */
+ case 2:
+ q = 1;
+ r = 5;
+ s = 6;
+ break; /* +Z (far) */
+ case 3:
+ q = 2;
+ r = 6;
+ s = 7;
+ break; /* +Y */
+ case 4:
+ q = 0;
+ r = 3;
+ s = 7;
+ break; /* -Z (near) */
+ default:
+ q = 4;
+ r = 7;
+ s = 6;
+ break; /* +X */
+ }
+
+ normal_quad_v3(frustum_planes[p], bbox->vec[p], bbox->vec[q], bbox->vec[r], bbox->vec[s]);
+ /* Increase precision and use the mean of all 4 corners. */
+ frustum_planes[p][3] = -dot_v3v3(frustum_planes[p], bbox->vec[p]);
+ frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[q]);
+ frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[r]);
+ frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[s]);
+ frustum_planes[p][3] *= 0.25f;
+ }
+}
+
+static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
+ const float (*viewinv)[4],
+ const float (*projmat)[4],
+ const float (*projinv)[4],
+ BoundSphere *bsphere)
+{
+ /* Extract Bounding Sphere */
+ if (projmat[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 (projmat[2][0] == 0.0f && projmat[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]; /* farpoint 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 cliping 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, projinv, 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, projinv, 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;
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
+
+ /* Transform to world space. */
+ mul_m4_v3(viewinv, bsphere->center);
+ }
+}
+
+static void draw_matrix_state_from_view(DRWMatrixState *mstate,
+ const float viewmat[4][4],
+ const float winmat[4][4])
+{
+ /* If only one the matrices is negative, then the
+ * polygon winding changes and we don't want that. */
+ BLI_assert(is_negative_m4(viewmat) != is_negative_m4(winmat));
+
+ copy_m4_m4(mstate->viewmat, viewmat);
+ invert_m4_m4(mstate->viewinv, mstate->viewmat);
+
+ copy_m4_m4(mstate->winmat, winmat);
+ invert_m4_m4(mstate->wininv, mstate->winmat);
+
+ mul_m4_m4m4(mstate->persmat, winmat, viewmat);
+ invert_m4_m4(mstate->persinv, mstate->persmat);
+}
+
+/* Create a view with culling. */
+DRWView *DRW_view_create(const float viewmat[4][4],
+ const float winmat[4][4],
+ const float (*culling_viewmat)[4],
+ const float (*culling_winmat)[4],
+ DRWCallVisibilityFn *visibility_fn)
+{
+ DRWView *view = BLI_memblock_alloc(DST.vmempool->views);
+
+ if (DST.primary_view_ct < MAX_CULLED_VIEWS) {
+ view->culling_mask = 1u << DST.primary_view_ct++;
+ }
+ else {
+ view->culling_mask = 0u;
+ }
+ view->clip_planes_len = 0;
+ view->visibility_fn = visibility_fn;
+ view->parent = NULL;
+
+ /* TODO move elsewhere */
+ if (DST.view_default) {
+ copy_v4_v4(view->storage.viewcamtexcofac, DST.view_default->storage.viewcamtexcofac);
+ }
+
+ DRW_view_update(view, viewmat, winmat, culling_viewmat, culling_winmat);
+
+ return view;
+}
+
+/* Create a view with culling done by another view. */
+DRWView *DRW_view_create_sub(const DRWView *parent_view,
+ const float viewmat[4][4],
+ const float winmat[4][4])
+{
+ BLI_assert(parent_view && parent_view->parent == NULL);
+
+ DRWView *view = BLI_memblock_alloc(DST.vmempool->views);
+
+ /* Perform copy. */
+ *view = *parent_view;
+ view->parent = (DRWView *)parent_view;
+
+ /* TODO move elsewhere */
+ if (DST.view_default) {
+ copy_v4_v4(view->storage.viewcamtexcofac, DST.view_default->storage.viewcamtexcofac);
+ }
+
+ DRW_view_update_sub(view, viewmat, winmat);
+
+ return view;
+}
+
+/**
+ * DRWView Update:
+ * This is meant to be done on existing views when rendering in a loop and there is no
+ * need to allocate more DRWViews.
+ **/
+
+/* Update matrices of a view created with DRW_view_create_sub. */
+void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4])
+{
+ BLI_assert(view->parent != NULL);
+ DRWMatrixState *mstate = &view->storage.matstate;
+
+ view->is_dirty = true;
+
+ draw_matrix_state_from_view(mstate, viewmat, winmat);
+}
+
+/* Update matrices of a view created with DRW_view_create. */
+void DRW_view_update(DRWView *view,
+ const float viewmat[4][4],
+ const float winmat[4][4],
+ const float (*culling_viewmat)[4],
+ const float (*culling_winmat)[4])
+{
+ /* DO NOT UPDATE THE DEFAULT VIEW.
+ * Create subviews instead, or a copy. */
+ BLI_assert(view != DST.view_default);
+ BLI_assert(view->parent == NULL);
+ DRWMatrixState *mstate = &view->storage.matstate;
+
+ view->is_dirty = true;
+
+ draw_matrix_state_from_view(mstate, viewmat, winmat);
+
+ /* Prepare frustum culling. */
+
+#ifdef DRW_DEBUG_CULLING
+ static float mv[MAX_CULLED_VIEWS][4][4], mw[MAX_CULLED_VIEWS][4][4];
+
+ /* Select view here. */
+ if (view->culling_mask != 0) {
+ uint index = bitscan_forward_uint(view->culling_mask);
+
+ if (G.debug_value == 0) {
+ copy_m4_m4(mv[index], culling_viewmat ? culling_viewmat : viewmat);
+ copy_m4_m4(mw[index], culling_winmat ? culling_winmat : winmat);
+ }
+ else {
+ culling_winmat = mw[index];
+ culling_viewmat = mv[index];
+ }
+ }
+#endif
+
+ float wininv[4][4];
+ if (culling_winmat) {
+ winmat = culling_winmat;
+ invert_m4_m4(wininv, winmat);
+ }
+ else {
+ copy_m4_m4(wininv, mstate->wininv);
+ }
+
+ float viewinv[4][4];
+ if (culling_viewmat) {
+ viewmat = culling_viewmat;
+ invert_m4_m4(viewinv, viewmat);
+ }
+ else {
+ copy_m4_m4(viewinv, mstate->viewinv);
+ }
+
+ draw_frustum_boundbox_calc(viewinv, winmat, &view->frustum_corners);
+ draw_frustum_culling_planes_calc(&view->frustum_corners, view->frustum_planes);
+ draw_frustum_bound_sphere_calc(
+ &view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere);
+
+#ifdef DRW_DEBUG_CULLING
+ if (G.debug_value != 0) {
+ DRW_debug_sphere(
+ view->frustum_bsphere.center, view->frustum_bsphere.radius, (const float[4]){1, 1, 0, 1});
+ DRW_debug_bbox(&view->frustum_corners, (const float[4]){1, 1, 0, 1});
+ }
+#endif
+}
+
+/* Return default view if it is a viewport render. */
+const DRWView *DRW_view_default_get(void)
+{
+ return DST.view_default;
+}
+
+/* MUST only be called once per render and only in render mode. Sets default view. */
+void DRW_view_default_set(DRWView *view)
+{
+ BLI_assert(DST.view_default == NULL);
+ DST.view_default = view;
+}
+
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ */
+void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len)
+{
+ BLI_assert(plane_len <= MAX_CLIP_PLANES);
+ view->clip_planes_len = plane_len;
+ if (plane_len > 0) {
+ memcpy(view->storage.clipplanes, planes, sizeof(float) * 4 * plane_len);
+ }
+}
+
+/* Return world space frustum corners. */
+void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
+{
+ memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
+}
+
+/* Return world space frustum sides as planes.
+ * See draw_frustum_culling_planes_calc() for the plane order. */
+void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4])
+{
+ memcpy(planes, &view->frustum_planes, sizeof(view->frustum_planes));
+}
+
+bool DRW_view_is_persp_get(const DRWView *view)
+{
+ view = (view) ? view : DST.view_active;
+ return view->storage.matstate.winmat[3][3] == 0.0f;
+}
+
+float DRW_view_near_distance_get(const DRWView *view)
+{
+ view = (view) ? view : DST.view_active;
+ const float(*projmat)[4] = view->storage.matstate.winmat;
+
+ if (DRW_view_is_persp_get(view)) {
+ return -projmat[3][2] / (projmat[2][2] - 1.0f);
+ }
+ else {
+ return -(projmat[3][2] + 1.0f) / projmat[2][2];
+ }
+}
+
+float DRW_view_far_distance_get(const DRWView *view)
+{
+ view = (view) ? view : DST.view_active;
+ const float(*projmat)[4] = view->storage.matstate.winmat;
+
+ if (DRW_view_is_persp_get(view)) {
+ return -projmat[3][2] / (projmat[2][2] + 1.0f);
+ }
+ else {
+ return -(projmat[3][2] - 1.0f) / projmat[2][2];
+ }
+}
+
+void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
+{
+ view = (view) ? view : DST.view_active;
+ const DRWMatrixState *state = &view->storage.matstate;
+ copy_m4_m4(mat, (inverse) ? state->viewinv : state->viewmat);
+}
+
+void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
+{
+ view = (view) ? view : DST.view_active;
+ const DRWMatrixState *state = &view->storage.matstate;
+ copy_m4_m4(mat, (inverse) ? state->wininv : state->winmat);
+}
+
+void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse)
+{
+ view = (view) ? view : DST.view_active;
+ const DRWMatrixState *state = &view->storage.matstate;
+ copy_m4_m4(mat, (inverse) ? state->persinv : state->persmat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Passes (DRW_pass)
* \{ */
@@ -1118,8 +1592,8 @@ void DRW_pass_foreach_shgroup(DRWPass *pass,
}
typedef struct ZSortData {
- float *axis;
- float *origin;
+ const float *axis;
+ const float *origin;
} ZSortData;
static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
@@ -1182,8 +1656,7 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
*/
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
- float(*viewinv)[4];
- viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
+ const float(*viewinv)[4] = DST.view_active->storage.matstate.viewinv;
ZSortData zsortdata = {viewinv[2], viewinv[3]};
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 49927b74e72..986c8fe18f6 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -238,7 +238,7 @@ void drw_state_set(DRWState state)
int test;
if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
if (test == 1) {
- for (int i = 0; i < DST.clip_planes_len; ++i) {
+ for (int i = 0; i < DST.view_active->clip_planes_len; ++i) {
glEnable(GL_CLIP_DISTANCE0 + i);
}
}
@@ -395,274 +395,47 @@ void DRW_state_reset(void)
void DRW_state_clip_planes_len_set(uint plane_len)
{
BLI_assert(plane_len <= MAX_CLIP_PLANES);
- DST.clip_planes_len = plane_len;
+ /* DUMMY TO REMOVE */
}
void DRW_state_clip_planes_reset(void)
{
- DST.clip_planes_len = 0;
+ /* DUMMY TO REMOVE */
}
void DRW_state_clip_planes_set_from_rv3d(RegionView3D *rv3d)
{
- int max_len = 6;
- int real_len = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : max_len;
- while (real_len < max_len) {
- /* Fill in dummy values that wont change results (6 is hard coded in shaders). */
- copy_v4_v4(rv3d->clip[real_len], rv3d->clip[3]);
- real_len++;
- }
-
- DRW_state_clip_planes_len_set(max_len);
+ /* DUMMY TO REMOVE */
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Clipping (DRW_clipping)
+/** \name Culling (DRW_culling)
* \{ */
-/* Extract the 8 corners from a Projection Matrix.
- * Although less accurate, this solution can be simplified as follows:
- * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const
- * float[3]){1.0f, 1.0f, 1.0f}); for (int i = 0; i < 8; i++) {mul_project_m4_v3(projinv,
- * bbox.vec[i]);}
- */
-static void draw_frustum_boundbox_calc(const float (*projmat)[4], BoundBox *r_bbox)
+static bool draw_call_is_culled(DRWCall *call, DRWView *view)
{
- float left, right, bottom, top, near, far;
- bool is_persp = projmat[3][3] == 0.0f;
-
- projmat_dimensions(projmat, &left, &right, &bottom, &top, &near, &far);
-
- if (is_persp) {
- left *= near;
- right *= near;
- bottom *= near;
- top *= near;
- }
-
- r_bbox->vec[0][2] = r_bbox->vec[3][2] = r_bbox->vec[7][2] = r_bbox->vec[4][2] = -near;
- r_bbox->vec[0][0] = r_bbox->vec[3][0] = left;
- r_bbox->vec[4][0] = r_bbox->vec[7][0] = right;
- r_bbox->vec[0][1] = r_bbox->vec[4][1] = bottom;
- r_bbox->vec[7][1] = r_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;
- }
-
- r_bbox->vec[1][2] = r_bbox->vec[2][2] = r_bbox->vec[6][2] = r_bbox->vec[5][2] = -far;
- r_bbox->vec[1][0] = r_bbox->vec[2][0] = left;
- r_bbox->vec[6][0] = r_bbox->vec[5][0] = right;
- r_bbox->vec[1][1] = r_bbox->vec[5][1] = bottom;
- r_bbox->vec[2][1] = r_bbox->vec[6][1] = top;
+ return (call->state->culling->mask & view->culling_mask) != 0;
}
-static void draw_clipping_setup_from_view(void)
+/* Set active view for rendering. */
+void DRW_view_set_active(DRWView *view)
{
- if (DST.clipping.updated) {
- return;
- }
-
- float(*viewinv)[4] = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
- float(*projmat)[4] = DST.view_data.matstate.mat[DRW_MAT_WIN];
- float(*projinv)[4] = DST.view_data.matstate.mat[DRW_MAT_WININV];
- BoundSphere *bsphere = &DST.clipping.frustum_bsphere;
-
- /* Extract Clipping Planes */
- BoundBox bbox;
-#if 0 /* It has accuracy problems. */
- BKE_boundbox_init_from_minmax(
- &bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f});
- for (int i = 0; i < 8; i++) {
- mul_project_m4_v3(projinv, bbox.vec[i]);
- }
-#else
- draw_frustum_boundbox_calc(projmat, &bbox);
-#endif
- /* Transform into world space. */
- for (int i = 0; i < 8; i++) {
- mul_m4_v3(viewinv, bbox.vec[i]);
- }
-
- memcpy(&DST.clipping.frustum_corners, &bbox, sizeof(BoundBox));
-
- /* Compute clip planes using the world space frustum corners. */
- for (int p = 0; p < 6; p++) {
- int q, r, s;
- switch (p) {
- case 0:
- q = 1;
- r = 2;
- s = 3;
- break; /* -X */
- case 1:
- q = 0;
- r = 4;
- s = 5;
- break; /* -Y */
- case 2:
- q = 1;
- r = 5;
- s = 6;
- break; /* +Z (far) */
- case 3:
- q = 2;
- r = 6;
- s = 7;
- break; /* +Y */
- case 4:
- q = 0;
- r = 3;
- s = 7;
- break; /* -Z (near) */
- default:
- q = 4;
- r = 7;
- s = 6;
- break; /* +X */
- }
- if (DST.frontface == GL_CW) {
- SWAP(int, q, s);
- }
-
- normal_quad_v3(
- DST.clipping.frustum_planes[p], bbox.vec[p], bbox.vec[q], bbox.vec[r], bbox.vec[s]);
- /* Increase precision and use the mean of all 4 corners. */
- DST.clipping.frustum_planes[p][3] = -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[p]);
- DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[q]);
- DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[r]);
- DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[s]);
- DST.clipping.frustum_planes[p][3] *= 0.25f;
- }
-
- /* Extract Bounding Sphere */
- if (projmat[3][3] != 0.0f) {
- /* Orthographic */
- /* The most extreme points on the near and far plane. (normalized device coords). */
- float *nearpoint = bbox.vec[0];
- 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 (projmat[2][0] == 0.0f && projmat[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]; /* farpoint 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 cliping 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, projinv, 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, projinv, 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;
- bsphere->radius = len_v3v3(bsphere->center, farpoint);
-
- /* Transform to world space. */
- mul_m4_v3(viewinv, bsphere->center);
- }
-
- DST.clipping.updated = true;
+ DST.view_active = (view) ? view : DST.view_default;
}
/* Return True if the given BoundSphere intersect the current view frustum */
-bool DRW_culling_sphere_test(BoundSphere *bsphere)
+static bool draw_culling_sphere_test(const BoundSphere *frustum_bsphere,
+ const float (*frustum_planes)[4],
+ const BoundSphere *bsphere)
{
- draw_clipping_setup_from_view();
-
/* Bypass test if radius is negative. */
if (bsphere->radius < 0.0f) {
return true;
}
/* Do a rough test first: Sphere VS Sphere intersect. */
- BoundSphere *frustum_bsphere = &DST.clipping.frustum_bsphere;
float center_dist_sq = len_squared_v3v3(bsphere->center, frustum_bsphere->center);
float radius_sum = bsphere->radius + frustum_bsphere->radius;
if (center_dist_sq > SQUARE(radius_sum)) {
@@ -674,26 +447,21 @@ bool DRW_culling_sphere_test(BoundSphere *bsphere)
/* TODO order planes with sides first then far then near clip. Should be better culling
* heuristic when sculpting. */
for (int p = 0; p < 6; p++) {
- float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bsphere->center);
+ float dist = plane_point_side_v3(frustum_planes[p], bsphere->center);
if (dist < -bsphere->radius) {
return false;
}
}
-
return true;
}
-/* Return True if the given BoundBox intersect the current view frustum.
- * bbox must be in world space. */
-bool DRW_culling_box_test(BoundBox *bbox)
+static bool draw_culling_box_test(const float (*frustum_planes)[4], const BoundBox *bbox)
{
- draw_clipping_setup_from_view();
-
/* 6 view frustum planes */
for (int p = 0; p < 6; p++) {
/* 8 box vertices. */
for (int v = 0; v < 8; v++) {
- float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bbox->vec[v]);
+ float dist = plane_point_side_v3(frustum_planes[p], bbox->vec[v]);
if (dist > 0.0f) {
/* At least one point in front of this plane.
* Go to next plane. */
@@ -705,139 +473,134 @@ bool DRW_culling_box_test(BoundBox *bbox)
}
}
}
-
return true;
}
-/* Return True if the current view frustum is inside or intersect the given plane */
-bool DRW_culling_plane_test(float plane[4])
+static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4])
{
- draw_clipping_setup_from_view();
-
/* Test against the 8 frustum corners. */
for (int c = 0; c < 8; c++) {
- float dist = plane_point_side_v3(plane, DST.clipping.frustum_corners.vec[c]);
+ float dist = plane_point_side_v3(plane, corners->vec[c]);
if (dist < 0.0f) {
return true;
}
}
-
return false;
}
-void DRW_culling_frustum_corners_get(BoundBox *corners)
+/* Return True if the given BoundSphere intersect the current view frustum.
+ * bsphere must be in world space. */
+bool DRW_culling_sphere_test(const BoundSphere *bsphere)
{
- draw_clipping_setup_from_view();
- memcpy(corners, &DST.clipping.frustum_corners, sizeof(BoundBox));
+ return draw_culling_sphere_test(
+ &DST.view_active->frustum_bsphere, DST.view_active->frustum_planes, bsphere);
}
-/* See draw_clipping_setup_from_view() for the plane order. */
-void DRW_culling_frustum_planes_get(float planes[6][4])
+/* Return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space. */
+bool DRW_culling_box_test(const BoundBox *bbox)
{
- draw_clipping_setup_from_view();
- memcpy(planes, &DST.clipping.frustum_planes, sizeof(DST.clipping.frustum_planes));
+ return draw_culling_box_test(DST.view_active->frustum_planes, bbox);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Draw (DRW_draw)
- * \{ */
-
-static void draw_visibility_eval(DRWCallState *st)
+/* Return True if the view frustum is inside or intersect the given plane.
+ * plane must be in world space. */
+bool DRW_culling_plane_test(const float plane[4])
{
- bool culled = st->flag & DRW_CALL_CULLED;
-
- if (st->cache_id != DST.state_cache_id) {
- /* Update culling result for this view. */
- culled = !DRW_culling_sphere_test(&st->bsphere);
- }
+ return draw_culling_plane_test(&DST.view_active->frustum_corners, plane);
+}
- if (st->visibility_cb) {
- culled = !st->visibility_cb(!culled, st->user_data);
- }
+void DRW_culling_frustum_corners_get(BoundBox *corners)
+{
+ *corners = DST.view_active->frustum_corners;
+}
- SET_FLAG_FROM_TEST(st->flag, culled, DRW_CALL_CULLED);
+void DRW_culling_frustum_planes_get(float planes[6][4])
+{
+ memcpy(planes, DST.view_active->frustum_planes, sizeof(float) * 6 * 4);
}
-static void draw_matrices_model_prepare(DRWCallState *st)
+static void draw_compute_culling(DRWView *view)
{
- if (st->cache_id == DST.state_cache_id) {
- /* Values are already updated for this view. */
- return;
- }
- else {
- st->cache_id = DST.state_cache_id;
- }
+ view = view->parent ? view->parent : view;
- /* No need to go further the call will not be used. */
- if ((st->flag & DRW_CALL_CULLED) != 0 && (st->flag & DRW_CALL_BYPASS_CULLING) == 0) {
+ /* TODO(fclem) multithread this. */
+ /* TODO(fclem) compute all dirty views at once. */
+ if (!view->is_dirty) {
return;
}
- if (st->matflag & DRW_CALL_MODELVIEWPROJECTION) {
- mul_m4_m4m4(st->modelviewprojection, DST.view_data.matstate.mat[DRW_MAT_PERS], st->model);
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(DST.vmempool->cullstates, &iter);
+ DRWCullingState *cull;
+ while ((cull = BLI_memblock_iterstep(&iter))) {
+ if (cull->bsphere.radius < 0.0) {
+ cull->mask = 0;
+ }
+ else {
+ bool culled = !draw_culling_sphere_test(
+ &view->frustum_bsphere, view->frustum_planes, &cull->bsphere);
+
+#ifdef DRW_DEBUG_CULLING
+ if (G.debug_value != 0) {
+ if (culled) {
+ DRW_debug_sphere(
+ cull->bsphere.center, cull->bsphere.radius, (const float[4]){1, 0, 0, 1});
+ }
+ else {
+ DRW_debug_sphere(
+ cull->bsphere.center, cull->bsphere.radius, (const float[4]){0, 1, 0, 1});
+ }
+ }
+#endif
+
+ if (view->visibility_fn) {
+ culled = !view->visibility_fn(!culled, cull->user_data);
+ }
+
+ SET_FLAG_FROM_TEST(cull->mask, culled, view->culling_mask);
+ }
}
+
+ view->is_dirty = false;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw (DRW_draw)
+ * \{ */
+
static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
{
- /* step 1 : bind object dependent matrices */
- if (call != NULL) {
- DRWCallState *state = call->state;
+ BLI_assert(call);
+ DRWCallState *state = call->state;
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
- }
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
- }
- if (shgroup->modelviewprojection != -1) {
- GPU_shader_uniform_vector(shgroup->shader,
- shgroup->modelviewprojection,
- 16,
- 1,
- (float *)state->modelviewprojection);
- }
- if (shgroup->objectinfo != -1) {
- float infos[4];
- infos[0] = state->ob_index;
- // infos[1]; /* UNUSED. */
- infos[2] = state->ob_random;
- infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
- }
- if (shgroup->orcotexfac != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
- }
+ if (shgroup->model != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
}
- else {
- /* For instancing and batching. */
- float unitmat[4][4];
- unit_m4(unitmat);
-
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)unitmat);
- }
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)unitmat);
- }
- if (shgroup->modelviewprojection != -1) {
- GPU_shader_uniform_vector(shgroup->shader,
- shgroup->modelviewprojection,
- 16,
- 1,
- (float *)DST.view_data.matstate.mat[DRW_MAT_PERS]);
- }
- if (shgroup->objectinfo != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)unitmat);
- }
- if (shgroup->orcotexfac != -1) {
- float orcofacs[2][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
- GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)orcofacs);
- }
+ if (shgroup->modelinverse != -1) {
+ GPU_shader_uniform_vector(
+ shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
+ }
+ if (shgroup->objectinfo != -1) {
+ float infos[4];
+ infos[0] = state->ob_index;
+ // infos[1]; /* UNUSED. */
+ infos[2] = state->ob_random;
+ infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
+ }
+ if (shgroup->orcotexfac != -1) {
+ GPU_shader_uniform_vector(
+ shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ }
+ /* Still supported for compatibility with gpu_shader_* but should be forbidden
+ * and is slow (since it does not cache the result). */
+ if (shgroup->modelviewprojection != -1) {
+ float mvp[4][4];
+ mul_m4_m4m4(mvp, DST.view_active->storage.matstate.persmat, state->model);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp);
}
}
@@ -1161,10 +924,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
int callid = 0;
for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
- /* OPTI/IDEA(clem): Do this preparation in another thread. */
- draw_visibility_eval(call->state);
-
- if ((call->state->flag & DRW_CALL_CULLED) != 0) {
+ if (draw_call_is_culled(call, DST.view_active)) {
continue;
}
@@ -1206,29 +966,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
static void drw_update_view(void)
{
- if (DST.dirty_mat) {
- DST.state_cache_id++;
- DST.dirty_mat = false;
-
- DRW_uniformbuffer_update(G_draw.view_ubo, &DST.view_data);
-
- /* Catch integer wrap around. */
- if (UNLIKELY(DST.state_cache_id == 0)) {
- DST.state_cache_id = 1;
- /* We must reset all CallStates to ensure that not
- * a single one stayed with cache_id equal to 1. */
- BLI_memblock_iter iter;
- DRWCallState *state;
- BLI_memblock_iternew(DST.vmempool->states, &iter);
- while ((state = BLI_memblock_iterstep(&iter))) {
- state->cache_id = 0;
- }
- }
+ /* TODO(fclem) update a big UBO and only bind ranges here. */
+ DRW_uniformbuffer_update(G_draw.view_ubo, &DST.view_active->storage);
- /* TODO dispatch threads to compute matrices/culling */
- }
+ /* TODO get rid of this. */
+ DST.view_storage_cpy = DST.view_active->storage;
- draw_clipping_setup_from_view();
+ draw_compute_culling(DST.view_active);
}
static void drw_draw_pass_ex(DRWPass *pass,
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index 1bd94cbeecf..2c22acdc879 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -330,7 +330,8 @@ static DRWPass *edit_mesh_create_overlay_pass(float *face_alpha,
float winmat[4][4];
float viewdist = rv3d->dist;
- DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_view_winmat_get(NULL, winmat, false);
+
/* special exception for ortho camera (viewdist isnt used for perspective cameras) */
if (rv3d->persp == RV3D_CAMOB && rv3d->is_persp == false) {
viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
index 9802b9111fc..845c615c75c 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -9,9 +9,10 @@ layout(std140) uniform viewBlock
mat4 ProjectionMatrix;
mat4 ProjectionMatrixInverse;
- vec4 CameraTexCoFactors;
+ vec4 clipPlanes[6];
- vec4 clipPlanes[2];
+ /* TODO move it elsewhere. */
+ vec4 CameraTexCoFactors;
};
uniform mat4 ModelMatrix;
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index e61cfe363df..e7600279d6f 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -39,8 +39,10 @@ typedef struct GPUViewport GPUViewport;
typedef struct ViewportMemoryPool {
struct BLI_memblock *calls;
struct BLI_memblock *states;
+ struct BLI_memblock *cullstates;
struct BLI_memblock *shgroups;
struct BLI_memblock *uniforms;
+ struct BLI_memblock *views;
struct BLI_memblock *passes;
struct BLI_memblock *images;
} ViewportMemoryPool;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index b825819ceb4..4fd439f4203 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -625,12 +625,18 @@ void GPU_viewport_free(GPUViewport *viewport)
if (viewport->vmempool.states != NULL) {
BLI_memblock_destroy(viewport->vmempool.states, NULL);
}
+ if (viewport->vmempool.cullstates != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.cullstates, NULL);
+ }
if (viewport->vmempool.shgroups != NULL) {
BLI_memblock_destroy(viewport->vmempool.shgroups, NULL);
}
if (viewport->vmempool.uniforms != NULL) {
BLI_memblock_destroy(viewport->vmempool.uniforms, NULL);
}
+ if (viewport->vmempool.views != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.views, NULL);
+ }
if (viewport->vmempool.passes != NULL) {
BLI_memblock_destroy(viewport->vmempool.passes, NULL);
}