15 #include "cullPlanes.h"
16 #include "cullTraverser.h"
17 #include "cullTraverserData.h"
18 #include "clipPlaneAttrib.h"
19 #include "occluderEffect.h"
20 #include "boundingBox.h"
50 if (get_ref_count() == 1) {
56 for (Planes::iterator pi = new_planes->_planes.begin();
57 pi != new_planes->_planes.end();
59 if ((*pi).second->get_ref_count() != 1) {
60 (*pi).second = DCAST(
BoundingPlane, (*pi).second->make_copy());
62 (*pi).second->xform(mat);
65 for (Occluders::iterator oi = new_planes->_occluders.begin();
66 oi != new_planes->_occluders.end();
68 if ((*oi).second->get_ref_count() != 1) {
71 (*oi).second->xform(mat);
99 if (get_ref_count() == 1) {
105 CPT(TransformState) net_transform = NULL;
108 int num_on_planes = net_attrib->get_num_on_planes();
109 for (
int i = 0; i < num_on_planes; ++i) {
110 NodePath clip_plane = net_attrib->get_on_plane(i);
111 Planes::const_iterator pi = new_planes->_planes.find(clip_plane);
112 if (pi == new_planes->_planes.end()) {
113 if (!off_attrib->has_off_plane(clip_plane)) {
116 if (net_transform == (TransformState *)NULL) {
117 net_transform = data->get_net_transform(trav);
121 CPT(TransformState) new_transform =
122 net_transform->invert_compose(clip_plane.get_net_transform());
124 LPlane plane = plane_node->get_plane() * new_transform->get_mat();
132 CPT(TransformState) center_transform = NULL;
136 const
Lens *lens = scene->get_lens();
138 int num_on_occluders = node_effect->get_num_on_occluders();
139 for (
int i = 0; i < num_on_occluders; ++i) {
140 NodePath occluder = node_effect->get_on_occluder(i);
141 Occluders::const_iterator oi = new_planes->_occluders.find(occluder);
142 if (oi == new_planes->_occluders.end()) {
147 CPT(TransformState) occluder_transform = occluder.get_transform(scene->get_cull_center());
151 if (center_transform == (TransformState *)NULL) {
152 if (net_transform == (TransformState *)NULL) {
153 net_transform = data->get_net_transform(trav);
156 center_transform = net_transform->invert_compose(scene->get_cull_center().get_net_transform());
169 CPT(TransformState) composed_transform = center_transform->compose(occluder_transform);
170 const
LMatrix4 &composed_mat = composed_transform->get_mat();
172 ccp[0] = occluder_node->get_vertex(0) * composed_mat;
173 ccp[1] = occluder_node->get_vertex(1) * composed_mat;
174 ccp[2] = occluder_node->get_vertex(2) * composed_mat;
175 ccp[3] = occluder_node->get_vertex(3) * composed_mat;
177 LPoint3 ccp_min(min(min(ccp[0][0], ccp[1][0]),
178 min(ccp[2][0], ccp[3][0])),
179 min(min(ccp[0][1], ccp[1][1]),
180 min(ccp[2][1], ccp[3][1])),
181 min(min(ccp[0][2], ccp[1][2]),
182 min(ccp[2][2], ccp[3][2])));
183 LPoint3 ccp_max(max(max(ccp[0][0], ccp[1][0]),
184 max(ccp[2][0], ccp[3][0])),
185 max(max(ccp[0][1], ccp[1][1]),
186 max(ccp[2][1], ccp[3][1])),
187 max(max(ccp[0][2], ccp[1][2]),
188 max(ccp[2][2], ccp[3][2])));
193 int occluder_result = data->_view_frustum->
contains(occluder_gbv);
194 if (occluder_result == BoundingVolume::IF_no_intersection) {
196 if (pgraph_cat.is_spam()) {
198 <<
"Ignoring occluder " << occluder <<
": outside view frustum.\n";
205 const LMatrix4 &occluder_mat_cull = occluder_transform->get_mat();
207 points_near[0] = occluder_node->
get_vertex(0) * occluder_mat_cull;
208 points_near[1] = occluder_node->
get_vertex(1) * occluder_mat_cull;
209 points_near[2] = occluder_node->
get_vertex(2) * occluder_mat_cull;
210 points_near[3] = occluder_node->
get_vertex(3) * occluder_mat_cull;
211 LPlane plane(points_near[0], points_near[1], points_near[2]);
215 swap(points_near[0], points_near[3]);
216 swap(points_near[1], points_near[2]);
217 plane = LPlane(points_near[0], points_near[1], points_near[2]);
220 if (pgraph_cat.is_spam()) {
222 <<
"Ignoring occluder " << occluder <<
": wrong direction.\n";
230 lens->
project(points_near[0], coords[0]);
231 lens->
project(points_near[1], coords[1]);
232 lens->
project(points_near[2], coords[2]);
233 lens->
project(points_near[3], coords[3]);
234 coords[0][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[0][0]));
235 coords[0][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[0][1]));
236 coords[1][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[1][0]));
237 coords[1][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[1][1]));
238 coords[2][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[2][0]));
239 coords[2][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[2][1]));
240 coords[3][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[3][0]));
241 coords[3][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[3][1]));
242 PN_stdfloat coverage = ((coords[0] - coords[1]).cross(coords[0] - coords[2]).
length()
243 + (coords[3] - coords[1]).cross(coords[3] - coords[2]).
length())
245 if (coverage < occluder_node->get_min_coverage()) {
247 if (pgraph_cat.is_spam()) {
249 <<
"Ignoring occluder " << occluder <<
": coverage less than minimum.\n";
257 bool is_enclosed =
false;
258 Occluders::const_iterator oi;
259 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
260 int occluder_result = (*oi).second->contains(occluder_gbv);
261 if ((occluder_result & BoundingVolume::IF_all) != 0) {
269 if (pgraph_cat.is_spam()) {
271 <<
"Ignoring occluder " << occluder <<
": behind another.\n";
279 const LMatrix4 &occluder_mat = occluder.get_net_transform()->
get_mat();
280 points_near[0] = occluder_node->
get_vertex(0) * occluder_mat;
281 points_near[1] = occluder_node->
get_vertex(1) * occluder_mat;
282 points_near[2] = occluder_node->
get_vertex(2) * occluder_mat;
283 points_near[3] = occluder_node->
get_vertex(3) * occluder_mat;
287 LPoint3 center = scene->get_cull_center().get_net_transform()->get_pos();
288 PN_stdfloat far_clip = scene->get_lens()->get_far() * 2.0;
290 points_far[0] = normalize(points_near[0] - center) * far_clip + points_near[0];
291 points_far[1] = normalize(points_near[1] - center) * far_clip + points_near[1];
292 points_far[2] = normalize(points_near[2] - center) * far_clip + points_near[2];
293 points_far[3] = normalize(points_near[3] - center) * far_clip + points_near[3];
299 points_near[1], points_near[2], points_near[3], points_near[0]);
301 new_planes->_occluders[occluder] = frustum;
303 if (show_occluder_volumes) {
305 nassertr(net_transform != NULL, new_planes);
306 trav->draw_bounding_volume(frustum, data->get_internal_transform(trav));
333 BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
339 if (orig_cpa == (ClipPlaneAttrib *)NULL) {
344 planes->_occluders = _occluders;
350 Planes::const_iterator pi;
351 for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
352 int plane_result = (*pi).second->contains(node_gbv);
353 if (plane_result == BoundingVolume::IF_no_intersection) {
357 result = plane_result;
359 }
else if ((plane_result & BoundingVolume::IF_all) != 0) {
363 new_planes = new_planes->remove_plane((*pi).first);
364 nassertr(new_planes !=
this, new_planes);
365 new_cpa = DCAST(
ClipPlaneAttrib, new_cpa->remove_on_plane((*pi).first));
368 result &= plane_result;
371 if (new_cpa != orig_cpa) {
372 if (new_cpa->is_identity()) {
373 state = state->remove_attrib(ClipPlaneAttrib::get_class_slot());
375 state = state->add_attrib(new_cpa);
380 Occluders::const_iterator oi;
381 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
382 int occluder_result = (*oi).second->contains(node_gbv);
383 if (occluder_result == BoundingVolume::IF_no_intersection) {
391 occluder_result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
392 new_planes = new_planes->remove_occluder((*oi).first);
393 nassertr(new_planes !=
this, new_planes);
395 }
else if ((occluder_result & BoundingVolume::IF_all) != 0) {
399 result = BoundingVolume::IF_no_intersection;
403 result &= occluder_result;
417 remove_plane(const
NodePath &clip_plane)
const {
419 if (get_ref_count() == 1) {
425 Planes::iterator pi = new_planes->_planes.find(clip_plane);
426 nassertr(pi != new_planes->_planes.end(), new_planes);
427 new_planes->_planes.erase(pi);
440 remove_occluder(const
NodePath &occluder)
const {
442 if (get_ref_count() == 1) {
448 Occluders::iterator pi = new_planes->_occluders.find(occluder);
449 nassertr(pi != new_planes->_occluders.end(), new_planes);
450 new_planes->_occluders.erase(pi);
461 write(ostream &out)
const {
462 out <<
"CullPlanes (" << _planes.size() <<
" planes and "
463 << _occluders.size() <<
" occluders):\n";
464 Planes::const_iterator pi;
465 for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
466 out <<
" " << (*pi).first <<
" : " << *(*pi).second <<
"\n";
469 Occluders::const_iterator oi;
470 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
471 out <<
" " << (*oi).first <<
" : " << *(*oi).second <<
"\n";
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
A base class for any number of different kinds of lenses, linear and otherwise.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PandaNode * node() const
Returns the referenced node of the path.
This functions similarly to a LightAttrib.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
int contains(const GeometricBoundingVolume *vol) const
Returns the appropriate set of IntersectionFlags to indicate the amount of intersection with the indi...
This represents the set of clip planes and/or occluders that are definitely in effect for the current...
LPoint3f project(const LVecBase3f &onto) const
Returns a new vector representing the projection of this vector onto another one. ...
int get_num_vertices() const
Returns the number of vertices in the occluder polygon.
A node in the scene graph that can hold an occluder polygon, which must be a rectangle.
static LVector3f forward(CoordinateSystem cs=CS_default)
Returns the forward vector for the given coordinate system.
PN_stdfloat get_min_coverage()
Returns the minimum screen coverage.
This funny bounding volume is an infinite plane that divides space into two regions: the part behind ...
float length() const
Returns the length of the vector, by the Pythagorean theorem.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
This is a 4-by-4 transform matrix.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
const LPoint3 & get_vertex(int n) const
Returns the nth vertex of the occluder polygon.
void ref() const
Explicitly increments the reference count.
bool is_double_sided()
Is this occluder double-sided.
This object holds the camera position, etc., and other general setup information for rendering a part...
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
A node that contains a plane.
This defines a bounding convex hexahedron.