Search Unity

Enabling/disabling MSAA messes with lighting settings

Discussion in 'General Graphics' started by DeltaPiSystems, Nov 7, 2019.

  1. DeltaPiSystems

    DeltaPiSystems

    Joined:
    Jul 26, 2019
    Posts:
    30
    I have a 'special' situation...
    I mirror my z-axis using a custom right-handed look-at
    Code (CSharp):
    1. _camera.worldToCameraMatrix = Matrix4X4Utilities.LookAtRh(cameraData.Eye, cameraData.LookAt, cameraData.UpAxis);
    I calculate my normals per-fragment in my shader:
    Code (CSharp):
    1. fixed4 frag(v2f i) : SV_Target
    2. {
    3.     float3 normal = normalize(cross(ddx(i.worldPos), ddy(i.worldPos)));
    4.    
    5.     // dot product between normal and light direction for
    6.     // standard diffuse (Lambert) lighting
    7.     half nl = max(0, dot(normal, _WorldSpaceLightPos0.xyz));
    8.     // factor in the light color
    9.     fixed4 diff = nl * _LightColor0;
    10.    
    11.     // in addition to the diffuse lighting from the main light,
    12.     // add illumination from ambient or light probes
    13.     // ShadeSH9 function from UnityCG.cginc evaluates it,
    14.     // using world space normal
    15.     diff.xyz += ShadeSH9(half4(normal,1));
    16.     return i.color * diff;
    17. }
    18.  
    When I change the MSAA setting on my camera, light direction 'flips', making the light come from the exact opposite direction.

    MSAA on:
    upload_2019-11-7_8-50-55.png

    MSAA off:
    upload_2019-11-7_8-51-21.png

    Why does this happen and what alternative methods can I use?
    I don't need shadows, prefer performance, prefer MSAA (FXAA isn't very good) and I need only a depth buffer.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    Two thoughts.

    First, if you don’t have the
    “LightMode”=“ForwardBase”
    tag on your shader pass, the light direction can be a little funny, but I don’t know if that’s the issue.

    Second, there’s a weird thing with MSAA in Direct3D. Normally, OpenGL and Direct3D texture sampling and rendering orientation are flipped from each other. Unity handles this by flipping the projection matrix, and a few variables here and there to let shaders know the projection is flipped, or that the incoming render texture was rendered flipped. MSAA is weird because it causes the GPU to render in the same orientation as OpenGL. I wonder if that’s what’s flipping the normal since now the ddy() is going to be giving you the inverse vector, flipping the cross product.

    I’d try using this line and see if it works:
    Code (csharp):
    1. float3 normal = normalize(cross(ddy(i.worldPos), ddx(i.worldPos))) * _ProjectionParams.x;
    I've honestly never seen this problem crop up from MSAA flipping the screen since it should be using an inverted projection matrix to keep it consistent, but maybe there's something else in your rendering setup causing it to behave differently.
     
    Last edited: Nov 7, 2019
    DeltaPiSystems likes this.
  3. DeltaPiSystems

    DeltaPiSystems

    Joined:
    Jul 26, 2019
    Posts:
    30
    Your proposed solution works!
    You truly are a hero.

    I have no clue why, other than a right-handed worldToCameraMatrix I do nothing seemingly weird. That said, Unity doesn't like right-handed worldToCameraMatrices (camera gizmo goes weird)