15 #include "cullPlanes.h" 16 #include "cullTraverser.h" 17 #include "cullTraverserData.h" 18 #include "clipPlaneAttrib.h" 19 #include "occluderEffect.h" 20 #include "boundingBox.h" 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);
105 CPT(TransformState) net_transform = NULL;
109 for (
int i = 0; i < num_on_planes; ++i) {
111 Planes::const_iterator pi = new_planes->_planes.
find(clip_plane);
112 if (pi == new_planes->_planes.end()) {
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;
139 for (
int i = 0; i < num_on_occluders; ++i) {
141 Occluders::const_iterator oi = new_planes->_occluders.
find(occluder);
142 if (oi == new_planes->_occluders.end()) {
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;
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);
333 BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
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 {
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 {
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.
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
A base class for any number of different kinds of lenses, linear and otherwise.
NodePath get_on_plane(int n) const
Returns the nth plane enabled by the attribute, sorted in render order.
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 is a three-component point in space (as opposed to a three-component vector, which represents a ...
This represents the set of clip planes and/or occluders that are definitely in effect for the current...
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 ...
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,1) in both dimensions, where (0,0) is the center of the lens and (-1,-1) is the lower-left corner.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
NodePath find(const string &path) const
Searches for a node below the referenced node that matches the indicated string.
int get_num_on_planes() const
Returns the number of planes that are enabled by the attribute.
This is a 4-by-4 transform matrix.
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
NodePath get_on_occluder(int n) const
Returns the nth occluder enabled by the effectute, sorted in render order.
int get_num_vertices() const
Returns the number of vertices in the occluder polygon.
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...
int get_ref_count() const
Returns the current reference count.
float length() const
Returns the length of the vector, by the Pythagorean theorem.
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
PandaNode * node() const
Returns the referenced node of the path.
SceneSetup * get_scene() const
Returns the SceneSetup object.
int get_num_on_occluders() const
Returns the number of occluders that are enabled by the effectute.
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
bool is_double_sided()
Is this occluder double-sided.
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...
PN_stdfloat get_far() const
Returns the position of the far plane (or cylinder, sphere, whatever).
A node that contains a plane.
This defines a bounding convex hexahedron.
const LPoint3 & get_vertex(int n) const
Returns the nth vertex of the occluder polygon.