Blender V4.3
CulledOccluderSource.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
11
13
14#include "BLI_sys_types.h"
15
16#include "BKE_global.hh"
17
18namespace Freestyle {
19
20CulledOccluderSource::CulledOccluderSource(const GridHelpers::Transform &t,
21 WingedEdge &we,
22 ViewMap &viewMap,
23 bool extensiveFEdgeSearch)
24 : OccluderSource(t, we), rejected(0), gridSpaceOccluderProsceniumInitialized(false)
25{
26 cullViewEdges(viewMap, extensiveFEdgeSearch);
27
28 // If we have not found any visible FEdges during our cull, then there is nothing to iterate
29 // over. Short-circuit everything.
30 valid = gridSpaceOccluderProsceniumInitialized;
31
32 if (valid && !testCurrent()) {
33 next();
34 }
35}
36
37bool CulledOccluderSource::testCurrent()
38{
39 if (valid) {
40 // The test for gridSpaceOccluderProsceniumInitialized should not be necessary
41 return gridSpaceOccluderProsceniumInitialized &&
42 GridHelpers::insideProscenium(gridSpaceOccluderProscenium, cachedPolygon);
43 }
44 return false;
45}
46
48{
49 while (OccluderSource::next()) {
50 if (testCurrent()) {
51 ++rejected;
52 return true;
53 }
54 }
55 if (G.debug & G_DEBUG_FREESTYLE) {
56 std::cout << "Finished generating occluders. Rejected " << rejected << " faces." << std::endl;
57 }
58 return false;
59}
60
62{
63 for (uint i = 0; i < 4; ++i) {
64 proscenium[i] = gridSpaceOccluderProscenium[i];
65 }
66}
67
68static inline real distance2D(const Vec3r &point, const real origin[2])
69{
70 return ::hypot((point[0] - origin[0]), (point[1] - origin[1]));
71}
72
73static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
74{
75 Vec2r min(proscenium[0], proscenium[2]);
76 Vec2r max(proscenium[1], proscenium[3]);
79
81}
82
83static inline bool insideProscenium(const real proscenium[4], const Vec3r &point)
84{
85 return !(point[0] < proscenium[0] || point[0] > proscenium[1] || point[1] < proscenium[2] ||
86 point[1] > proscenium[3]);
87}
88
89void CulledOccluderSource::cullViewEdges(ViewMap &viewMap, bool extensiveFEdgeSearch)
90{
91 // Cull view edges by marking them as non-displayable.
92 // This avoids the complications of trying to delete edges from the ViewMap.
93
94 // Non-displayable view edges will be skipped over during visibility calculation.
95
96 // View edges will be culled according to their position w.r.t. the viewport proscenium (viewport
97 // + 5% border, or some such).
98
99 // Get proscenium boundary for culling
100 real viewProscenium[4];
102 real prosceniumOrigin[2];
103 prosceniumOrigin[0] = (viewProscenium[1] - viewProscenium[0]) / 2.0;
104 prosceniumOrigin[1] = (viewProscenium[3] - viewProscenium[2]) / 2.0;
105 if (G.debug & G_DEBUG_FREESTYLE) {
106 cout << "Proscenium culling:" << endl;
107 cout << "Proscenium: [" << viewProscenium[0] << ", " << viewProscenium[1] << ", "
108 << viewProscenium[2] << ", " << viewProscenium[3] << "]" << endl;
109 cout << "Origin: [" << prosceniumOrigin[0] << ", " << prosceniumOrigin[1] << "]" << endl;
110 }
111
112 // A separate occluder proscenium will also be maintained, starting out the same as the viewport
113 // proscenium, and expanding as necessary so that it encompasses the center point of at least one
114 // feature edge in each retained view edge. The occluder proscenium will be used later to cull
115 // occluding triangles before they are inserted into the Grid. The occluder proscenium starts out
116 // the same size as the view proscenium
117 GridHelpers::getDefaultViewProscenium(occluderProscenium);
118
119 // XXX Freestyle is inconsistent in its use of ViewMap::viewedges_container and
120 // vector<ViewEdge*>::iterator. Probably all occurrences of vector<ViewEdge*>::iterator should be
121 // replaced ViewMap::viewedges_container throughout the code. For each view edge
122 ViewMap::viewedges_container::iterator ve, veend;
123
124 for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
125 // Overview:
126 // Search for a visible feature edge
127 // If none: mark view edge as non-displayable
128 // Otherwise:
129 // Find a feature edge with center point inside occluder proscenium.
130 // If none exists, find the feature edge with center point closest to viewport origin.
131 // Expand occluder proscenium to enclose center point.
132
133 // For each feature edge, while bestOccluderTarget not found and view edge not visible
134 bool bestOccluderTargetFound = false;
135 FEdge *bestOccluderTarget = nullptr;
136 real bestOccluderDistance = 0.0;
137 FEdge *festart = (*ve)->fedgeA();
138 FEdge *fe = festart;
139 // All ViewEdges start culled
140 (*ve)->setIsInImage(false);
141
142 // For simple visibility calculation: mark a feature edge that is known to have a center point
143 // inside the occluder proscenium. Cull all other feature edges.
144 do {
145 // All FEdges start culled
146 fe->setIsInImage(false);
147
148 // Look for the visible edge that can most easily be included in the occluder proscenium.
149 if (!bestOccluderTargetFound) {
150 // If center point is inside occluder proscenium,
151 if (insideProscenium(occluderProscenium, fe->center2d())) {
152 // Use this feature edge for visibility deterimination
153 fe->setIsInImage(true);
154 expandGridSpaceOccluderProscenium(fe);
155 // Mark bestOccluderTarget as found
156 bestOccluderTargetFound = true;
157 bestOccluderTarget = fe;
158 }
159 else {
160 real d = distance2D(fe->center2d(), prosceniumOrigin);
161 // If center point is closer to viewport origin than current target
162 if (bestOccluderTarget == nullptr || d < bestOccluderDistance) {
163 // Then store as bestOccluderTarget
164 bestOccluderDistance = d;
165 bestOccluderTarget = fe;
166 }
167 }
168 }
169
170 // If feature edge crosses the view proscenium
171 if (!(*ve)->isInImage() && crossesProscenium(viewProscenium, fe)) {
172 // Then the view edge will be included in the image
173 (*ve)->setIsInImage(true);
174 }
175 fe = fe->nextEdge();
176 } while (fe != nullptr && fe != festart && !(bestOccluderTargetFound && (*ve)->isInImage()));
177
178 // Either we have run out of FEdges, or we already have the one edge we need to determine
179 // visibility Cull all remaining edges.
180 while (!ELEM(fe, nullptr, festart)) {
181 fe->setIsInImage(false);
182 fe = fe->nextEdge();
183 }
184
185 // If bestOccluderTarget was not found inside the occluder proscenium,
186 // we need to expand the occluder proscenium to include it.
187 if ((*ve)->isInImage() && bestOccluderTarget != nullptr && !bestOccluderTargetFound) {
188 // Expand occluder proscenium to enclose bestOccluderTarget
189 Vec3r point = bestOccluderTarget->center2d();
190 if (point[0] < occluderProscenium[0]) {
191 occluderProscenium[0] = point[0];
192 }
193 else if (point[0] > occluderProscenium[1]) {
194 occluderProscenium[1] = point[0];
195 }
196 if (point[1] < occluderProscenium[2]) {
197 occluderProscenium[2] = point[1];
198 }
199 else if (point[1] > occluderProscenium[3]) {
200 occluderProscenium[3] = point[1];
201 }
202 // Use bestOccluderTarget for visibility determination
203 bestOccluderTarget->setIsInImage(true);
204 }
205 }
206
207 // We are done calculating the occluder proscenium.
208 // Expand the occluder proscenium by an epsilon to avoid rounding errors.
209 const real epsilon = 1.0e-6;
210 occluderProscenium[0] -= epsilon;
211 occluderProscenium[1] += epsilon;
212 occluderProscenium[2] -= epsilon;
213 occluderProscenium[3] += epsilon;
214
215 // For "Normal" or "Fast" style visibility computation only:
216
217 // For more detailed visibility calculation, make a second pass through the view map, marking all
218 // feature edges with center points inside the final occluder proscenium. All of these feature
219 // edges can be considered during visibility calculation.
220
221 // So far we have only found one FEdge per ViewEdge. The "Normal" and "Fast" styles of visibility
222 // computation want to consider many FEdges for each ViewEdge. Here we re-scan the view map to
223 // find any usable FEdges that we skipped on the first pass, or that have become usable because
224 // the occluder proscenium has been expanded since the edge was visited on the first pass.
225 if (extensiveFEdgeSearch) {
226 // For each view edge,
227 for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
228 if (!(*ve)->isInImage()) {
229 continue;
230 }
231 // For each feature edge,
232 FEdge *festart = (*ve)->fedgeA();
233 FEdge *fe = festart;
234 do {
235 // If not (already) visible and center point inside occluder proscenium,
236 if (!fe->isInImage() && insideProscenium(occluderProscenium, fe->center2d())) {
237 // Use the feature edge for visibility determination
238 fe->setIsInImage(true);
239 expandGridSpaceOccluderProscenium(fe);
240 }
241 fe = fe->nextEdge();
242 } while (!ELEM(fe, nullptr, festart));
243 }
244 }
245
246 // Up until now, all calculations have been done in camera space.
247 // However, the occluder source's iteration and the grid that consumes the occluders both work in
248 // gridspace, so we need a version of the occluder proscenium in gridspace. Set the gridspace
249 // occlude proscenium
250}
251
252void CulledOccluderSource::expandGridSpaceOccluderProscenium(FEdge *fe)
253{
254 if (gridSpaceOccluderProsceniumInitialized) {
255 GridHelpers::expandProscenium(gridSpaceOccluderProscenium, transform(fe->center3d()));
256 }
257 else {
258 const Vec3r &point = transform(fe->center3d());
259 gridSpaceOccluderProscenium[0] = gridSpaceOccluderProscenium[1] = point[0];
260 gridSpaceOccluderProscenium[2] = gridSpaceOccluderProscenium[3] = point[1];
261 gridSpaceOccluderProsceniumInitialized = true;
262 }
263}
264
265} /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
unsigned int uint
#define ELEM(...)
Class to define a cell grid surrounding the projected image of a scene.
Class to define a cell grid surrounding the projected image of a scene.
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
#define A
void getOccluderProscenium(real proscenium[4])
void cullViewEdges(ViewMap &viewMap, bool extensiveFEdgeSearch)
FEdge * nextEdge()
Definition Silhouette.h:623
SVertex * vertexA()
Definition Silhouette.h:597
bool isInImage() const
Definition Silhouette.h:711
SVertex * vertexB()
Definition Silhouette.h:603
void setIsInImage(bool iFlag)
Definition Silhouette.h:811
const GridHelpers::Transform & transform
virtual real getProjectedY() const
Definition Silhouette.h:98
virtual real getProjectedX() const
Definition Silhouette.h:92
viewedges_container & ViewEdges()
Definition ViewMap.h:104
#define B
#define G(x, y, z)
bool intersect2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B)
Definition GeomUtils.cpp:19
VecMat::Vec2< real > Vec2r
Definition Geom.h:24
VecMat::Vec3< real > Vec3r
Definition Geom.h:30
void getDefaultViewProscenium(real viewProscenium[4])
void expandProscenium(real proscenium[4], const Polygon3r &polygon)
bool insideProscenium(const real proscenium[4], const Polygon3r &polygon)
inherits from class Rep
Definition AppCanvas.cpp:20
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:14
#define min(a, b)
Definition sort.c:32
float max