Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
409 lines
11 KiB
C++
409 lines
11 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup freestyle
|
|
* \brief Base class to define a cell grid surrounding the bounding box of the scene
|
|
*/
|
|
|
|
#include <cstring> // for memset
|
|
#include <float.h>
|
|
#include <stdint.h> // For POINTER_FROM_UINT, i.e. uintptr_t.
|
|
#include <vector>
|
|
|
|
#include "Geom.h"
|
|
#include "GeomUtils.h"
|
|
#include "Polygon.h"
|
|
|
|
#include "../system/FreestyleConfig.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
# include "MEM_guardedalloc.h"
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
namespace Freestyle {
|
|
|
|
using namespace Geometry;
|
|
|
|
typedef vector<Polygon3r *> OccludersSet;
|
|
|
|
//
|
|
// Class to define cells used by the regular grid
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class Cell {
|
|
public:
|
|
Cell(Vec3r &orig)
|
|
{
|
|
_orig = orig;
|
|
}
|
|
|
|
virtual ~Cell() {}
|
|
|
|
inline void addOccluder(Polygon3r *o)
|
|
{
|
|
if (o) {
|
|
_occluders.push_back(o);
|
|
}
|
|
}
|
|
|
|
inline const Vec3r &getOrigin()
|
|
{
|
|
return _orig;
|
|
}
|
|
|
|
inline OccludersSet &getOccluders()
|
|
{
|
|
return _occluders;
|
|
}
|
|
|
|
private:
|
|
Vec3r _orig;
|
|
OccludersSet _occluders;
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Cell")
|
|
#endif
|
|
};
|
|
|
|
class GridVisitor {
|
|
public:
|
|
virtual ~GridVisitor(){}; // soc
|
|
|
|
virtual void discoverCell(Cell * /*cell*/) {}
|
|
|
|
virtual void examineOccluder(Polygon3r * /*occ*/) {}
|
|
|
|
virtual void finishCell(Cell * /*cell*/) {}
|
|
|
|
virtual bool stop()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridVisitor")
|
|
#endif
|
|
};
|
|
|
|
/** Gathers all the occluders belonging to the cells traversed by the ray */
|
|
class allOccludersGridVisitor : public GridVisitor {
|
|
public:
|
|
allOccludersGridVisitor(OccludersSet &occluders) : GridVisitor(), occluders_(occluders) {}
|
|
|
|
virtual void examineOccluder(Polygon3r *occ);
|
|
|
|
OccludersSet &occluders()
|
|
{
|
|
return occluders_;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
occluders_.clear();
|
|
}
|
|
|
|
private:
|
|
OccludersSet &occluders_;
|
|
};
|
|
|
|
/** Finds the first intersection and breaks.
|
|
* The occluder and the intersection information are stored and accessible.
|
|
*/
|
|
class firstIntersectionGridVisitor : public GridVisitor {
|
|
// soc - changed order to remove warnings
|
|
public:
|
|
double u_, v_, t_;
|
|
|
|
private:
|
|
Polygon3r *occluder_;
|
|
Vec3r ray_org_, ray_dir_, cell_size_;
|
|
Cell *current_cell_;
|
|
|
|
public:
|
|
firstIntersectionGridVisitor(const Vec3r &ray_org, const Vec3r &ray_dir, const Vec3r &cell_size)
|
|
: GridVisitor(),
|
|
u_(0),
|
|
v_(0),
|
|
t_(DBL_MAX),
|
|
occluder_(0),
|
|
ray_org_(ray_org),
|
|
ray_dir_(ray_dir),
|
|
cell_size_(cell_size),
|
|
current_cell_(0)
|
|
{
|
|
}
|
|
|
|
virtual ~firstIntersectionGridVisitor() {}
|
|
|
|
virtual void discoverCell(Cell *cell)
|
|
{
|
|
current_cell_ = cell;
|
|
}
|
|
|
|
virtual void examineOccluder(Polygon3r *occ);
|
|
|
|
virtual bool stop();
|
|
|
|
Polygon3r *occluder()
|
|
{
|
|
return occluder_;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Class to define a regular grid used for ray casting computations
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class Grid {
|
|
public:
|
|
/** Builds a Grid. Must be followed by a call to configure() */
|
|
Grid() {}
|
|
|
|
virtual ~Grid()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
/** clears the grid
|
|
* Deletes all the cells, clears the hash-table, resets size, size of cell, number of cells.
|
|
*/
|
|
virtual void clear();
|
|
|
|
/** Sets the different parameters of the grid
|
|
* orig
|
|
* The grid origin
|
|
* size
|
|
* The grid's dimensions
|
|
* nb
|
|
* The number of cells of the grid
|
|
*/
|
|
virtual void configure(const Vec3r &orig, const Vec3r &size, uint nb);
|
|
|
|
/** returns a vector of integer containing the coordinates of the cell containing the point
|
|
* passed as argument
|
|
* p
|
|
* The point for which we're looking the cell
|
|
*/
|
|
inline void getCellCoordinates(const Vec3r &p, Vec3u &res)
|
|
{
|
|
int tmp;
|
|
for (int i = 0; i < 3; i++) {
|
|
tmp = (int)((p[i] - _orig[i]) / _cell_size[i]);
|
|
if (tmp < 0) {
|
|
res[i] = 0;
|
|
}
|
|
else if ((uint)tmp >= _cells_nb[i]) {
|
|
res[i] = _cells_nb[i] - 1;
|
|
}
|
|
else {
|
|
res[i] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Fills the case corresponding to coord with the cell */
|
|
virtual void fillCell(const Vec3u &coord, Cell &cell) = 0;
|
|
|
|
/** returns the cell whose coordinates are passed as argument */
|
|
virtual Cell *getCell(const Vec3u &coord) = 0;
|
|
|
|
/** returns the cell containing the point passed as argument.
|
|
* If the cell is empty (contains no occluder), nullptr is returned:
|
|
* p
|
|
* The point for which we're looking the cell
|
|
*/
|
|
inline Cell *getCell(const Vec3r &p)
|
|
{
|
|
Vec3u coord;
|
|
getCellCoordinates(p, coord);
|
|
return getCell(coord);
|
|
}
|
|
|
|
/** Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k)
|
|
* is passed as argument:
|
|
* cell_coord
|
|
* i,j,k integer coordinates for the cell
|
|
* orig
|
|
* x,y,x vector to be filled in with the cell origin's coordinates
|
|
*/
|
|
inline void getCellOrigin(const Vec3u &cell_coord, Vec3r &orig)
|
|
{
|
|
for (uint i = 0; i < 3; i++) {
|
|
orig[i] = _orig[i] + cell_coord[i] * _cell_size[i];
|
|
}
|
|
}
|
|
|
|
/** Retrieves the box corresponding to the cell whose coordinates are passed as argument:
|
|
* cell_coord
|
|
* i,j,k integer coordinates for the cell
|
|
* min_out
|
|
* The min x,y,x vector of the box. Filled in by the method.
|
|
* max_out
|
|
* The max x,y,z coordinates of the box. Filled in by the method.
|
|
*/
|
|
inline void getCellBox(const Vec3u &cell_coord, Vec3r &min_out, Vec3r &max_out)
|
|
{
|
|
getCellOrigin(cell_coord, min_out);
|
|
max_out = min_out + _cell_size;
|
|
}
|
|
|
|
/** inserts a convex polygon occluder
|
|
* This method is quite coarse insofar as it adds all cells intersecting the polygon bounding
|
|
* box convex_poly The list of 3D points constituting a convex polygon
|
|
*/
|
|
void insertOccluder(Polygon3r *occluder);
|
|
|
|
/** Adds an occluder to the list of occluders */
|
|
void addOccluder(Polygon3r *occluder)
|
|
{
|
|
_occluders.push_back(occluder);
|
|
}
|
|
|
|
/** Casts a ray between a starting point and an ending point
|
|
* Returns the list of occluders contained in the cells intersected by this ray
|
|
* Starts with a call to InitRay.
|
|
*/
|
|
void castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, uint timestamp);
|
|
|
|
// Prepares to cast ray without generating OccludersSet
|
|
void initAcceleratedRay(const Vec3r &orig, const Vec3r &end, uint timestamp);
|
|
|
|
/** Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a
|
|
* given direction. Returns the list of occluders contained in the cells intersected by this ray
|
|
* Starts with a call to InitRay.
|
|
*/
|
|
void castInfiniteRay(const Vec3r &orig,
|
|
const Vec3r &dir,
|
|
OccludersSet &occluders,
|
|
uint timestamp);
|
|
|
|
// Prepares to cast ray without generating OccludersSet.
|
|
bool initAcceleratedInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint timestamp);
|
|
|
|
/** Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a
|
|
* given direction. Returns the first intersection (occluder,t,u,v) or null. Starts with a call
|
|
* to InitRay.
|
|
*/
|
|
Polygon3r *castRayToFindFirstIntersection(
|
|
const Vec3r &orig, const Vec3r &dir, double &t, double &u, double &v, uint timestamp);
|
|
|
|
/** Init all structures and values for computing the cells intersected by this new ray */
|
|
void initRay(const Vec3r &orig, const Vec3r &end, uint timestamp);
|
|
|
|
/** Init all structures and values for computing the cells intersected by this infinite ray.
|
|
* Returns false if the ray doesn't intersect the grid.
|
|
*/
|
|
bool initInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint timestamp);
|
|
|
|
/** Accessors */
|
|
inline const Vec3r &getOrigin() const
|
|
{
|
|
return _orig;
|
|
}
|
|
|
|
inline Vec3r gridSize() const
|
|
{
|
|
return _size;
|
|
}
|
|
|
|
inline Vec3r getCellSize() const
|
|
{
|
|
return _cell_size;
|
|
}
|
|
|
|
// ARB profiling only:
|
|
inline OccludersSet *getOccluders()
|
|
{
|
|
return &_occluders;
|
|
}
|
|
|
|
void displayDebug()
|
|
{
|
|
cerr << "Cells nb : " << _cells_nb << endl;
|
|
cerr << "Cell size : " << _cell_size << endl;
|
|
cerr << "Origin : " << _orig << endl;
|
|
cerr << "Occluders nb : " << _occluders.size() << endl;
|
|
}
|
|
|
|
protected:
|
|
/** Core of castRay and castInfiniteRay, find occluders along the given ray */
|
|
inline void castRayInternal(GridVisitor &visitor)
|
|
{
|
|
Cell *current_cell = nullptr;
|
|
do {
|
|
current_cell = getCell(_current_cell);
|
|
if (current_cell) {
|
|
visitor.discoverCell(current_cell);
|
|
OccludersSet &occluders =
|
|
current_cell->getOccluders(); // FIXME: I had forgotten the ref &
|
|
for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) {
|
|
if (POINTER_AS_UINT((*it)->userdata2) != _timestamp) {
|
|
(*it)->userdata2 = POINTER_FROM_UINT(_timestamp);
|
|
visitor.examineOccluder(*it);
|
|
}
|
|
}
|
|
visitor.finishCell(current_cell);
|
|
}
|
|
} while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell)));
|
|
}
|
|
|
|
/** returns the cell next to the cell passed as argument. */
|
|
bool nextRayCell(Vec3u ¤t_cell, Vec3u &next_cell);
|
|
|
|
uint _timestamp;
|
|
|
|
Vec3u _cells_nb; // number of cells for x,y,z axis
|
|
Vec3r _cell_size; // cell x,y,z dimensions
|
|
Vec3r _size; // grid x,y,x dimensions
|
|
Vec3r _orig; // grid origin
|
|
|
|
Vec3r _ray_dir; // direction vector for the ray
|
|
Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates)
|
|
Vec3r _pt; // Points corresponding to the incoming and outgoing intersections of one cell with
|
|
// the ray
|
|
real _t_end; // To know when we are at the end of the ray
|
|
real _t;
|
|
|
|
// OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by
|
|
// a ray
|
|
OccludersSet _occluders; // List of all occluders inserted in the grid
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Grid")
|
|
#endif
|
|
};
|
|
|
|
//
|
|
// Class to walk through occluders in grid without building intermediate data structures
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class VirtualOccludersSet {
|
|
public:
|
|
VirtualOccludersSet(Grid &_grid) : grid(_grid){};
|
|
Polygon3r *begin();
|
|
Polygon3r *next();
|
|
Polygon3r *next(bool stopOnNewCell);
|
|
|
|
private:
|
|
Polygon3r *firstOccluderFromNextCell();
|
|
Grid &grid;
|
|
OccludersSet::iterator it, end;
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VirtualOccludersSet")
|
|
#endif
|
|
};
|
|
|
|
} /* namespace Freestyle */
|