Is UNITY_MATRIX_VP wrong under DX11?

Hi all,

I’m struggling with a rendering issue that appears when ticking the DX11 box in Player Settings. It’s making some of my custom shaders render wrong. I posted this issue to the Forum as well but I think I gave it a poor title there. :wink: It’s not getting any replies, so I decided to try and fish here, too.

The rendering artifacts I’m seeing indicate 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 matrices
  • UNITY_MATRIX _MVP - The full, concatenated ModelViewProjection matrix

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

Shader "Custom/TestVF" {
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
 
        pass
        {      
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma vertex vert
            #pragma fragment frag
 
            struct vertOut
            {
                float4 position : POSITION;
            };
       
            vertOut vert(appdata_full vertIn)
            {
                vertOut o;              
                o.position = mul(UNITY_MATRIX_MVP, vertIn.vertex);
                return o;
            }
 
            void frag(out float4 c_out : COLOR)
            {
                c_out = float4(0,1,0,1);
            }
 
            ENDCG
        }
    }
    FallBack "Diffuse" }

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):

        vertOut vert(appdata_full vertIn)
        {
            vertOut o;
           
            float4 vertWorld = mul(_Object2World, vertIn.vertex);
            o.position = mul(UNITY_MATRIX_VP, vertWorld);
            return o;
        }

That should do exactly the same, it just does the same transformation over 2 matrix calculations instead of one.

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:

        vertOut vert(appdata_full vertIn)
        {
            vertOut o;
           
            float4 vertWorld = mul(_Object2World, vertIn.vertex);
            float4 vertView = mul(UNITY_MATRIX_V, vertWorld);
            o.position = mul(UNITY_MATRIX_P, vertView);              
            return o;
        }

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 in the forum. I can’t attach it here because UA has a 512KB attachment limit:

http://forum.unity3d.com/threads/using-built-in-transformation-matrices-in-a-pair-of-vertex-fragment-shaders-on-dx11.272869/

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. :slight_smile:

It turns out the short answer to my question was “yes”.

The VP matrix was indeed set wrong under DX11. I was very lucky and got Aras’ attention on the forum for this problem, and he was able to check the source code and find a bug that caused the VP matrix to go out of sync under DX11. Interested parties may follow the link to the forum version of this question.

It will be fixed for Unity 5, and hopefully also for the next 4.5x patch. Closing now. :slight_smile:

I have a similar problem on directx 11, windows 10, unity 2018.2.18f1 . Below vertex shader behaves correctly.

			v2f vert(appdata_base v) {
				v2f o;
				float4 worldFragment =mul(UNITY_MATRIX_M, v.vertex);	    
				o.position = mul(UNITY_MATRIX_VP,worldFragment);
				return o;
			}

But the following one not

			v2f vert(appdata_base v) {
				v2f o;
				float4 worldFragment =mul(UNITY_MATRIX_MV, v.vertex);	    
				o.position = mul(UNITY_MATRIX_P,worldFragment);
				return o;
			}

What could be the reason?