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
8
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
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
222{
223 if (dirty_ && !procedural_) {
224 dirty_ = false;
225 data_.push_update();
226 culling_.push_update();
227 }
228
231}
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]);
254 data_freeze_.push_update();
255 culling_freeze_[0] = static_cast<ViewCullingData>(culling_[0]);
256 culling_freeze_.push_update();
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);
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)
static AppView * view
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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
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
#define F
StorageArrayBuffer< ObjectBounds, 128 > ObjectBoundsBuf
Definition draw_view.hh:30
StorageArrayBuffer< ObjectInfos, 128 > ObjectInfosBuf
Definition draw_view.hh:31
StorageArrayBuffer< uint, 4, true > VisibilityBuf
Definition draw_view.hh:32
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)
MatBase< float, 4, 4 > float4x4
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