87 if (net_attrib ==
nullptr && node_effect ==
nullptr) {
91 PT(CullPlanes) new_planes;
93 new_planes = (CullPlanes *)
this;
95 new_planes =
new CullPlanes(*
this);
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;
277 LPoint3 center = scene->
get_cull_center().get_net_transform()->get_pos();
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;
321 CPT(CullPlanes) new_planes =
this;
324 if (!state->get_attrib(orig_cpa)) {
328 CullPlanes *planes =
new CullPlanes;
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);
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());
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;