Hey everyone. I recently noticed that in my shader, when I don't mention a "float4 position : SV_POSITION" parameter in the fragment function, the texture being supplied to the material doesn't show. Instead what shows up is just one color from the texture. Here's my code with the "float4 position : SV_POSITION" parameter in the Fragment function: Code (CSharp): Shader "Custom/MyShader08" { Properties { _MainTex01 ("Texture01", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex01; float4 _MainTex01_ST; void vert( float4 position : POSITION, float2 texCoord0 : TEXCOORD0, out float4 oposition : SV_POSITION, out float2 otexCoord0 : TEXCOORD0 ) { oposition = UnityObjectToClipPos(position); otexCoord0 = TRANSFORM_TEX(texCoord0, _MainTex01); } float4 frag( float4 position : SV_POSITION, float2 texCoord0 : TEXCOORD0) : SV_Target { float4 color = tex2D(_MainTex01, texCoord0); return color; } ENDCG } } } Here's the result. Texture shows up as it should. Here's my code without "float4 position : SV_POSITION" in the Fragment shader: Code (CSharp): Shader "Custom/MyShader08" { Properties { _MainTex01 ("Texture01", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex01; float4 _MainTex01_ST; void vert( float4 position : POSITION, float2 texCoord0 : TEXCOORD0, out float4 oposition : SV_POSITION, out float2 otexCoord0 : TEXCOORD0 ) { oposition = UnityObjectToClipPos(position); otexCoord0 = TRANSFORM_TEX(texCoord0, _MainTex01); } float4 frag( float2 texCoord0 : TEXCOORD0) : SV_Target { float4 color = tex2D(_MainTex01, texCoord0); return color; } ENDCG } } } This is the result: I'm very new to writing shaders so there's definitely something I'm missing here. I'm not able to understand why an SV_POSITION parameter is required in the Fragment function when I'm not using it. I've tried looking online for an answer and couldn't find one. The Shader Semantics page doesn't mention it either.
That’s very odd. Especially since the position value is stripped by the shader compiler anyway when it is included since it’s not being used.
Looking at the compiled shader, the reason can be found. However I'm not sure if this is a bug, or "user error". On Windows the working compiled shader looks like this: Vertex Shader Code (csharp): // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // POSITION 0 xyzw 0 NONE float xyz // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_POSITION 0 xyzw 0 POS float xyzw // TEXCOORD 0 xy 1 NONE float xy // vs_4_0 dcl_constantbuffer CB0[3], immediateIndexed dcl_constantbuffer CB1[4], immediateIndexed dcl_constantbuffer CB2[21], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output_siv o0.xyzw, position dcl_output o1.xy dcl_temps 2 0: mul r0.xyzw, v0.yyyy, cb1[1].xyzw 1: mad r0.xyzw, cb1[0].xyzw, v0.xxxx, r0.xyzw 2: mad r0.xyzw, cb1[2].xyzw, v0.zzzz, r0.xyzw 3: add r0.xyzw, r0.xyzw, cb1[3].xyzw 4: mul r1.xyzw, r0.yyyy, cb2[18].xyzw 5: mad r1.xyzw, cb2[17].xyzw, r0.xxxx, r1.xyzw 6: mad r1.xyzw, cb2[19].xyzw, r0.zzzz, r1.xyzw 7: mad o0.xyzw, cb2[20].xyzw, r0.wwww, r1.xyzw 8: mad o1.xy, v1.xyxx, cb0[2].xyxx, cb0[2].zwzz 9: ret Fragment Shader Code (csharp): // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_POSITION 0 xyzw 0 POS float // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Target 0 xyzw 0 TARGET float xyzw // ps_4_0 dcl_sampler s0, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_input_ps linear v1.xy dcl_output o0.xyzw 0: sample o0.xyzw, v1.xyxx, t0.xyzw, s0 1: ret The parts to pay attention to are the signature description comments, and the matching dcl_input_ps and dcl_output lines. More specifically the register number and the v# and o# values after the dcl_* lines. SV_POSITION is register 0, TEXCOORD0 is register 1 for both the vertex and fragment shader, and that fact is mirrored by the vertex shader's dcl_output o1.xy and fragment shader's dcl_input_ps v1.xy for the texcoord data. For the broken shader, the vertex shader is identical, but the fragment shader is different. Code (csharp): // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // TEXCOORD 0 xy 0 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Target 0 xyzw 0 TARGET float xyzw // ps_4_0 dcl_sampler s0, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_input_ps linear v0.xy dcl_output o0.xyzw 0: sample o0.xyzw, v0.xyxx, t0.xyzw, s0 1: ret Notice, the TEXCOORD0 is now listed as being on register 0, but the vertex shader is using register 1 still! The resulting miss match appears to just pass float2(0.0, 0.0) into the shader instead of the expected UVs or even the position. Like I said before, I'm not entirely sure if this is user error, as I would expect the semantics to handle this out of order issue for you, or if it's a requirement that the layout of the vertex output and fragment input match for D3D11 (it didn't for D3D9). So, one solution / work arounds would be to just include SV_POSITION, obviously. As I mentioned in my previous post, it doesn't actually "do" anything having it there since the shader compiler already strips it from the compiled shader (as evidence of there being no dcl_input_ps_siv linear noperspective v0.xyzw, position in the fragment shader. Another would be to change the order of your outputs from the vertex shader so the TEXCOORD0 is before the SV_POSITION, which causes the TEXCOORD0 to use register 0.
Oh wow! Very interesting seeing a breakdown of the problem. This makes me think I should do a some research on GPU architecture and familiarize myself with the some of the GPU instruction set, not necessarily to write shader assembly, but rather to be able to try and debug issues by looking into the compiled assembly. So, I tried switching the order of outputs and putting TEXCOORD0 before SV_POSITION, and it worked. For now I guess I'll just add the SV_POSITION parameter. Thanks for all the info. Definitely interested in finding out more about what the issue is here.