Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Utilizing position in your fragment output causes semantic error in D3D9 mode

Discussion in 'Shaders' started by Invertex, Aug 2, 2015.

  1. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,494
    The error given:
    Here is the "Texture Coordinates" shader example taken from:
    http://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html

    All I have done is set the Blue channel on my frag output to "i.position.y", and suddenly the shader won't work in D3D9 and gives the previously stated error.

    Code (CSharp):
    1. Shader "Custom/TextureCoordinates/Base" {
    2.     SubShader {
    3.         Pass {
    4.             CGPROGRAM
    5.             #pragma vertex vert
    6.             #pragma fragment frag
    7.             #pragma target 3.0
    8.  
    9.             #include "UnityCG.cginc"
    10.  
    11.             struct vertexInput {
    12.                 float4 vertex : POSITION;
    13.                 float4 texcoord0 : TEXCOORD0;
    14.             };
    15.  
    16.             struct fragmentInput{
    17.                 float4 position : SV_POSITION;
    18.                 float4 texcoord0 : TEXCOORD0;
    19.             };
    20.  
    21.             fragmentInput vert(vertexInput i){
    22.                 fragmentInput o;
    23.                 o.position = mul (UNITY_MATRIX_MVP, i.vertex);
    24.                 o.texcoord0 = i.texcoord0;
    25.                 return o;
    26.             }
    27.             fixed4 frag(fragmentInput i) : SV_Target {
    28.                 return fixed4(i.texcoord0.xy,i.position.y,1.0);
    29.             }
    30.             ENDCG
    31.         }
    32.     }
    33. }
    If I change my build settings to D3D11, but still leave the #pragma target 3.0, it suddenly works, despite still targeting the same shader model. This seems very odd.

    If this is intended, could someone share with me the proper method to handle this?
    I was doing:
    float2 sSpace = (i.position.xy / _ScreenParams.xy);
    For my screen space effects and it works perfectly when in D3D11 mode, but if it's not going to work in D3D9, I need to figure out a different solution, thanks!
     
  2. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    The code you have there compiles to hlsl, so it is on Unity's side, probably some issue with translation to glsl? Try the dx9 "VPOS" instead of "SV_POSITION"... If that does not work, you'll just have to copy the position to a separate texcoord in the vertex shader.
     
  3. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,494
    If I change it to VPOS, it gives this error:
    I've attempted to put the position into another texcoord, but for some reason it's not generating the same values...


    D3D11:

    Code (CSharp):
    1. Shader "Custom/testyD3D11" {
    2.     SubShader {
    3.         Pass {
    4.             CGPROGRAM
    5.             #pragma vertex vert
    6.             #pragma fragment frag
    7.             #pragma target 3.0
    8.             #include "UnityCG.cginc"
    9.             struct vertexInput {
    10.                 float4 vertex : POSITION;
    11.                 float4 texcoord0 : TEXCOORD0;
    12.             };
    13.             struct fragmentInput{
    14.                 float4 position : SV_POSITION;
    15.                 float4 texcoord0 : TEXCOORD0;
    16.             };
    17.             fragmentInput vert(vertexInput i){
    18.                 fragmentInput o;
    19.                 o.position = mul (UNITY_MATRIX_MVP, i.vertex);
    20.                 o.texcoord0 = i.texcoord0;
    21.                 return o;
    22.             }
    23.             fixed4 frag(fragmentInput i) : SV_Target {
    24.                 return fixed4(i.position.xy,0.1,1.0);
    25.             }
    26.             ENDCG
    27.         }
    28.     }
    29. }
    D3D9:

    Code (CSharp):
    1. Shader "Custom/testyD3D9" {
    2.     SubShader {
    3.         Pass {
    4.             CGPROGRAM
    5.             #pragma vertex vert
    6.             #pragma fragment frag
    7.             #pragma target 3.0
    8.             #include "UnityCG.cginc"
    9.             struct vertexInput {
    10.                 float4 vertex : POSITION;
    11.                 float4 texcoord0 : TEXCOORD0;
    12.                 float4 texcoord1 : TEXCOORD1;
    13.             };
    14.             struct fragmentInput{
    15.                 float4 position : SV_POSITION;
    16.                 float4 texcoord0 : TEXCOORD0;
    17.                 float4 texcoord1 : TEXCOORD1;
    18.             };
    19.             fragmentInput vert(vertexInput i){
    20.                 fragmentInput o;
    21.                 o.position = mul (UNITY_MATRIX_MVP, i.vertex);
    22.                 o.texcoord1 = mul (UNITY_MATRIX_MVP, i.vertex);
    23.                 o.texcoord0 = i.texcoord0;
    24.                 return o;
    25.             }
    26.             fixed4 frag(fragmentInput i) : SV_Target {
    27.                 return fixed4(i.texcoord1.xy,0.1,1.0);
    28.             }
    29.             ENDCG
    30.         }
    31.     }
    32. }
    Or am I not copying the position over to the texcoord1 correctly?
     
    Last edited: Aug 3, 2015
  4. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,494
    Bump...
     
  5. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    As far as I know, you can't use the clip space position in the pixel/fragment shader. So the copy to another float4 is correct. You have to imagine it's actually like this:

    Code (csharp):
    1. struct vertexInput {
    2.                 float4 vertex : POSITION;
    3.                 float4 texcoord0 : TEXCOORD0;
    4.                 float4 texcoord1 : TEXCOORD1;
    5.             };
    6.             struct vertexOutput {
    7.                 float4 position : SV_POSITION;
    8.                 float4 texcoord0 : TEXCOORD0;
    9.                 float4 texcoord1 : TEXCOORD1;
    10.             };
    11. struct fragmentInput{
    12.                 float4 texcoord0 : TEXCOORD0;
    13.                 float4 texcoord1 : TEXCOORD1;
    14.             };
    15.             vertexOutput vert(vertexInput i){
    16.                 vertexOutput o;
    17.                 o.position = mul (UNITY_MATRIX_MVP, i.vertex);
    18.                 o.texcoord1 = mul (UNITY_MATRIX_MVP, i.vertex);
    19.                 o.texcoord0 = i.texcoord0;
    20.                 return o;
    21.             }
    22.             fixed4 frag(fragmentInput i) : SV_Target {
    23.                 return fixed4(i.texcoord1.xy,0.1,1.0);
    24.             }
    The position is defined in the fragment input, but it won't actually have any meaningful value.
     
  6. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    The position is defined on some platforms, like d3d11 (and d3d9, or at least, the hlsl docs say so, not sure about other platforms). The difference between passing your own clip space position and reading from SV_POSITION is that the latter already has the perspective division applied (pos.xy / pos.w) and is scaled to (0, size) instead of (0, 1) or (-1, 1), which is what you're seeing in the left screenshot. The solution is to normalize the coordinates back by dividing them by _ScreenParams.xy and then offsetting them to whatever range you need.
     
  7. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,494
    Thanks for the help. There is still something strange going on that is at the root of my problem, DX9 and DX11 mode seem to produce different results with the same code. Here is jvo3dc's code, unaltered, in both modes. Why is the output different in each?


    edit:
    After some experimentation I discovered something odd. In DX9 mode, If I use the "texcoord0" in my return instead of the "texcoord1" that we passed position to, I get the exact same gradient result as the DX11 mode. This is really strange...
    And if I do that in DX11 mode, it gives me the same pure-dark-blue result that happens if I had done an
    "i.texcoord1.xy / _ScreenParams.xy"... As if in DX11 mode it's already doing that automatically to the texcoord0, this is weird.

    Though i've yet to find a way to replicate in DX9 the pure Yellow result that directly passing the position does in DX11 mode.
     
    Last edited: Aug 9, 2015