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";
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
This defines a bounding convex hexahedron.
This funny bounding volume is an infinite plane that divides space into two regions: the part behind ...
This functions similarly to a LightAttrib.
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
This represents the set of clip planes and/or occluders that are definitely in effect for the current...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
void draw_bounding_volume(const BoundingVolume *vol, const TransformState *internal_transform) const
Draws an appropriate visualization of the indicated bounding volume.
SceneSetup * get_scene() const
Returns the SceneSetup object.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A base class for any number of different kinds of lenses, linear and otherwise.
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,...
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
LPoint3 get_pos() const
Retrieves the translation component of the transform.
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
PandaNode * node() const
Returns the referenced node of the path.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
get_num_on_occluders
Returns the number of occluders that are enabled by the effectute.
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.
get_num_vertices
Returns the number of vertices in the occluder polygon.
get_min_coverage
Returns the minimum screen coverage.
is_double_sided
Is this occluder double-sided.
get_vertex
Returns the nth vertex of the occluder polygon.
A node that contains a plane.
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
void ref() const
Explicitly increments the reference count.
get_ref_count
Returns the current reference count.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
This object holds the camera position, etc., and other general setup information for rendering a part...
const Lens * get_lens() const
Returns the particular Lens used for rendering.
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(CullPlanes) CullPlanes
Returns a pointer to an empty CullPlanes object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.