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