Search Unity

Using built-in transformation matrices in a pair of vertex/fragment shaders on DX11

Discussion in 'Shaders' started by CHPedersen, Oct 8, 2014.

  1. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    Hi all,

    I've been experiencing some difficulty porting a bunch of my existing shaders from DX9 to DX11 when trying to get my project to run under DX11 today. In short, after fixing a few compiler errors, everything compiled but it started rendering wrong in ways that indicated some transformation matrix confusion.

    So I spent the day having a bit of fun messing around with the built-in matrices under DX11 to see what was wrong. I tested these 5 guys in particular:

    _Object2World - The current model matrix
    UNITY_MATRIX_V - The current view matrix
    UNITY_MATRIX_P - The current projection matrix
    UNITY_MATRIX_VP - The concatenation between the current view and projection matrix
    UNITY_MATRIX_MVP - The full, concatenated ModelViewProjection matrix

    I wrote this simple shader (full code) for it:

    Code (Cg):
    1. Shader "Custom/TestVF"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque" }
    10.         LOD 200
    11.  
    12.         pass
    13.         {      
    14.             CGPROGRAM
    15.             #include "UnityCG.cginc"
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.  
    19.             struct vertOut
    20.             {
    21.                 float4 position : POSITION;
    22.             };
    23.        
    24.             vertOut vert(appdata_full vertIn)
    25.             {
    26.                 vertOut o;              
    27.                 o.position = mul(UNITY_MATRIX_MVP, vertIn.vertex);
    28.                 return o;
    29.             }
    30.  
    31.             void frag(out float4 c_out : COLOR)
    32.             {
    33.                 c_out = float4(0,1,0,1);
    34.             }
    35.  
    36.             ENDCG
    37.         }
    38.     }
    39.     FallBack "Diffuse"
    40. }
    41.  
    I.e. a totally basic pass-through. This works as expected. I then started playing around with the matrices in the vertex shader. First, I did this (vertex shader only):

    Code (Cg):
    1.             vertOut vert(appdata_full vertIn)
    2.             {
    3.                 vertOut o;
    4.                
    5.                 float4 vertWorld = mul(_Object2World, vertIn.vertex);
    6.                 o.position = mul(UNITY_MATRIX_VP, vertWorld);
    7.                 return o;
    8.             }
    That should do exactly the same, it just does the same transformation over 2 matrix calculations instead of one. It inserts a temporary "stop" in world space.

    Interestingly, this does not yield the same result. O_O

    I was surprised to see my sphere get positioned in the lower left corner of the screen, and also stretched along the x-axis. That behaviour is under DX11 only, it works fine if I untick it in player settings and go back to DX9.

    More interestingly, I then split the calculation apart even further and did all 3 calculations step-by-step using the individual matrices, so the vertex shader becomes this:

    Code (Cg):
    1.             vertOut vert(appdata_full vertIn)
    2.             {
    3.                 vertOut o;
    4.                
    5.                 float4 vertWorld = mul(_Object2World, vertIn.vertex);
    6.                 float4 vertView = mul(UNITY_MATRIX_V, vertWorld);
    7.                 o.position = mul(UNITY_MATRIX_P, vertView);              
    8.                 return o;
    9.             }
    If I do this, then we're back to working as expected. That vertex shader does exactly the same as the one that uses the standard MVP matrix. I have the deepest respect for Unity's guys, so I'm a little leery of suggesting something like this, but I can't find any other explanation for this behaviour than the concatenated view*projection matrix (UNITY_MATRIX_VP) being set wrong under DX11.

    It would be wonderful if anyone would be willing to give this a spin on their machine to see if they get the same results. I saved the test project which is very small and attached the zip file to this post.

    The project is a testscene with a green sphere, and you can comment and uncomment the relevant lines in the shader to see the effect I'm talking about. Please let me know if I'm just stupid and made some silly mistake in the code above. :)
     

    Attached Files:

  2. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,536
    That sounds weird indeed! And yeah, quite possibly there might be a bug in DX11 code where it sets up VP matrix. Which would be embarrassing. I'll try to take a look when I'm on a Windows machine next week. Poke me on twitter if I forget :)
     
  3. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    That sounds awesome, Aras. Thanks a bunch for checking this out! I don't actually have a Twitter account, but this is more than enough incentive for me to make one. :) I'll see you there if I don't hear back from you after a bit.
     
  4. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,536
    Indeed, turns out on DX11 in some cases the VP matrix was getting out of sync. Fixed now for 5.0, will try to get the fix into next 4.5.x patch release too.
     
    CHPedersen likes this.
  5. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    That's wonderful news. Not that the bug existed, but that I'm not insane after all, and we found it and fixed it. :)
     
  6. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,536
    Thanks for reporting it! The fix should be out in 4.5.5 patch 2 towards end of this week. Fingers crossed.
     
  7. LIVENDA

    LIVENDA

    Joined:
    Oct 31, 2013
    Posts:
    275
    Has this issue been fixed? I know it's an old thread however it seems we are still getting incorrect MVP in DX11 vs Dx9
     
  8. fastcoder

    fastcoder

    Joined:
    Sep 20, 2013
    Posts:
    15
    I have a similar problem on directx 11, windows 10, unity 2018.2.18f1 . Below vertex shader behaves correctly.

    Code (CSharp):
    1.                
    2. v2f vert(appdata_base v) {
    3.                     v2f o;
    4.                     float4 worldFragment =mul(UNITY_MATRIX_M, v.vertex);      
    5.                     o.position = mul(UNITY_MATRIX_VP,worldFragment);
    6.                     return o;
    7.                 }
    But the following one not


    Code (CSharp):
    1.              
    2.  v2f vert(appdata_base v) {
    3.                     v2f o;
    4.                     float4 worldFragment =mul(UNITY_MATRIX_MV, v.vertex);      
    5.                     o.position = mul(UNITY_MATRIX_P,worldFragment);
    6.                     return o;
    7.                 }
    What could be the reason?