0
\$\begingroup\$

I a previous post (Scaling and offset problems with screen space reflexion in DX11) I was fnally able to produce SSR with several methods (ray marching/McGuire/Mirror like). These techniques have all their own limits producing some articfacts like "holes" for overlapping object not in the same z and not close enougth or other problems.

Can someone help me in some ways to resolve these various artifacts shown in the answer picture in this previous post. Did someone knows if these holes in McGuire code can be handled? I’m thinking of something like these algorithms were you can remove someone in a photo and replace it by the surrounding scene.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Solutions.

First I suggest reading the thesis from Anthony Paul Beug (Screen Space Reflexion Techniques, 2020) that summarizes and compares several SSR techniques with code for DX and which gives several ideas for artefacts.

In the picture panel A is the initial McGuire SSR method I implemented. The holes marked white are due to overlapping objects. For instance, the blue dot hides the green ball that hides the vertical plane. The plane has thus a hole due to the overlapping green ball in the main scene. The only way to deal with this is to create an additional layer to store the missing information for occluded pixels (panel B). The artefacts marked in yellow are from the bottom of the object where things starts to be invisible for the camera or the ray march is not able to hit the pixel. I have to say that I did not understand why the ray is able to hit the top of the sphere correctly but not the bottom. This can be fixed somehow (panel C) but is not perfect at the moment (panel D) as some deformed shapes appear when far from screen centre or still incomplete pixel detection.

enter image description here

The first problem is thus solved (panel B) by adding extra render targets to store the hidden pixels. Before this I’m sorting object back to front on the cpu. For this I pretransform the object boundingbox (WVP) to obtain screen data XYZ. Z is used first for back to front sorting (mandatory for the correct final drawing). XY are used to calculate the bounding square for each object in screen space to determine intersections between objects. Intersecting object are then Z compared to know who is overlapped. An object overlap flag is incremented each time an object is overlapped. This overlap flag is part of the constant buffer object. In addition the DepthMin and DepthMax of the object are also stored in the cbuffer for later use. The cbuffer for mesh is like this:

 typedef struct _CBMESH
 {
      XMMATRIX mWorld;
      XMMATRIX mIT_VW; //Inverse Transpose View*World for view space normals
      XMMATRIX mMirror; //used for « depth mirror » calcul.
      XMFLOAT4 FactorColor;
      XMFLOAT4 D1D2DMinDMax; //D1 = 1 if overlap = 1 else 0; 
      //D2 = 1 is overlap > 1 else 0; DMin/max DepthMin/Max mentioned earlier.
      DWORD Flag; //for specific coloring treatment
      XMFLOAT3 pad; //unused
   }CBMESH, *LPCBMESH;

In this scene (panel E) object can have 0 (white square), 1 (red) more than one (green) overlaps. At rendering time all objects are drawn in the main layer 1 (albedo +normal view space + regular depth buffer). enter image description here

Objects overlapped once are drawn in the second layer (albedo+normal view space + specific depth map channel R). Objects overlapped more than one are drawn in the third layer (albedo+normal view space + specific depth map channel G). An extra map is used for “depth mirror” value explain later. Yes 8 targets at the end. Maybe there is a better way to proceed. It was mentioned that up to 4 layers may be needed. This is similar to the depth peeling method described on NVidia web site but here I select layer based on the overlap count. As I’m using multitarget rendering for all the preparation process I have independent blend for each target. Layer 1 (albedo+normal) has opaque setting and the other SRC_ALPHA/INV_SRC_ALPHA colour blend. Specific depth maps are filled with 1 and then using OP_MIN for RG colors similar to COMPARISON_LESS. Object are drawn in all targets whatever the settings so we need to make some “invisible” in 2nd and 3rd layer. This is where D1D2DMinDMax is used like this :

    Output.Color2 = float4(Color,D1D2DMinDMax.y); //3rd layer shows object only if they have overlap > 1 (alpha is set to D1D2DMinDMax.y=1, object visible else not visible). 

Same for the normal in 3rd layer. D1D2DMinDMax.x set alpha for 2nd layer. A the same time the specific depth map is filled using also D1D2DMinDMax.xy:

    Output.Color6 = float2(1-D1D2DMinDMax.x+Input.Pos.z*D1D2DMinDMax.x,1-D1D2DMinDMax.y+Input.Pos.z*D1D2DMinDMax.y);//put 1 if not visible (remember we do OP_MIN) or the depth value if visible. R is layer 2 and G layer 3.

During SSR ray march all 3 depth information are evaluated in the McGuire method to find the best SceneZMax value.

The final problem is the ray missing the bottom of the objects. I thought using GatherRed on main depth buffer to sample 4 depths at once but can’t get it working correctly. I solved the problem (partially, panel C/D) with a “mirrored depth” value. The idea is to mirror locally the depth of the object to give better chances to the ray to hit the pixel. First I prepare a “billboard” matrix using the direction from camera to the object position.

   gBillBoard = XMMatrixRotationAxis(V, -Roty);//V is the direction, RotY is the camera rotation, the sign seems not important). 

Then I store gBillBoard*WVP in the mMirror member of the cbuffer mesh. In the VShader I calculate:

  output.PosM = (input.pos, mMirror).

PosM.z/PosM.w is the alternative Depth. Then I fill the mirror depth map with the locally mirrored depth using the two last member zw of D1D2DMinDMax (because of the precision the precalculated sum did not work properly) :

Output.Color7 = D1D2DMinDMax.w+D1D2DMinDMax.z-Input.PosM.z/Input.PosM.w;

This simple operation makes Z=DMin becoming DMax and vice versa all over the interval resulting in a “local mirrored depth”. The result is not perfect as shown in panel D. The shape is better preserved when at screen centre. The more at the screen boundaries the higher the shape is deformed. I hope someone can help me find a better matrix to solve this deformation problem.

At the end the FPS rate is >70 in the worst case and around 90 in the best after removal of some unnecessary shader instructions. Using B5G6R5 format for albedo/normal extra layers improves the FPS a little while maintaining sufficient quality and reducing a little the bandwith. No blur is made.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.