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;
}
/**
* 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
* data (which might have been pre-munged to support the GSG's needs).

View File

@ -157,6 +157,8 @@ PUBLISHED:
GraphicsStateGuardianBase *gsg);
public:
bool is_in_view(const BoundingVolume *view_frustum, Thread *current_thread) const;
bool draw(GraphicsStateGuardianBase *gsg,
const GeomVertexData *vertex_data, size_t num_instances,
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);
CPT(TransformState) internal_transform = data.get_internal_transform(trav);
for (int i = 0; i < num_geoms; i++) {
CPT(Geom) geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
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++) {
CPT(Geom) geom = geoms.get_geom(i);
if (geom->is_empty()) {
continue;
}
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
// Cull.
continue;
}
CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
if (state->has_cull_callback() && !state->cull_callback(trav, data)) {
// Cull.
continue;
}
if (data._instances != nullptr) {
// Draw each individual instance. We don't bother culling each
// individual Geom for each instance; that is probably way too slow.
CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform);
object->_instances = data._instances;
trav->get_cull_handler()->record_object(object, trav);
continue;
}
if (data._instances != nullptr) {
// Draw each individual instance. We don't bother culling each
// individual Geom for each instance; that is probably way too slow.
CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform);
object->_instances = data._instances;
trav->get_cull_handler()->record_object(object, trav);
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.
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;
}
// Cull the individual Geom against the view frustum.
if (data._view_frustum != nullptr &&
!geom->is_in_view(data._view_frustum, current_thread)) {
// Cull this Geom.
continue;
}
if (!data._cull_planes->is_empty()) {
// Also cull the Geom against the cull planes.
@ -567,11 +573,11 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
continue;
}
}
}
CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform);
trav->get_cull_handler()->record_object(object, trav);
CullableObject *object =
new CullableObject(std::move(geom), std::move(state), internal_transform);
trav->get_cull_handler()->record_object(object, trav);
}
}
}