From e06cd3042f84856ae540153451def8028f900cc9 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 29 Jul 2021 12:41:23 +0100 Subject: [PATCH] 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. --- modules/csg/csg_shape.cpp | 11 +++++++++++ modules/csg/csg_shape.h | 2 ++ scene/3d/room_manager.cpp | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 3e9d6509ab1..65529798240 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -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 { if (root_mesh.is_valid()) { Array arr; diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index c19933716e3..b5730e2b9c2 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -119,6 +119,8 @@ protected: public: Array get_meshes() const; + void force_update_shape(); + void set_operation(Operation p_operation); Operation get_operation() const; diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp index 4f9be0a59ee..02a3efab59b 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -1596,6 +1596,11 @@ bool RoomManager::_bound_findpoints_geom_instance(GeometryInstance *p_gi, Vector #ifdef MODULE_CSG_ENABLED CSGShape *shape = Object::cast_to(p_gi); 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(); if (!arr.size()) { return false;