@DSK Done, with a demo!
Committed to GitHub in Implement TCastleScene.WasVisible, TAbstractShapeNode.WasVisible, with · castle-engine/castle-engine@8adafca · GitHub . You can either wait a few hours until the binary build of CGE is updated, or get CGE source code and recompile it now following Compiling from source | Castle Game Engine .
New methods:
- TCastleScene.WasVisible, docs:
{ Whether the scene was (potentially, at least partially) visible in the last rendering event.
The "was visible" means that "some shape was visible", that is:
some shape passed frustum culling and occlusion culling (see https://castle-engine.io/occlusion_query )
tests.
For this method it doesn't matter if the scene contains some lights
that only make some other scenes brighter. Or if the scene contains some background
that affects TCastleViewport skybox. Only the visibility of shapes matters.
If this scene instance is used multiple times within some viewport,
or when multiple viewports render the same scene,
then it is enough that at least one shape in one of the scene instances
was visible last frame. }
function WasVisible: Boolean;
- TAbstractShapeNode.WasVisible, docs:
{ Whether the shape was (potentially, at least partially) visible in the last rendering event.
Note that the same shape reference may be present multiple times
within one scene.
Moreover, the same scene may be present multiple times within one viewport.
Moreover, multiple viewports may render the same scene.
The shape is marked as "was visible" if any instance of it was visible
in any viewport in any scene. }
function WasVisible: Boolean;
- Demo in
examples/viewport_and_scenes/test_was_visible
. castle-engine/examples/viewport_and_scenes/test_was_visible at master · castle-engine/castle-engine · GitHub , Screens:
Note some caveats:
-
There are no events, like OnShow / OnHide. Instead I exposed methods
WasVisible
, and you have to query them as often as you need to detect changes.This made it simpler to implement, as should be good enough for many use-cases. Engine has optimizations that allow to completely avoid rendering things that are not visible (e.g. whole scene rendering will be ignored if frustum culling is used and scene bounding box is not inside frustum, in which case we don’t even iterate over shapes). So if we wanted to have events, we’d need to add additional loops that iterate over “watched” scenes/shapes (with some OnShow/OnHide registered) and generate OnShow / OnHide when their WasVisible changed.
It seems simpler and more flexible to avoid this loop on the engine side, and delegate to user code the job of querying
WasVisible
(as often as you need, for the scenes/shapes you are interested in). -
In the end I didn’t use
TShape
to store / query this information, contrary to what I said earlier, asTShape
andScene.Shapes
tree is harder to access, and it may be rebuild in case of some changes to scene graph.Instead I placed
WasVisible
inTAbstractShapeNode
(ancestor ofTShapeNode
), this is more stable, as this node is guaranteed to remain persistent across scene modifications.I am also considering to move the
TShape
andScene.Shapes
to internal engine parts. Most code should just use nodes,TShapeNode
andTAbstractShapeNode
, notTShape
.