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,6 +516,23 @@ 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);
if (num_geoms == 1) {
// If there's only one Geom, we don't need to bother culling each individual
// Geom bounding volume against the view frustum, since we've already
// 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++) { for (int i = 0; i < num_geoms; i++) {
CPT(Geom) geom = geoms.get_geom(i); CPT(Geom) geom = geoms.get_geom(i);
if (geom->is_empty()) { if (geom->is_empty()) {
@ -538,23 +555,12 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
continue; continue;
} }
// Cull the Geom bounding volume against the view frustum andor the cull
// planes. Don't bother unless we've got more than one Geom, since
// otherwise the bounding volume of the GeomNode is (probably) the same as
// that of the one Geom, and we've already culled against that.
if (num_geoms > 1) {
if (data._view_frustum != nullptr) {
// Cull the individual Geom against the view frustum. // Cull the individual Geom against the view frustum.
CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread); if (data._view_frustum != nullptr &&
const GeometricBoundingVolume *geom_gbv = !geom->is_in_view(data._view_frustum, current_thread)) {
geom_volume->as_geometric_bounding_volume();
int result = data._view_frustum->contains(geom_gbv);
if (result == BoundingVolume::IF_no_intersection) {
// Cull this Geom. // Cull this Geom.
continue; 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.
CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread); CPT(BoundingVolume) geom_volume = geom->get_bounds(current_thread);
@ -567,12 +573,12 @@ 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);
} }
}
} }
/** /**