30 if (empty ==
nullptr) {
45 xform(
const LMatrix4 &mat)
const {
53 for (Planes::iterator pi = new_planes->_planes.begin();
54 pi != new_planes->_planes.end();
56 if ((*pi).second->get_ref_count() != 1) {
57 (*pi).second = DCAST(
BoundingPlane, (*pi).second->make_copy());
59 (*pi).second->xform(mat);
62 for (Occluders::iterator oi = new_planes->_occluders.begin();
63 oi != new_planes->_occluders.end();
65 if ((*oi).second->get_ref_count() != 1) {
68 (*oi).second->xform(mat);
87 if (net_attrib ==
nullptr && node_effect ==
nullptr) {
100 if (net_attrib !=
nullptr) {
102 for (
int i = 0; i < num_on_planes; ++i) {
104 Planes::const_iterator pi = new_planes->_planes.find(clip_plane);
105 if (pi == new_planes->_planes.end()) {
109 if (net_transform ==
nullptr) {
110 net_transform = data->get_net_transform(trav);
115 net_transform->invert_compose(clip_plane.get_net_transform());
117 LPlane plane = plane_node->
get_plane() * new_transform->get_mat();
124 if (node_effect !=
nullptr) {
131 for (
int i = 0; i < num_on_occluders; ++i) {
133 Occluders::const_iterator oi = new_planes->_occluders.find(occluder);
134 if (oi == new_planes->_occluders.end()) {
143 if (center_transform ==
nullptr) {
144 if (net_transform ==
nullptr) {
145 net_transform = data->get_net_transform(trav);
148 center_transform = net_transform->invert_compose(scene->
get_cull_center().get_net_transform());
160 CPT(
TransformState) composed_transform = center_transform->compose(occluder_transform);
161 const LMatrix4 &composed_mat = composed_transform->get_mat();
163 ccp[0] = occluder_node->
get_vertex(0) * composed_mat;
164 ccp[1] = occluder_node->
get_vertex(1) * composed_mat;
165 ccp[2] = occluder_node->
get_vertex(2) * composed_mat;
166 ccp[3] = occluder_node->
get_vertex(3) * composed_mat;
168 LPoint3 ccp_min(min(min(ccp[0][0], ccp[1][0]),
169 min(ccp[2][0], ccp[3][0])),
170 min(min(ccp[0][1], ccp[1][1]),
171 min(ccp[2][1], ccp[3][1])),
172 min(min(ccp[0][2], ccp[1][2]),
173 min(ccp[2][2], ccp[3][2])));
174 LPoint3 ccp_max(max(max(ccp[0][0], ccp[1][0]),
175 max(ccp[2][0], ccp[3][0])),
176 max(max(ccp[0][1], ccp[1][1]),
177 max(ccp[2][1], ccp[3][1])),
178 max(max(ccp[0][2], ccp[1][2]),
179 max(ccp[2][2], ccp[3][2])));
183 if (data->_view_frustum !=
nullptr) {
184 int occluder_result = data->_view_frustum->contains(occluder_gbv);
185 if (occluder_result == BoundingVolume::IF_no_intersection) {
187 if (pgraph_cat.is_spam()) {
189 <<
"Ignoring occluder " << occluder <<
": outside view frustum.\n";
196 const LMatrix4 &occluder_mat_cull = occluder_transform->
get_mat();
197 LPoint3 points_near[4];
198 points_near[0] = occluder_node->
get_vertex(0) * occluder_mat_cull;
199 points_near[1] = occluder_node->
get_vertex(1) * occluder_mat_cull;
200 points_near[2] = occluder_node->
get_vertex(2) * occluder_mat_cull;
201 points_near[3] = occluder_node->
get_vertex(3) * occluder_mat_cull;
202 LPlane plane(points_near[0], points_near[1], points_near[2]);
204 if (plane.get_normal().dot(LVector3::forward()) >= 0.0) {
206 std::swap(points_near[0], points_near[3]);
207 std::swap(points_near[1], points_near[2]);
208 plane = LPlane(points_near[0], points_near[1], points_near[2]);
211 if (pgraph_cat.is_spam()) {
213 <<
"Ignoring occluder " << occluder <<
": wrong direction.\n";
221 lens->
project(points_near[0], coords[0]);
222 lens->
project(points_near[1], coords[1]);
223 lens->
project(points_near[2], coords[2]);
224 lens->
project(points_near[3], coords[3]);
225 coords[0][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[0][0]));
226 coords[0][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[0][1]));
227 coords[1][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[1][0]));
228 coords[1][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[1][1]));
229 coords[2][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[2][0]));
230 coords[2][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[2][1]));
231 coords[3][0] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[3][0]));
232 coords[3][1] = max((PN_stdfloat)-1.0, min((PN_stdfloat)1.0, coords[3][1]));
233 PN_stdfloat coverage = ((coords[0] - coords[1]).cross(coords[0] - coords[2]).length()
234 + (coords[3] - coords[1]).cross(coords[3] - coords[2]).length())
236 if (coverage < occluder_node->get_min_coverage()) {
238 if (pgraph_cat.is_spam()) {
240 <<
"Ignoring occluder " << occluder <<
": coverage less than minimum.\n";
248 bool is_enclosed =
false;
249 Occluders::const_iterator oi;
250 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
251 int occluder_result = (*oi).second->contains(occluder_gbv);
252 if ((occluder_result & BoundingVolume::IF_all) != 0) {
259 if (pgraph_cat.is_spam()) {
261 <<
"Ignoring occluder " << occluder <<
": behind another.\n";
269 const LMatrix4 &occluder_mat = occluder.get_net_transform()->
get_mat();
270 points_near[0] = occluder_node->
get_vertex(0) * occluder_mat;
271 points_near[1] = occluder_node->
get_vertex(1) * occluder_mat;
272 points_near[2] = occluder_node->
get_vertex(2) * occluder_mat;
273 points_near[3] = occluder_node->
get_vertex(3) * occluder_mat;
279 LPoint3 points_far[4];
280 points_far[0] = normalize(points_near[0] - center) * far_clip + points_near[0];
281 points_far[1] = normalize(points_near[1] - center) * far_clip + points_near[1];
282 points_far[2] = normalize(points_near[2] - center) * far_clip + points_near[2];
283 points_far[3] = normalize(points_near[3] - center) * far_clip + points_near[3];
289 points_near[1], points_near[2], points_near[3], points_near[0]);
291 new_planes->_occluders[occluder] = frustum;
293 if (show_occluder_volumes) {
295 nassertr(net_transform !=
nullptr, new_planes);
319 BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
324 if (!state->get_attrib(orig_cpa)) {
329 planes->_occluders = _occluders;
335 Planes::const_iterator pi;
336 for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
337 int plane_result = (*pi).second->contains(node_gbv);
338 if (plane_result == BoundingVolume::IF_no_intersection) {
342 result = plane_result;
344 }
else if ((plane_result & BoundingVolume::IF_all) != 0) {
347 new_planes = new_planes->remove_plane((*pi).first);
348 nassertr(new_planes !=
this, new_planes);
349 new_cpa = DCAST(
ClipPlaneAttrib, new_cpa->remove_on_plane((*pi).first));
352 result &= plane_result;
355 if (new_cpa != orig_cpa) {
356 if (new_cpa->is_identity()) {
357 state = state->remove_attrib(ClipPlaneAttrib::get_class_slot());
359 state = state->add_attrib(new_cpa);
364 Occluders::const_iterator oi;
365 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
366 int occluder_result = (*oi).second->contains(node_gbv);
367 if (occluder_result == BoundingVolume::IF_no_intersection) {
374 occluder_result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
375 new_planes = new_planes->remove_occluder((*oi).first);
376 nassertr(new_planes !=
this, new_planes);
378 }
else if ((occluder_result & BoundingVolume::IF_all) != 0) {
381 result = BoundingVolume::IF_no_intersection;
385 result &= occluder_result;
396 remove_plane(
const NodePath &clip_plane)
const {
404 Planes::iterator pi = new_planes->_planes.find(clip_plane);
405 nassertr(pi != new_planes->_planes.end(), new_planes);
406 new_planes->_planes.erase(pi);
416 remove_occluder(
const NodePath &occluder)
const {
424 Occluders::iterator pi = new_planes->_occluders.find(occluder);
425 nassertr(pi != new_planes->_occluders.end(), new_planes);
426 new_planes->_occluders.erase(pi);
435 write(std::ostream &out)
const {
436 out <<
"CullPlanes (" << _planes.size() <<
" planes and " 437 << _occluders.size() <<
" occluders):\n";
438 Planes::const_iterator pi;
439 for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
440 out <<
" " << (*pi).first <<
" : " << *(*pi).second <<
"\n";
443 Occluders::const_iterator oi;
444 for (oi = _occluders.begin(); oi != _occluders.end(); ++oi) {
445 out <<
" " << (*oi).first <<
" : " << *(*oi).second <<
"\n";
get_num_vertices
Returns the number of vertices in the occluder polygon.
get_ref_count
Returns the current reference count.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for any number of different kinds of lenses, linear and otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_vertex
Returns the nth vertex of the occluder polygon.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
const Lens * get_lens() const
Returns the particular Lens used for rendering.
This functions similarly to a LightAttrib.
This represents the set of clip planes and/or occluders that are definitely in effect for the current...
get_on_occluder
Returns the nth occluder enabled by the effectute, sorted in render order.
A node in the scene graph that can hold an occluder polygon, which must be a rectangle.
This funny bounding volume is an infinite plane that divides space into two regions: the part behind ...
bool project(const LPoint3 &point3d, LPoint3 &point2d) const
Given a 3-d point in space, determine the 2-d point this maps to, in the range (-1,...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_on_occluders
Returns the number of occluders that are enabled by the effectute.
LPoint3 get_pos() const
Retrieves the translation component of the transform.
void ref() const
Explicitly increments the reference count.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
is_double_sided
Is this occluder double-sided.
PandaNode * node() const
Returns the referenced node of the path.
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
SceneSetup * get_scene() const
Returns the SceneSetup object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_min_coverage
Returns the minimum screen coverage.
CPT(CullPlanes) CullPlanes
Returns a pointer to an empty CullPlanes object.
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void draw_bounding_volume(const BoundingVolume *vol, const TransformState *internal_transform) const
Draws an appropriate visualization of the indicated bounding volume.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
This object holds the camera position, etc., and other general setup information for rendering a part...
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,...
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
A node that contains a plane.
This defines a bounding convex hexahedron.