Blender V4.3
draw_view.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_geom.h"
10#include "BLI_math_matrix.hh"
11#include "GPU_compute.hh"
12#include "GPU_debug.hh"
13
14#include "draw_debug.hh"
15#include "draw_shader.hh"
16#include "draw_view.hh"
17
18namespace blender::draw {
19
20void View::sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id)
21{
22 data_[view_id].viewmat = view_mat;
23 data_[view_id].viewinv = math::invert(view_mat);
24 data_[view_id].winmat = win_mat;
25 data_[view_id].wininv = math::invert(win_mat);
26
27 is_inverted_ = (is_negative_m4(view_mat.ptr()) == is_negative_m4(win_mat.ptr()));
28
29 frustum_boundbox_calc(view_id);
32
33 dirty_ = true;
34}
35
36void View::sync(const DRWView *view)
37{
38 float4x4 view_mat, win_mat;
39 DRW_view_viewmat_get(view, view_mat.ptr(), false);
40 DRW_view_winmat_get(view, win_mat.ptr(), false);
41 this->sync(view_mat, win_mat);
42}
43
45{
46 /* Extract the 8 corners from a Projection Matrix. */
47#if 0 /* Equivalent to this but it has accuracy problems. */
48 BKE_boundbox_init_from_minmax(&bbox, float3(-1.0f), float3(1.0f));
49 for (int i = 0; i < 8; i++) {
50 mul_project_m4_v3(data_.wininv.ptr(), bbox.vec[i]);
51 }
52#endif
53
54 MutableSpan<float4> corners = {culling_[view_id].frustum_corners.corners,
55 int64_t(ARRAY_SIZE(culling_[view_id].frustum_corners.corners))};
56
57 float left, right, bottom, top, near, far;
58 bool is_persp = data_[view_id].winmat[3][3] == 0.0f;
59
60 projmat_dimensions(data_[view_id].winmat.ptr(), &left, &right, &bottom, &top, &near, &far);
61
62 corners[0][2] = corners[3][2] = corners[7][2] = corners[4][2] = -near;
63 corners[0][0] = corners[3][0] = left;
64 corners[4][0] = corners[7][0] = right;
65 corners[0][1] = corners[4][1] = bottom;
66 corners[7][1] = corners[3][1] = top;
67
68 /* Get the coordinates of the far plane. */
69 if (is_persp) {
70 float sca_far = far / near;
71 left *= sca_far;
72 right *= sca_far;
73 bottom *= sca_far;
74 top *= sca_far;
75 }
76
77 corners[1][2] = corners[2][2] = corners[6][2] = corners[5][2] = -far;
78 corners[1][0] = corners[2][0] = left;
79 corners[6][0] = corners[5][0] = right;
80 corners[1][1] = corners[5][1] = bottom;
81 corners[2][1] = corners[6][1] = top;
82
83 const float4x4 &view_inv = data_[view_id].viewinv;
84 /* Transform into world space. */
85 for (float4 &corner : corners) {
86 corner = float4(math::transform_point(view_inv, float3(corner)), 1.0);
87 }
88}
89
91{
92 float4x4 persmat = data_[view_id].winmat * data_[view_id].viewmat;
94 culling_[view_id].frustum_planes.planes[0],
95 culling_[view_id].frustum_planes.planes[5],
96 culling_[view_id].frustum_planes.planes[1],
97 culling_[view_id].frustum_planes.planes[3],
98 culling_[view_id].frustum_planes.planes[4],
99 culling_[view_id].frustum_planes.planes[2]);
100 /* Normalize. */
101 for (float4 &plane : culling_[view_id].frustum_planes.planes) {
102 plane /= math::length(plane.xyz());
103 }
104}
105
107{
108 BoundSphere &bsphere = *reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere);
109 Span<float4> corners = {culling_[view_id].frustum_corners.corners,
110 int64_t(ARRAY_SIZE(culling_[view_id].frustum_corners.corners))};
111
112 /* Extract Bounding Sphere */
113 if (data_[view_id].winmat[3][3] != 0.0f) {
114 /* Orthographic */
115 /* The most extreme points on the near and far plane. (normalized device coords). */
116 const float *nearpoint = corners[0];
117 const float *farpoint = corners[6];
118
119 /* just use median point */
120 mid_v3_v3v3(bsphere.center, farpoint, nearpoint);
121 bsphere.radius = len_v3v3(bsphere.center, farpoint);
122 }
123 else if (data_[view_id].winmat[2][0] == 0.0f && data_[view_id].winmat[2][1] == 0.0f) {
124 /* Perspective with symmetrical frustum. */
125
126 /* We obtain the center and radius of the circumscribed circle of the
127 * isosceles trapezoid composed by the diagonals of the near and far clipping plane */
128
129 /* center of each clipping plane */
130 float mid_min[3], mid_max[3];
131 mid_v3_v3v3(mid_min, corners[3], corners[4]);
132 mid_v3_v3v3(mid_max, corners[2], corners[5]);
133
134 /* square length of the diagonals of each clipping plane */
135 float a_sq = len_squared_v3v3(corners[3], corners[4]);
136 float b_sq = len_squared_v3v3(corners[2], corners[5]);
137
138 /* distance squared between clipping planes */
139 float h_sq = len_squared_v3v3(mid_min, mid_max);
140
141 float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq);
142
143 /* The goal is to get the smallest sphere,
144 * not the sphere that passes through each corner */
145 CLAMP(fac, 0.0f, 1.0f);
146
147 interp_v3_v3v3(bsphere.center, mid_min, mid_max, fac);
148
149 /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
150 bsphere.radius = len_v3v3(bsphere.center, corners[1]);
151 }
152 else {
153 /* Perspective with asymmetrical frustum. */
154
155 /* We put the sphere center on the line that goes from origin
156 * to the center of the far clipping plane. */
157
158 /* Detect which of the corner of the far clipping plane is the farthest to the origin */
159 float nfar[4]; /* most extreme far point in NDC space */
160 float farxy[2]; /* far-point projection onto the near plane */
161 float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */
162 float nearpoint[3]; /* most extreme near point in camera coordinate */
163 float farcenter[3] = {0.0f}; /* center of far clipping plane in camera coordinate */
164 float F = -1.0f, N; /* square distance of far and near point to origin */
165 float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */
166 float e, s; /* far and near clipping distance (<0) */
167 float c; /* slope of center line = distance of far clipping center
168 * to z axis / far clipping distance. */
169 float z; /* projection of sphere center on z axis (<0) */
170
171 /* Find farthest corner and center of far clip plane. */
172 float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */
173 for (int i = 0; i < 4; i++) {
174 float point[3];
175 mul_v3_project_m4_v3(point, data_[view_id].wininv.ptr(), corner);
176 float len = len_squared_v3(point);
177 if (len > F) {
178 copy_v3_v3(nfar, corner);
179 copy_v3_v3(farpoint, point);
180 F = len;
181 }
182 add_v3_v3(farcenter, point);
183 /* rotate by 90 degree to walk through the 4 points of the far clip plane */
184 float tmp = corner[0];
185 corner[0] = -corner[1];
186 corner[1] = tmp;
187 }
188
189 /* the far center is the average of the far clipping points */
190 mul_v3_fl(farcenter, 0.25f);
191 /* the extreme near point is the opposite point on the near clipping plane */
192 copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f);
193 mul_v3_project_m4_v3(nearpoint, data_[view_id].wininv.ptr(), nfar);
194 /* this is a frustum projection */
195 N = len_squared_v3(nearpoint);
196 e = farpoint[2];
197 s = nearpoint[2];
198 /* distance to view Z axis */
199 f = len_v2(farpoint);
200 /* get corresponding point on the near plane */
201 mul_v2_v2fl(farxy, farpoint, s / e);
202 /* this formula preserve the sign of n */
203 sub_v2_v2(nearpoint, farxy);
204 n = f * s / e - len_v2(nearpoint);
205 c = len_v2(farcenter) / e;
206 /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */
207 z = (F - N) / (2.0f * (e - s + c * (f - n)));
208
209 bsphere.center[0] = farcenter[0] * z / e;
210 bsphere.center[1] = farcenter[1] * z / e;
211 bsphere.center[2] = z;
212
213 /* For XR, the view matrix may contain a scale factor. Then, transforming only the center
214 * into world space after calculating the radius will result in incorrect behavior. */
215 mul_m4_v3(data_[view_id].viewinv.ptr(), bsphere.center); /* Transform to world space. */
216 mul_m4_v3(data_[view_id].viewinv.ptr(), farpoint);
217 bsphere.radius = len_v3v3(bsphere.center, farpoint);
218 }
219}
220
232
246
248 ObjectInfosBuf & /*infos*/,
249 uint resource_len,
250 bool debug_freeze)
251{
252 if (debug_freeze && frozen_ == false) {
253 data_freeze_[0] = static_cast<ViewMatrices>(data_[0]);
255 culling_freeze_[0] = static_cast<ViewCullingData>(culling_[0]);
257 }
258#ifdef _DEBUG
259 if (debug_freeze) {
260 float4x4 persmat = data_freeze_[0].winmat * data_freeze_[0].viewmat;
262 }
263#endif
264 frozen_ = debug_freeze;
265
266 GPU_debug_group_begin("View.compute_visibility");
267
268 /* TODO(fclem): Early out if visibility hasn't changed. */
269
270 uint word_per_draw = this->visibility_word_per_draw();
271 /* Switch between tightly packed and set of whole word per instance. */
272 uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) :
273 resource_len * word_per_draw;
274 words_len = ceil_to_multiple_u(max_ii(1, words_len), 4);
275 /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */
276 visibility_buf_.resize(words_len);
277
278 const uint32_t data = 0xFFFFFFFFu;
280
281 if (do_visibility_) {
283 GPU_shader_bind(shader);
284 GPU_shader_uniform_1i(shader, "resource_len", resource_len);
285 GPU_shader_uniform_1i(shader, "view_len", view_len_);
286 GPU_shader_uniform_1i(shader, "visibility_word_per_draw", word_per_draw);
287 GPU_storagebuf_bind(bounds, GPU_shader_get_ssbo_binding(shader, "bounds_buf"));
293 }
294
295 if (frozen_) {
296 /* Bind back the non frozen data. */
299 }
300
302}
303
308
309} // namespace blender::draw
void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float max[3])
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE int max_ii(int a, int b)
void projmat_dimensions(const float winmat[4][4], float *r_left, float *r_right, float *r_bottom, float *r_top, float *r_near, float *r_far)
void planes_from_projmat(const float mat[4][4], float left[4], float right[4], float bottom[4], float top[4], float near[4], float far[4])
void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3])
void mul_project_m4_v3(const float mat[4][4], float vec[3])
void mul_m4_v3(const float M[4][4], float r[3])
bool is_negative_m4(const float mat[4][4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
#define CLAMP(a, b, c)
#define ARRAY_SIZE(arr)
void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len)
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
void GPU_shader_bind(GPUShader *shader)
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_UNIFORM
Definition GPU_state.hh:54
void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value)
void GPU_uniformbuf_bind_as_ssbo(GPUUniformBuf *ubo, int slot)
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
struct GPUShader GPUShader
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
UniformArrayBuffer< ViewCullingData, DRW_VIEW_MAX > culling_
Definition draw_view.hh:41
VisibilityBuf visibility_buf_
Definition draw_view.hh:46
bool is_persp(int view_id=0) const
Definition draw_view.hh:90
const float4x4 & winmat(int view_id=0) const
Definition draw_view.hh:145
const float4x4 persmat(int view_id=0) const
Definition draw_view.hh:158
void compute_procedural_bounds()
Definition draw_view.cc:233
UniformArrayBuffer< ViewMatrices, DRW_VIEW_MAX > data_freeze_
Definition draw_view.hh:43
virtual void compute_visibility(ObjectBoundsBuf &bounds, ObjectInfosBuf &infos, uint resource_len, bool debug_freeze)
Definition draw_view.cc:247
UniformArrayBuffer< ViewMatrices, DRW_VIEW_MAX > data_
Definition draw_view.hh:40
UniformArrayBuffer< ViewCullingData, DRW_VIEW_MAX > culling_freeze_
Definition draw_view.hh:44
const float4x4 & viewinv(int view_id=0) const
Definition draw_view.hh:139
virtual VisibilityBuf & get_visibility_buffer()
Definition draw_view.cc:304
void frustum_culling_sphere_calc(int view_id)
Definition draw_view.cc:106
const float4x4 & wininv(int view_id=0) const
Definition draw_view.hh:151
int visibility_word_per_draw() const
Definition draw_view.hh:164
void frustum_boundbox_calc(int view_id)
Definition draw_view.cc:44
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id=0)
Definition draw_view.cc:20
void frustum_culling_planes_calc(int view_id)
Definition draw_view.cc:90
Simple API to draw debug shapes and log in the viewport.
#define drw_debug_matrix_as_bbox(...)
Definition draw_debug.hh:33
#define DRW_VISIBILITY_GROUP_SIZE
#define DRW_VIEW_CULLING_UBO_SLOT
#define DRW_VIEW_UBO_SLOT
int len
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)
GPUShader * DRW_shader_draw_visibility_compute_get()
GPUShader * DRW_shader_draw_view_finalize_get()
uint top
static int left
#define N
T length(const VecBase< T, Size > &a)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
float center[3]
Definition DRW_render.hh:93
const c_style_mat & ptr() const