pgraph: Optimization for GeomNode::add_for_draw()

This commit is contained in:
rdb 2020-12-12 15:08:32 +01:00
parent 251d73a47b
commit 2b29c757d9
3 changed files with 69 additions and 38 deletions

View File

@ -1294,6 +1294,29 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
return gc; return gc;
} }
/**
* Returns true if the Geom is within the given view frustum.
*/
bool Geom::
is_in_view(const BoundingVolume *view_frustum, Thread *current_thread) const {
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_user_bounds != nullptr) {
const GeometricBoundingVolume *gbv = cdata->_user_bounds->as_geometric_bounding_volume();
return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
}
else if (!cdata->_internal_bounds_stale) {
const GeometricBoundingVolume *gbv = cdata->_internal_bounds->as_geometric_bounding_volume();
return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
}
else {
CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
compute_internal_bounds(cdataw, current_thread);
const GeometricBoundingVolume *gbv = cdataw->_internal_bounds->as_geometric_bounding_volume();
return view_frustum->contains(gbv) != BoundingVolume::IF_no_intersection;
}
}
/** /**
* Actually draws the Geom with the indicated GSG, using the indicated vertex * Actually draws the Geom with the indicated GSG, using the indicated vertex
* data (which might have been pre-munged to support the GSG's needs). * data (which might have been pre-munged to support the GSG's needs).

View File

@ -157,6 +157,8 @@ PUBLISHED:
GraphicsStateGuardianBase *gsg); GraphicsStateGuardianBase *gsg);
public: public:
bool is_in_view(const BoundingVolume *view_frustum, Thread *current_thread) const;
bool draw(GraphicsStateGuardianBase *gsg, bool draw(GraphicsStateGuardianBase *gsg,
const GeomVertexData *vertex_data, size_t num_instances, const GeomVertexData *vertex_data, size_t num_instances,
bool force, Thread *current_thread) const; bool force, Thread *current_thread) const;

View File

@ -516,44 +516,50 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
trav->_geoms_pcollector.add_level(num_geoms); trav->_geoms_pcollector.add_level(num_geoms);
CPT(TransformState) internal_transform = data.get_internal_transform(trav); CPT(TransformState) internal_transform = data.get_internal_transform(trav);
for (int i = 0; i < num_geoms; i++) { if (num_geoms == 1) {
CPT(Geom) geom = geoms.get_geom(i); // If there's only one Geom, we don't need to bother culling each individual
if (geom->is_empty()) { // Geom bounding volume against the view frustum, since we've already
continue; // checked the one on the GeomNode itself.
CPT(Geom) geom = geoms.get_geom(0);
if (!geom->is_empty()) {
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(0));
if (!state->has_cull_callback() || state->cull_callback(trav, data)) {
CullableObject *object =
new CullableObject(std::move(geom), std::move(state), std::move(internal_transform));
object->_instances = data._instances;
trav->get_cull_handler()->record_object(object, trav);
}
} }
}
else {
// More than one Geom.
for (int i = 0; i < num_geoms; i++) {
CPT(Geom) geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
}
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
if (state->has_cull_callback() && !state->cull_callback(trav, data)) { if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
// Cull. // Cull.
continue; continue;
} }
if (data._instances != nullptr) { if (data._instances != nullptr) {
// Draw each individual instance. We don't bother culling each // Draw each individual instance. We don't bother culling each
// individual Geom for each instance; that is probably way too slow. // individual Geom for each instance; that is probably way too slow.
CullableObject *object = CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform); new CullableObject(std::move(geom), std::move(state), internal_transform);
object->_instances = data._instances; object->_instances = data._instances;
trav->get_cull_handler()->record_object(object, trav); trav->get_cull_handler()->record_object(object, trav);
continue; continue;
} }
// Cull the Geom bounding volume against the view frustum andor the cull // Cull the individual Geom against the view frustum.
// planes. Don't bother unless we've got more than one Geom, since if (data._view_frustum != nullptr &&
// otherwise the bounding volume of the GeomNode is (probably) the same as !geom->is_in_view(data._view_frustum, current_thread)) {
// that of the one Geom, and we've already culled against that. // Cull this Geom.
if (num_geoms > 1) { continue;
if (data._view_frustum != nullptr) {
// Cull the individual Geom against the view frustum.
CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread);
const GeometricBoundingVolume *geom_gbv =
geom_volume->as_geometric_bounding_volume();
int result = data._view_frustum->contains(geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull this Geom.
continue;
}
} }
if (!data._cull_planes->is_empty()) { if (!data._cull_planes->is_empty()) {
// Also cull the Geom against the cull planes. // Also cull the Geom against the cull planes.
@ -567,11 +573,11 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
continue; continue;
} }
} }
}
CullableObject *object = CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform); new CullableObject(std::move(geom), std::move(state), internal_transform);
trav->get_cull_handler()->record_object(object, trav); trav->get_cull_handler()->record_object(object, trav);
}
} }
} }