Portals - Fix CSG updates on room conversion

Due to a quirk in CSG Shapes, updating is usually deferred to the next frame. This is problematic as we need to read back the geometry on the first frame when converting levels.

This PR adds a function to CSGShape to force immediate updating (if dirty), and calls it during room conversion.
This commit is contained in:
lawnjelly 2021-07-29 12:41:23 +01:00
parent 5d4352fad4
commit e06cd3042f
3 changed files with 18 additions and 0 deletions

View file

@ -576,6 +576,17 @@ void CSGShape::_validate_property(PropertyInfo &property) const {
} }
} }
// Calling _make_dirty() normally calls a deferred _update_shape.
// This is problematic if we need to read the geometry immediately.
// This function provides a means to make sure the shape is updated
// immediately. It should only be used where necessary to prevent
// updating CSGs multiple times per frame. Use _make_dirty in preference.
void CSGShape::force_update_shape() {
if (dirty) {
_update_shape();
}
}
Array CSGShape::get_meshes() const { Array CSGShape::get_meshes() const {
if (root_mesh.is_valid()) { if (root_mesh.is_valid()) {
Array arr; Array arr;

View file

@ -119,6 +119,8 @@ protected:
public: public:
Array get_meshes() const; Array get_meshes() const;
void force_update_shape();
void set_operation(Operation p_operation); void set_operation(Operation p_operation);
Operation get_operation() const; Operation get_operation() const;

View file

@ -1596,6 +1596,11 @@ bool RoomManager::_bound_findpoints_geom_instance(GeometryInstance *p_gi, Vector
#ifdef MODULE_CSG_ENABLED #ifdef MODULE_CSG_ENABLED
CSGShape *shape = Object::cast_to<CSGShape>(p_gi); CSGShape *shape = Object::cast_to<CSGShape>(p_gi);
if (shape) { if (shape) {
// Shapes will not be up to date on the first frame due to a quirk
// of CSG - it defers updates to the next frame. So we need to explicitly
// force an update to make sure the CSG is correct on level load.
shape->force_update_shape();
Array arr = shape->get_meshes(); Array arr = shape->get_meshes();
if (!arr.size()) { if (!arr.size()) {
return false; return false;