Announcement

Collapse
No announcement yet.

Shadowatlas borders and parameters for long distance lights

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Shadowatlas borders and parameters for long distance lights

    While playing around with my light source that I want to use as a simulated sun I saw that the shadows start to look like in the picture when the distance to the light source increases. I tried to alter some parameters in the atlas but I dont understand them enough honestly.
    If I saw this right this shadow technique uses some kind of upscaling? Something like the SuperEagle effect that emulators use to turn low res pixel into lines and shapes? Might this be what causes this effect?

    I am of course aware that a shadowmap used for a big area needs some compromises in quality. So, I think that a blockier low res shadow would be ok. Is there a way to disable this upscaling algo? If, that is, is the reason for these effects.

    I checked an old demo that ran on Afterwarp 2.x and there I used a "sun" light that was 10000 Units in the sky while the shadow looked ok. I also remember that the old version didnt have this upscale filter, thats why I wonder if that is the reason.
    Attached Files

  • #2
    The appearance of shadows is greatly affected by the configuration of near and far planes, as well as field of view. Among these, near plane is most critical, so you should try to put it as much closer to the scene as possible (but try not to overdo it as otherwise you'll lose shadows for some objects). Small values like 0.1 or 1.0 for near plane should definitely be avoided. Common values for near/far planes should be something like 200 and 1500 respectively, and field of view around 30-45 degrees (pi/6 - pi/4). Higher field of view can work, but requires fine-tuning other parameters.

    Otherwise you can reduce visible artifacts by adjusting TShadowParameters structure, specifically try increasing Variance parameter and possibly Bias: read these values first to determine their defaults and then gradually increase them until artifacts disappear.

    The framework uses shadow mapping technique, which means that a view from light source is rendered to a so-called "shadow map", which is then blurred before being used in the scene. The shadow technique hasn't changed since Afterwarp v1 except for some minor improvements (there is an ongoing research for a future update, however). There is no "upscaling" as such, other than filtering when the shadow map is accessed. You can increase shadow map size, or adjust "BlurSigma" and "BlurSamples" in TShadowParameters to adjust the blurring (these are same parameters as Sigma and Samples used in TGaussianBlur).

    Comment


    • #3
      The Near value was the one I didn't think about. Limiting that did the trick and I can fine tune further. You don't need that shadow area up in the sky obviously. I think I should be able to adjust the shadow perspective dynamically later to the current camera position so that I can use the maximum quality without wasting anything on areas not visible or far away. However I have one final issue.

      When you move stuff outside of your shadow perspectives frustum instead of the shadows disappearing everything becomes shadow. In games you can often see shadows disappearing in the distance which is fine, but everything becoming dark in the distance would be rather unfortunate. The only workaround I can think of would be a check for each object if it is inside the shadow area or not and then deactivate the shadow atlas in the scene.
      Attached Files

      Comment


      • #4
        That issue shouldn't normally occur as the shadow atlas sampled at the edges of the shadow map should have border color. Please make sure that you are setting non-zero border during shadow casting atlas creation and also that you are calling BorderFill function before rendering the shadow maps.

        Comment


        • #5
          Borderfill is used. But how do you set a non-zero border during creation of the atlas? I cant find any value for that. Looked also in the examples.


          Comment


          • #6
            Sorry, it is called "padding" and is the last parameter; by default, it should be set to one. If you have only one light source casting shadows, then you can do the opposite: set padding to zero and make sure to set shadow caster size matching the atlas size.

            Comment


            • #7
              ok. I tried that. Unfortunately no change.

              Here is my code:

              Code:
              LTechniqueShadows := TTechniqueShadows.ESM_Warp;
              FShadowCastingAtlas := TShadowCastingAtlas.Create(FDevice, Point2i(4096, 4096), LTechniqueShadows, 8, 0);
              FShadowCastingAtlas.Add(Point2i(4096,4096));​
              Code:
              // Render shadow map.
              FShadowCastingAtlas.BorderFill;
              //LShadowParameters := FShadowCastingAtlas.Parameters;
              //FShadowCastingAtlas.Parameters := LShadowParameters;
              
              LShadowCaster := FShadowCastingAtlas.Casters[0];
              LShadowCasterView := FObjects.CreateView;
              LShadowCasterView.View := TMatrix4f.LookAt(Viewport_SceneLights[0].Position, Vector3f(0,0,0), TVector3f.AxisY);
              LShadowCasterView.SetProjection(TMatrix4f.PerspectiveFOVY(Pi * 0.35, 1.0, 6500.0, 9500.0,
              LDepthClipNegative), LDepthClipNegative);
              
              LShadowCaster.ViewProjection := LShadowCasterView.ViewProjection;
              
              LShadowCaster.Clear;
              LShadowCaster.BeginScene;
              try
              Viewport_SceneDepthNormals.Attributes := [];
              Viewport_SceneDepthNormals.View := LShadowCasterView.View;
              Viewport_SceneDepthNormals.Projection := LShadowCasterView.Projection;
              
              for i := 0 to GameScenes[Viewport_LoadedNum].GameModels.Count -1 do
              RenderSceneModels (Viewport_SceneDepthNormals, i, true);
              
              finally
              LShadowCaster.EndScene;
              end;
              LShadowCaster.Filter;​

              Comment


              • #8
                In above code you are leaking views when calling "FObjects.CreateView". Since you are not using views for rendering (ideally, you should as the view performs object visibility tests against the frustum so you don't render what you don't see), you may want to remove the view from there entirely. Can you try "EVSM" shadows instead of "ESM_Warp"?

                Comment


                • #9
                  I didnt use the Objects class so far as I created my own objects and hierachy class. But, yes I saw these functions that perform the visibility tests and it would be wise to switch to that. Maybe I can put a decendent over it to add my own stuff. For example my idea is that other stuff like light sources, sound emitters, cameras and way later also particle emitters can be added into object hierachies as well.

                  Oh and I also tested the EVSM. I switched to esmwarp because the artifacts are less visible there.

                  Just as an option, is the frustum check a complicated function? I thought that I cound "round" it from the matrix to a bounding box and check if boundingbox of a model is inside that one.

                  Anyway. Thanks again. I will try to implement afterwarps object class first as I think that would best in longterm.

                  Comment


                  • #10
                    Hey uhm. I looked through different things and as far as I understand it in order to use the automatic culling provided by the ObjectModel classes I have to use the Autodraw method and that would mean that I had to go all in and use it completely. (Materials, Hierachy ect) That would be a big.step back for me as I had to redo big parts, so I would rather like to try my own culling methods.
                    I know I am annoying in this regard

                    I figured out checking if points are within a frustrum and was also able to check for all 8 corners of a boundingbox. But I quickly noticed the downsides of this and that being to close to an object would cull it simply because the corners are outside.
                    I also read about AABB checks against the planes of a frustrum but couldnt quite get behind it and how you can check an already transformed bounding box matrix with that method.

                    Long story short: would you be so kind and share your method that checks if a model is within a frustrum that you use with the autodraw method? Rewritting it to Pascal isnt necesarry, I should be able to figure it out from C code.
                    I apologize for my ongoing requests in this matter.

                    Comment


                    • #11
                      AutoDraw functions do not perform culling. The culling is performed when you call TObjectModelView.Update, which internally maintains a bounding volume hierarchy (BVH) of objects, except for objects marked as "hierarchyless" (which are internally processed separately) and uses that to quickly determine what is within the view frustum; the same hierarchy is used to perform object selection.

                      I don't think it would be complicated to integrate Afterwarp's object system into your own: in your own "object" class include a field of TObjectModel type, which you can instantiate from parent TObjectModels (which should be a field of parent container which contains your "objects"). During creation of own "object", create TObjectModel and pass "Self" as "Payload" parameter. So, you can always retrieve your "object" from TObjectModel.Payload, and you can access TObjectModel from your object as field. After call to TObjectModelView.Update, you will have a list of visible objects in TObjectModelView, which you can iterate (e.g. use "for in" loop); from each iterated TObjectModel you can retrieve your "object" class from payload. Same applies to object selection, where you get selected object as TObjectModel, from which you can get your "object". TObjectModels also allows you to quickly obtain "TObjectModel" associated with each unique "Payload" (internally it is a hash table), so in theory, you can even use TObjectModels itself as a container for your own objects. In other words, if you have "TGameObject" class, you can have "TGameObject.ObjectModel" property of TObjectModel type, whereas TObjectModel.Payload is actually a value of TGameObject type, so you have 1:1 relationship between "TGameObject" and "TObjectModel".

                      The whole purpose of TObjectModels is to have a light-weight object/model system which can perform visibility and selection (and in future, collision tests). It is completely decoupled from rendering, so you can keep using your own rendering loop. However, should you decide to do so, you could use AutoDraw functions to later draw these objects automatically. Also note that there are AutoDraw functions overloads that do not need TObjectModels, so you can leverage them from your own rendering loop as well.

                      Unless you want to manually optimize some code in assembler or use some third-party library, I wouldn't recommend performing object visibility tests against frustum manually in Delphi, as any performance gains from omitting such objects during rendering will be mitigated by slow visibility tests, unless you implement something like BVHs yourself, which can also get fairly complicated. If you still want to pursue this approach, please let me know and I'll try to help.

                      Edit: if you use TObjectModels and your rendering loop (that is, TObjectModel without setting its "Mesh" property), you would need to specify TObjectModel.Transform[TModelTransform.LocalVolume] (in addition to TModelTransform.Local, which defines object position and orientation). This transform should include scale matrix (to set the proper size of a unity cube), as well as position and orientation.

                      Comment

                      Working...
                      X