Blender V4.3
Grid.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include <stdexcept>
11
12#include "BBox.h"
13#include "Grid.h"
14
15#include "BLI_utildefines.h"
16
17namespace Freestyle {
18
19// Grid Visitors
22{
23 occluders_.push_back(occ);
24}
25
26static bool inBox(const Vec3r &inter, const Vec3r &box_min, const Vec3r &box_max)
27{
28 if (((inter.x() >= box_min.x()) && (inter.x() < box_max.x())) &&
29 ((inter.y() >= box_min.y()) && (inter.y() < box_max.y())) &&
30 ((inter.z() >= box_min.z()) && (inter.z() < box_max.z())))
31 {
32 return true;
33 }
34 return false;
35}
36
38{
39 // check whether the edge and the polygon plane are coincident:
40 //-------------------------------------------------------------
41 // first let us compute the plane equation.
42 Vec3r v1((occ)->getVertices()[0]);
43 Vec3d normal((occ)->getNormal());
44 // soc unused - double d = -(v1 * normal);
45
46 double tmp_u, tmp_v, tmp_t;
47 if ((occ)->rayIntersect(ray_org_, ray_dir_, tmp_t, tmp_u, tmp_v)) {
48 if (fabs(ray_dir_ * normal) > 0.0001) {
49 // Check whether the intersection is in the cell:
50 if (inBox(ray_org_ + tmp_t * ray_dir_ / ray_dir_.norm(),
51 current_cell_->getOrigin(),
52 current_cell_->getOrigin() + cell_size_))
53 {
54#if 0
55 Vec3d bboxdiag(_scene3d->bbox().getMax() - _scene3d->bbox().getMin());
56 if ((t > 1.0e-06 * (min(min(bboxdiag.x(), bboxdiag.y()), bboxdiag.z()))) &&
57 (t < raylength)) {
58#else
59 if (tmp_t < t_) {
60#endif
61 occluder_ = occ;
62 u_ = tmp_u;
63 v_ = tmp_v;
64 t_ = tmp_t;
65 }
66 }
67 else {
68 occ->userdata2 = nullptr;
69 }
70 }
71 }
72} // namespace Freestyle
73
75{
76 if (occluder_) {
77 return true;
78 }
79 return false;
80}
81
82// Grid
85{
86 if (!_occluders.empty()) {
87 for (OccludersSet::iterator it = _occluders.begin(); it != _occluders.end(); it++) {
88 delete (*it);
89 }
90 _occluders.clear();
91 }
92
93 _size = Vec3r(0, 0, 0);
94 _cell_size = Vec3r(0, 0, 0);
95 _orig = Vec3r(0, 0, 0);
96 _cells_nb = Vec3u(0, 0, 0);
97 //_ray_occluders.clear();
98}
99
100void Grid::configure(const Vec3r &orig, const Vec3r &size, uint nb)
101{
102 _orig = orig;
103 Vec3r tmpSize = size;
104 // Compute the volume of the desired grid
105 real grid_vol = size[0] * size[1] * size[2];
106
107 if (grid_vol == 0) {
108 double min = DBL_MAX;
109 int index = 0;
110 int nzeros = 0;
111 for (int i = 0; i < 3; ++i) {
112 if (size[i] == 0) {
113 ++nzeros;
114 index = i;
115 }
116 if ((size[i] != 0) && (min > size[i])) {
117 min = size[i];
118 }
119 }
120 if (nzeros > 1) {
121 throw std::runtime_error("Warning: the 3D grid has more than one null dimension");
122 }
123 tmpSize[index] = min;
124 _orig[index] = _orig[index] - min / 2;
125 }
126 // Compute the desired volume of a single cell
127 real cell_vol = grid_vol / nb;
128 // The edge of such a cubic cell is cubic root of cellVolume
129 real edge = pow(cell_vol, 1.0 / 3.0);
130
131 // We compute the number of cells par edge such as we cover at least the whole box.
132 uint i;
133 for (i = 0; i < 3; i++) {
134 _cells_nb[i] = uint(floor(tmpSize[i] / edge)) + 1;
135 }
136
137 _size = tmpSize;
138
139 for (i = 0; i < 3; i++) {
140 _cell_size[i] = _size[i] / _cells_nb[i];
141 }
142}
143
145{
146 const vector<Vec3r> vertices = occluder->getVertices();
147 if (vertices.empty()) {
148 return;
149 }
150
151 // add this occluder to the grid's occluders list
152 addOccluder(occluder);
153
154 // find the bbox associated to this polygon
155 Vec3r min, max;
156 occluder->getBBox(min, max);
157
158 // Retrieve the cell x, y, z coordinates associated with these min and max
159 Vec3u imax, imin;
160 getCellCoordinates(max, imax);
161 getCellCoordinates(min, imin);
162
163 // We are now going to fill in the cells overlapping with the polygon bbox.
164 // If the polygon is a triangle (most of cases), we also check for each of these cells if it is
165 // overlapping with the triangle in order to only fill in the ones really overlapping the
166 // triangle.
167
168 uint i, x, y, z;
169 vector<Vec3r>::const_iterator it;
170 Vec3u coord;
171
172 if (vertices.size() == 3) { // Triangle case
173 Vec3r triverts[3];
174 i = 0;
175 for (it = vertices.begin(); it != vertices.end(); it++) {
176 triverts[i] = Vec3r(*it);
177 i++;
178 }
179
180 Vec3r boxmin, boxmax;
181
182 for (z = imin[2]; z <= imax[2]; z++) {
183 for (y = imin[1]; y <= imax[1]; y++) {
184 for (x = imin[0]; x <= imax[0]; x++) {
185 coord[0] = x;
186 coord[1] = y;
187 coord[2] = z;
188 // We retrieve the box coordinates of the current cell
189 getCellBox(coord, boxmin, boxmax);
190 // We check whether the triangle and the box ovewrlap:
191 Vec3r boxcenter((boxmin + boxmax) / 2.0);
192 Vec3r boxhalfsize(_cell_size / 2.0);
193 if (GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) {
194 // We must then create the Cell and add it to the cells list if it does not exist yet.
195 // We must then add the occluder to the occluders list of this cell.
196 Cell *cell = getCell(coord);
197 if (!cell) {
198 cell = new Cell(boxmin);
199 fillCell(coord, *cell);
200 }
201 cell->addOccluder(occluder);
202 }
203 }
204 }
205 }
206 }
207 else { // The polygon is not a triangle, we add all the cells overlapping the polygon bbox.
208 for (z = imin[2]; z <= imax[2]; z++) {
209 for (y = imin[1]; y <= imax[1]; y++) {
210 for (x = imin[0]; x <= imax[0]; x++) {
211 coord[0] = x;
212 coord[1] = y;
213 coord[2] = z;
214 Cell *cell = getCell(coord);
215 if (!cell) {
216 Vec3r orig;
217 getCellOrigin(coord, orig);
218 cell = new Cell(orig);
219 fillCell(coord, *cell);
220 }
221 cell->addOccluder(occluder);
222 }
223 }
224 }
225 }
226}
227
228bool Grid::nextRayCell(Vec3u &current_cell, Vec3u &next_cell)
229{
230 next_cell = current_cell;
231 real t_min, t;
232 uint i;
233
234 t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0.
235 uint coord = 0; // predominant coord(0=x, 1=y, 2=z)
236
237 // using a parametric equation of a line : B = A + t u, we find the tx, ty and tz respectively
238 // corresponding to the intersections with the plans:
239 // x = _cell_size[0], y = _cell_size[1], z = _cell_size[2]
240 for (i = 0; i < 3; i++) {
241 if (_ray_dir[i] == 0) {
242 continue;
243 }
244 if (_ray_dir[i] > 0) {
245 t = (_cell_size[i] - _pt[i]) / _ray_dir[i];
246 }
247 else {
248 t = -_pt[i] / _ray_dir[i];
249 }
250 if (t < t_min) {
251 t_min = t;
252 coord = i;
253 }
254 }
255
256 // We use the parametric line equation and the found t (tamx) to compute the B coordinates:
257 Vec3r pt_tmp(_pt);
258 _pt = pt_tmp + t_min * _ray_dir;
259
260 // We express B coordinates in the next cell coordinates system. We just have to
261 // set the coordinate coord of B to 0 of _CellSize[coord] depending on the sign of _u[coord]
262 if (_ray_dir[coord] > 0) {
263 next_cell[coord]++;
264 _pt[coord] -= _cell_size[coord];
265 // if we are out of the grid, we must stop
266 if (next_cell[coord] >= _cells_nb[coord]) {
267 return false;
268 }
269 }
270 else {
271 int tmp = next_cell[coord] - 1;
272 _pt[coord] = _cell_size[coord];
273 if (tmp < 0) {
274 return false;
275 }
276 next_cell[coord]--;
277 }
278
279 _t += t_min;
280 if (_t >= _t_end) {
281 return false;
282 }
283
284 return true;
285}
286
287void Grid::castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, uint timestamp)
288{
289 initRay(orig, end, timestamp);
290 allOccludersGridVisitor visitor(occluders);
291 castRayInternal(visitor);
292}
293
295 const Vec3r &dir,
296 OccludersSet &occluders,
297 uint timestamp)
298{
299 Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
300 bool inter = initInfiniteRay(orig, dir, timestamp);
301 if (!inter) {
302 return;
303 }
304 allOccludersGridVisitor visitor(occluders);
305 castRayInternal(visitor);
306}
307
309 const Vec3r &orig, const Vec3r &dir, double &t, double &u, double &v, uint timestamp)
310{
311 Polygon3r *occluder = nullptr;
312 Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
313 bool inter = initInfiniteRay(orig, dir, timestamp);
314 if (!inter) {
315 return nullptr;
316 }
317 firstIntersectionGridVisitor visitor(orig, dir, _cell_size);
318 castRayInternal(visitor);
319 // ARB: This doesn't work, because occluders are unordered within any cell
320 // visitor.occluder() will be an occluder, but we have no guarantee it will be the *first*
321 // occluder. I assume that is the reason this code is not actually used for FindOccludee.
322 occluder = visitor.occluder();
323 t = visitor.t_;
324 u = visitor.u_;
325 v = visitor.v_;
326 return occluder;
327}
328
329void Grid::initRay(const Vec3r &orig, const Vec3r &end, uint timestamp)
330{
331 _ray_dir = end - orig;
332 _t_end = _ray_dir.norm();
333 _t = 0;
334 _ray_dir.normalize();
335 _timestamp = timestamp;
336
337 for (uint i = 0; i < 3; i++) {
338 _current_cell[i] = uint(floor((orig[i] - _orig[i]) / _cell_size[i]));
339 // soc unused - uint u = _current_cell[i];
340 _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
341 }
342 //_ray_occluders.clear();
343}
344
345bool Grid::initInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint timestamp)
346{
347 _ray_dir = dir;
348 _t_end = FLT_MAX;
349 _t = 0;
350 _ray_dir.normalize();
351 _timestamp = timestamp;
352
353 // check whether the origin is in or out the box:
354 Vec3r boxMin(_orig);
355 Vec3r boxMax(_orig + _size);
356 BBox<Vec3r> box(boxMin, boxMax);
357 if (box.inside(orig)) {
358 for (uint i = 0; i < 3; i++) {
359 _current_cell[i] = uint(floor((orig[i] - _orig[i]) / _cell_size[i]));
360 // soc unused - uint u = _current_cell[i];
361 _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
362 }
363 }
364 else {
365 // is the ray intersecting the box?
366 real tmin(-1.0), tmax(-1.0);
367 if (GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)) {
368 BLI_assert(tmin != -1.0);
369 Vec3r newOrig = orig + tmin * _ray_dir;
370 for (uint i = 0; i < 3; i++) {
371 _current_cell[i] = uint(floor((newOrig[i] - _orig[i]) / _cell_size[i]));
372 if (_current_cell[i] == _cells_nb[i]) {
373 _current_cell[i] = _cells_nb[i] - 1;
374 }
375 // soc unused - uint u = _current_cell[i];
376 _pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
377 }
378 }
379 else {
380 return false;
381 }
382 }
383 //_ray_occluders.clear();
384
385 return true;
386}
387
388} /* namespace Freestyle */
A class to hold a bounding box.
#define BLI_assert(a)
Definition BLI_assert.h:50
unsigned int uint
Base class to define a cell grid surrounding the bounding box of the scene.
ATTR_WARN_UNUSED_RESULT const BMVert * v
const btVector3 * getVertices() const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
void addOccluder(Polygon3r *o)
Definition Grid.h:51
const Vec3r & getOrigin()
Definition Grid.h:58
void getBBox(Point &min, Point &max) const
Definition Polygon.h:73
const vector< Point > & getVertices() const
Definition Polygon.h:68
void castInfiniteRay(const Vec3r &orig, const Vec3r &dir, OccludersSet &occluders, uint timestamp)
Definition Grid.cpp:294
bool nextRayCell(Vec3u &current_cell, Vec3u &next_cell)
Definition Grid.cpp:228
virtual void configure(const Vec3r &orig, const Vec3r &size, uint nb)
Definition Grid.cpp:100
bool initInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint timestamp)
Definition Grid.cpp:345
virtual void clear()
Definition Grid.cpp:84
Polygon3r * castRayToFindFirstIntersection(const Vec3r &orig, const Vec3r &dir, double &t, double &u, double &v, uint timestamp)
Definition Grid.cpp:308
void insertOccluder(Polygon3r *occluder)
Definition Grid.cpp:144
void castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, uint timestamp)
Definition Grid.cpp:287
void initRay(const Vec3r &orig, const Vec3r &end, uint timestamp)
Definition Grid.cpp:329
value_type x() const
Definition VecMat.h:493
value_type z() const
Definition VecMat.h:513
value_type y() const
Definition VecMat.h:503
Vec< T, N > & normalize()
Definition VecMat.h:104
value_type norm() const
Definition VecMat.h:94
virtual void examineOccluder(Polygon3r *occ)
Definition Grid.cpp:21
virtual void examineOccluder(Polygon3r *occ)
Definition Grid.cpp:37
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float2 fabs(const float2 a)
bool overlapTriangleBox(const Vec3r &boxcenter, const Vec3r &boxhalfsize, const Vec3r triverts[3])
bool intersectRayBBox(const Vec3r &orig, const Vec3r &dir, const Vec3r &boxMin, const Vec3r &boxMax, real t0, real t1, real &tmin, real &tmax, real)
VecMat::Vec3< uint > Vec3u
Definition Geom.h:26
VecMat::Vec3< real > Vec3r
Definition Geom.h:30
inherits from class Rep
Definition AppCanvas.cpp:20
vector< Polygon3r * > OccludersSet
Definition Grid.h:35
static bool inBox(const Vec3r &inter, const Vec3r &box_min, const Vec3r &box_max)
Definition Grid.cpp:26
static uint x[3]
Definition RandGen.cpp:77
double real
Definition Precision.h:14
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float max