Blender  V2.93
CulledOccluderSource.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
22 #include "CulledOccluderSource.h"
23 
24 #include "../geometry/GridHelpers.h"
25 
26 #include "BKE_global.h"
27 
28 namespace Freestyle {
29 
30 CulledOccluderSource::CulledOccluderSource(const GridHelpers::Transform &t,
31  WingedEdge &we,
32  ViewMap &viewMap,
33  bool extensiveFEdgeSearch)
34  : OccluderSource(t, we), rejected(0), gridSpaceOccluderProsceniumInitialized(false)
35 {
36  cullViewEdges(viewMap, extensiveFEdgeSearch);
37 
38  // If we have not found any visible FEdges during our cull, then there is nothing to iterate
39  // over. Short-circuit everything.
40  valid = gridSpaceOccluderProsceniumInitialized;
41 
42  if (valid && !testCurrent()) {
43  next();
44  }
45 }
46 
47 bool CulledOccluderSource::testCurrent()
48 {
49  if (valid) {
50  // The test for gridSpaceOccluderProsceniumInitialized should not be necessary
51  return gridSpaceOccluderProsceniumInitialized &&
52  GridHelpers::insideProscenium(gridSpaceOccluderProscenium, cachedPolygon);
53  }
54  return false;
55 }
56 
58 {
59  while (OccluderSource::next()) {
60  if (testCurrent()) {
61  ++rejected;
62  return true;
63  }
64  }
65  if (G.debug & G_DEBUG_FREESTYLE) {
66  std::cout << "Finished generating occluders. Rejected " << rejected << " faces." << std::endl;
67  }
68  return false;
69 }
70 
72 {
73  for (unsigned int i = 0; i < 4; ++i) {
74  proscenium[i] = gridSpaceOccluderProscenium[i];
75  }
76 }
77 
78 static inline real distance2D(const Vec3r &point, const real origin[2])
79 {
80  return ::hypot((point[0] - origin[0]), (point[1] - origin[1]));
81 }
82 
83 static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
84 {
85  Vec2r min(proscenium[0], proscenium[2]);
86  Vec2r max(proscenium[1], proscenium[3]);
87  Vec2r A(fe->vertexA()->getProjectedX(), fe->vertexA()->getProjectedY());
88  Vec2r B(fe->vertexB()->getProjectedX(), fe->vertexB()->getProjectedY());
89 
91 }
92 
93 static inline bool insideProscenium(const real proscenium[4], const Vec3r &point)
94 {
95  return !(point[0] < proscenium[0] || point[0] > proscenium[1] || point[1] < proscenium[2] ||
96  point[1] > proscenium[3]);
97 }
98 
99 void CulledOccluderSource::cullViewEdges(ViewMap &viewMap, bool extensiveFEdgeSearch)
100 {
101  // Cull view edges by marking them as non-displayable.
102  // This avoids the complications of trying to delete edges from the ViewMap.
103 
104  // Non-displayable view edges will be skipped over during visibility calculation.
105 
106  // View edges will be culled according to their position w.r.t. the viewport proscenium (viewport
107  // + 5% border, or some such).
108 
109  // Get proscenium boundary for culling
110  real viewProscenium[4];
112  real prosceniumOrigin[2];
113  prosceniumOrigin[0] = (viewProscenium[1] - viewProscenium[0]) / 2.0;
114  prosceniumOrigin[1] = (viewProscenium[3] - viewProscenium[2]) / 2.0;
115  if (G.debug & G_DEBUG_FREESTYLE) {
116  cout << "Proscenium culling:" << endl;
117  cout << "Proscenium: [" << viewProscenium[0] << ", " << viewProscenium[1] << ", "
118  << viewProscenium[2] << ", " << viewProscenium[3] << "]" << endl;
119  cout << "Origin: [" << prosceniumOrigin[0] << ", " << prosceniumOrigin[1] << "]" << endl;
120  }
121 
122  // A separate occluder proscenium will also be maintained, starting out the same as the viewport
123  // proscenium, and expanding as necessary so that it encompasses the center point of at least one
124  // feature edge in each retained view edge. The occluder proscenium will be used later to cull
125  // occluding triangles before they are inserted into the Grid. The occluder proscenium starts out
126  // the same size as the view proscenium
127  GridHelpers::getDefaultViewProscenium(occluderProscenium);
128 
129  // XXX Freestyle is inconsistent in its use of ViewMap::viewedges_container and
130  // vector<ViewEdge*>::iterator. Probably all occurrences of vector<ViewEdge*>::iterator should be
131  // replaced ViewMap::viewedges_container throughout the code. For each view edge
132  ViewMap::viewedges_container::iterator ve, veend;
133 
134  for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
135  // Overview:
136  // Search for a visible feature edge
137  // If none: mark view edge as non-displayable
138  // Otherwise:
139  // Find a feature edge with center point inside occluder proscenium.
140  // If none exists, find the feature edge with center point closest to viewport origin.
141  // Expand occluder proscenium to enclose center point.
142 
143  // For each feature edge, while bestOccluderTarget not found and view edge not visible
144  bool bestOccluderTargetFound = false;
145  FEdge *bestOccluderTarget = nullptr;
146  real bestOccluderDistance = 0.0;
147  FEdge *festart = (*ve)->fedgeA();
148  FEdge *fe = festart;
149  // All ViewEdges start culled
150  (*ve)->setIsInImage(false);
151 
152  // For simple visibility calculation: mark a feature edge that is known to have a center point
153  // inside the occluder proscenium. Cull all other feature edges.
154  do {
155  // All FEdges start culled
156  fe->setIsInImage(false);
157 
158  // Look for the visible edge that can most easily be included in the occluder proscenium.
159  if (!bestOccluderTargetFound) {
160  // If center point is inside occluder proscenium,
161  if (insideProscenium(occluderProscenium, fe->center2d())) {
162  // Use this feature edge for visibility deterimination
163  fe->setIsInImage(true);
164  expandGridSpaceOccluderProscenium(fe);
165  // Mark bestOccluderTarget as found
166  bestOccluderTargetFound = true;
167  bestOccluderTarget = fe;
168  }
169  else {
170  real d = distance2D(fe->center2d(), prosceniumOrigin);
171  // If center point is closer to viewport origin than current target
172  if (bestOccluderTarget == nullptr || d < bestOccluderDistance) {
173  // Then store as bestOccluderTarget
174  bestOccluderDistance = d;
175  bestOccluderTarget = fe;
176  }
177  }
178  }
179 
180  // If feature edge crosses the view proscenium
181  if (!(*ve)->isInImage() && crossesProscenium(viewProscenium, fe)) {
182  // Then the view edge will be included in the image
183  (*ve)->setIsInImage(true);
184  }
185  fe = fe->nextEdge();
186  } while (fe != nullptr && fe != festart && !(bestOccluderTargetFound && (*ve)->isInImage()));
187 
188  // Either we have run out of FEdges, or we already have the one edge we need to determine
189  // visibility Cull all remaining edges.
190  while (!ELEM(fe, NULL, festart)) {
191  fe->setIsInImage(false);
192  fe = fe->nextEdge();
193  }
194 
195  // If bestOccluderTarget was not found inside the occluder proscenium,
196  // we need to expand the occluder proscenium to include it.
197  if ((*ve)->isInImage() && bestOccluderTarget != nullptr && !bestOccluderTargetFound) {
198  // Expand occluder proscenium to enclose bestOccluderTarget
199  Vec3r point = bestOccluderTarget->center2d();
200  if (point[0] < occluderProscenium[0]) {
201  occluderProscenium[0] = point[0];
202  }
203  else if (point[0] > occluderProscenium[1]) {
204  occluderProscenium[1] = point[0];
205  }
206  if (point[1] < occluderProscenium[2]) {
207  occluderProscenium[2] = point[1];
208  }
209  else if (point[1] > occluderProscenium[3]) {
210  occluderProscenium[3] = point[1];
211  }
212  // Use bestOccluderTarget for visibility determination
213  bestOccluderTarget->setIsInImage(true);
214  }
215  }
216 
217  // We are done calculating the occluder proscenium.
218  // Expand the occluder proscenium by an epsilon to avoid rounding errors.
219  const real epsilon = 1.0e-6;
220  occluderProscenium[0] -= epsilon;
221  occluderProscenium[1] += epsilon;
222  occluderProscenium[2] -= epsilon;
223  occluderProscenium[3] += epsilon;
224 
225  // For "Normal" or "Fast" style visibility computation only:
226 
227  // For more detailed visibility calculation, make a second pass through the view map, marking all
228  // feature edges with center points inside the final occluder proscenium. All of these feature
229  // edges can be considered during visibility calculation.
230 
231  // So far we have only found one FEdge per ViewEdge. The "Normal" and "Fast" styles of visibility
232  // computation want to consider many FEdges for each ViewEdge. Here we re-scan the view map to
233  // find any usable FEdges that we skipped on the first pass, or that have become usable because
234  // the occluder proscenium has been expanded since the edge was visited on the first pass.
235  if (extensiveFEdgeSearch) {
236  // For each view edge,
237  for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
238  if (!(*ve)->isInImage()) {
239  continue;
240  }
241  // For each feature edge,
242  FEdge *festart = (*ve)->fedgeA();
243  FEdge *fe = festart;
244  do {
245  // If not (already) visible and center point inside occluder proscenium,
246  if (!fe->isInImage() && insideProscenium(occluderProscenium, fe->center2d())) {
247  // Use the feature edge for visibility determination
248  fe->setIsInImage(true);
249  expandGridSpaceOccluderProscenium(fe);
250  }
251  fe = fe->nextEdge();
252  } while (!ELEM(fe, NULL, festart));
253  }
254  }
255 
256  // Up until now, all calculations have been done in camera space.
257  // However, the occluder source's iteration and the grid that consumes the occluders both work in
258  // gridspace, so we need a version of the occluder proscenium in gridspace. Set the gridspace
259  // occlude proscenium
260 }
261 
262 void CulledOccluderSource::expandGridSpaceOccluderProscenium(FEdge *fe)
263 {
264  if (gridSpaceOccluderProsceniumInitialized) {
265  GridHelpers::expandProscenium(gridSpaceOccluderProscenium, transform(fe->center3d()));
266  }
267  else {
268  const Vec3r &point = transform(fe->center3d());
269  gridSpaceOccluderProscenium[0] = gridSpaceOccluderProscenium[1] = point[0];
270  gridSpaceOccluderProscenium[2] = gridSpaceOccluderProscenium[3] = point[1];
271  gridSpaceOccluderProsceniumInitialized = true;
272  }
273 }
274 
275 } /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:140
#define ELEM(...)
Class to define a cell grid surrounding the projected image of a scene.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
#define A
void getOccluderProscenium(real proscenium[4])
void cullViewEdges(ViewMap &viewMap, bool extensiveFEdgeSearch)
Vec3r center2d()
Definition: Silhouette.h:682
SVertex * vertexA()
Definition: Silhouette.h:611
bool isInImage() const
Definition: Silhouette.h:725
SVertex * vertexB()
Definition: Silhouette.h:617
Vec3r center3d()
Definition: Silhouette.h:677
void setIsInImage(bool iFlag)
Definition: Silhouette.h:825
FEdge * nextEdge()
Definition: Silhouette.h:637
const GridHelpers::Transform & transform
virtual real getProjectedY() const
Definition: Silhouette.h:110
virtual real getProjectedX() const
Definition: Silhouette.h:104
viewedges_container & ViewEdges()
Definition: ViewMap.h:117
#define B
bool intersect2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B)
Definition: GeomUtils.cpp:29
VecMat::Vec3< real > Vec3r
Definition: Geom.h:42
void getDefaultViewProscenium(real viewProscenium[4])
Definition: GridHelpers.cpp:26
void expandProscenium(real proscenium[4], const Polygon3r &polygon)
Definition: GridHelpers.h:166
bool insideProscenium(const real proscenium[4], const Polygon3r &polygon)
Definition: GridHelpers.h:126
inherits from class Rep
Definition: AppCanvas.cpp:32
static real distance2D(const Vec3r &point, const real origin[2])
static bool insideProscenium(const real proscenium[4], const Vec3r &point)
static bool crossesProscenium(real proscenium[4], FEdge *fe)
double real
Definition: Precision.h:26
INLINE Rall1d< T, V, S > hypot(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
Definition: rall1d.h:383
static double epsilon
#define min(a, b)
Definition: sort.c:51
float max
#define G(x, y, z)