Shadow ignors DistanceCulling

Hi,
I have placed two scenes. One with DistanceCulling = 0 and one with DistanceCulling = 100.
When the DistanceCulling starts, the scene (left house) becomes invisible, but the shadow is still visible.

Maybe a bug?

regards
Dieter

Fixed, thank you for reporting!

I have already committed the fix, Do not render shadows for objects eliminated by DistanceCulling · castle-engine/castle-engine@6081eaa · GitHub . It will be available in binary CGE downloads ( Download | Castle Game Engine ) in ~6 hours, once Jenkins builds new CGE.

Indeed, we should not render shadows for invisible objects.

  • Not only it looks a bit weird…

  • … but in case of shadow volumes it is actually a bug: the calculation of shadow volumes assumes that shadow caster is really rendered, otherwise weird things may be visible.

I tested on a quickly hacked version of “3D FPS game” template, here are screenshots before and after.

Note: The “shadow maps” algorithm, that I will want to expose in the future, will actually enable to render shadows for invisible objects. We can have it as an option then (but still, by default off, so we will not render shadows from invisible objects).


Hi Michalis,

I have the same issue with the newest version.

Can you check please if you get the same result?

Thanks
Didi

We had indeed changes related to shadow volumes recently ( Shadow volumes: new WholeSceneManifold option, fixes and docs – Castle Game Engine ) so it is feasible I broke something.

… However, testing, it seems everything is OK. I tested:

  • modified “3D FPS game” (with DistanceCulling = 10)

  • I also added examples/viewport_and_scenes/shadows_distance_culling and tested it.


I actually found one small issue ( LocalRenderShadowVolume must update RenderCameraPosition · castle-engine/castle-engine@97f98fb · GitHub ) but I doubt this is your issue – it could cause 1-frame delay, not a constant invalid shadow.

Can you submit an exact testcase to reproduce your problem? Or maybe you can modify examples/viewport_and_scenes/shadows_distance_culling to cause it?

Note that I just added examples/viewport_and_scenes/shadows_distance_culling to the repository, it will take a while for Jenkins to update the binary builds. When this page : Comparing snapshot...master · castle-engine/castle-engine · GitHub will no longer show commit " Test shadows and DistanceCulling", then it is incorporated in the build on Download | Castle Game Engine .

I have seen now, that it happens only when WholeSceneManifold is TRUE.

But in my case i need this.

Is it possible to check if the scene is visible? When not visible I can set WholeSceneManifold to false?

Regards
Didi

Confirmed, the case of WholeSceneManifold combined with DistanceCulling is not good now. I had a TODO to improve it – I’m working on it (I kind of have a fix, but it doesn’t work fully yet :slight_smile: ).

I’ll let you know, maybe even today later I’ll finish it.

Still in progress.

I found the mistake in my reasoning about how the WholeSceneManifold should interact with per-shape culling (like done by DistanceCulling). It’s a bit larger change, so I’ll finish it later, hopefully tomorrow.

For today I committed my current solution – it behaves better than before, but it is not fully correct (when the DistanceCulling distance radius is inside the house, right now part of it will be rendered, part not; but when WholeSceneManifold=true we have to always render whole house).

I also extended the testcase examples/viewport_and_scenes/shadows_distance_culling to include test of WholeSceneManifold=true (I use house model with a few materials, such that it requires WholeSceneManifold).

More to come tomorrow :slight_smile:

All properly fixed.

WholeSceneManifold cooperates now with DistanceCulling properly always.

I tested various cases in examples/viewport_and_scenes/shadows_distance_culling.

As usual, please test and let me know is it good now in your case :slight_smile:

The fix is committed to GitHub master branch. You can observe this page: Comparing snapshot...master · castle-engine/castle-engine · GitHub . When it will no longer contain commit " Fix (and simplify) cooperation between WholeSceneManifold and Distanc…" then it means this fix is incorporated into builds on Download | Castle Game Engine .

Hi Michalis,

WholeSceneManifold with use of DistanceCulling looks very good now.
Performance is also still good.
In my new project i use in the moment 50 scenes (12 with WholeSceneManifold), three big Terrains and a lot of TCastleTransform.

TreeTransforms:    array [1..50] of TCastleTransform;    (with shadows)
Tree2Transforms:   array [1..20] of TCastleTransform;    (with shadows)
GrassTransforms1:  array [1..1600] of TCastleTransform;  (with move animation)
FlowersTransforms: array [1..500] of TCastleTransform;
RockTransforms:    array [1..50] of TCastleTransform;  

FPS is between 20 to 30.

some questions:

  • Why does DistanceCulling depends on the Scene.Scale? It would be easier to set DistanceCulling on more scenes with different scales, if the value were to be calculated on a uniform basis (e.g. Scale = 1)?

  • Visibility is not inherited between parent and child. I use a scene as parent and TCastleBox as child, and a TCastleText as child from the box. If the scene is not visible (because of DistanceCulling) the box and the text are still visible.

  • The child scene1 or scene4 (weapon) of a parent scene (avatar) has no shadow. All of these scenes are set up for shadow.
    I use this to change the weapon:

grafik

Regards
Didi

Hm, these are both features resulting from current design – although I agree that the design is not the most comfortable :slight_smile:

  • DistanceCulling is a property of given TCastleScene. So it is interpreted in the “local coordinate system” of this scene (scaling the scene scales also the DistanceCulling interpretation, in a way). This is consistent with some other things – in general distances and calculations are done in local coordinate system of given TCastleTransform.

    I agree this is not most comfortable in this case. Since you have to edit DistanceCulling on each scene, you’d like to select a bunch of scenes in editor, and edit their DistanceCulling at once, but you cannot if their scales differ.

  • And the 2nd fact, that DistanceCulling is on each scene (and doesn’t affect children), is consistent with the fact that TCastleScene specific features (like TCastleRender) do not affect children (because in general case, this would create more questions and difficulty for implementation - e.g. scene RenderOptions or ReceiveShadowVolumes also do not affect children).

    Although most properties on TCastleTransform, like Exists, do effect children. E.g. CastShadows do work recursively. I know, the end result isn’t perfect (esp. making ReceiveShadowVolumes and CastShadows not consistent), but at least there’s a rule to the madness – stuff on TCastleTransform is usually recursive, stuff on TCastleScene is usually not.

I think there is one solution to both these issues: we need a system to apply a distance culling on a group of objects. So you would apply it one place, e.g. a TreeGroup: TCastleTransform, and then all 50x TreeTransforms are just children of it, and they are automatically affected. Such distance culling would be specified in the local coordinate system of TreeGroup , and then the scaling specific to each particular tree should not matter.

We could do this by implementing TCastleBehavior that synchronizes DistanceCulling on all scene children.

I did a quick attempt at this – see Behavior that affects all children scenes, setting their DistanceCulling (TDistanceCullingGroup) · GitHub and comments within. Warning: It compiles,I really didn’t check anything else :slight_smile: Let me know if this is useful to you.

I will want to do more thinking how to expose this in a clean way in CGE — this behavior makes some assumptions, e.g. you will need to sometimes call UpdateChildren manually – if you add / scale the children at runtime. But I guess in your case it doesn’t matter if you use this for stuff like trees, but you probably don’t reposition at runtime.

This behavior also wastes opportunity to potentially reject whole groups that are outside of the distance. As it applies DistanceCulling on each scene, each scene will be checked separately. But one can envision a useful optimization that groups TCastleTransforms, effectively creativing BVH from them, and can reject whole groups.

So… I should think how to do this in long-term in a way that I really like :slight_smile: But for now, hopefully this will be useful to you as a “wrapper over DistanceCulling that makes it more comfortable”. It does make an improvement: you can manage a group of scenes with a single property (you add one instance of TDistanceCullingGroup to a one TreeGroup and you let it auto-configure culling on all children trees).

If this wasn’t explained by one of my statements above, please submit a testcase – I’ll be happy to investigate :slight_smile:

Hi Michalis,

thank you very much for the explanation.

DistanceCulling is not a big problem, because I can check in the editor when zooming out and in.

The Problem with the weapon shadow, if I understand you right, is not possible on the child-scene.
So I created a new scene (SceneAvatarWeapon) which is not a child of the SceneAvatar.
In the Update method I implemented this:

  if Scene1.Exists then
  begin
    Scene1.GetWorldView(aPos,aDir,aUp);
    SceneAvatarWeapon.SetWorldView(aPos,aDir,aUp);
  end;
  if Scene4.Exists then
  begin
    Scene4.GetWorldView(aPos,aDir,aUp);
    SceneAvatarWeapon.SetWorldView(aPos,aDir,aUp);
  end;

I take the translation and direction from the unvisible child and use them for the visible weapon with shadow.
It seems to work. Maybe to much work around?

Regards
Didi

In case of this issue (scene1, scene4, weapon) — oh, I admittedly just don’t understand the issue. If you can send the testcase, I can judge better :slight_smile:

The code you show is a valid code to synchronize the world transformation of 2 TCastleTransform. It looks OK, but I don’t know the purpose of it. But this is indeed a valid way to avoid having child-parent relationship, and just “synchronize by hand” some transformations, if necessary for any reason.

CGE - examples - viewport_and_scenes - shadows

duplicate the Scene1 (now we have two soldiers with shadow)

Make the Scene5 to a child of Scene1 the shadow is gone.