# Why can't I sample a texture in a vertex shader?

I'm old in Game Development but very new in shader writing. I just want a shader that transform from 1 texture to another. So I did start learning shader writing and wrote my desired shader. But during writing one thing I cannot understand as I am very dumb in shader writing that if I assign fixed4 color with COLOR semantic in vertex method then compiler gives the following error.

Shader error in 'Hamza/TwoTextures': cannot map expression to vs_4_0 instruction set at line 39 (on glcore)

Compiling Vertex program Platform defines: UNITY_ENABLE_REFLECTION_BUFFERS UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BOX_PROJECTION UNITY_SPECCUBE_BLENDING SHADER_API_DESKTOP UNITY_TEXTURE_ALPHASPLIT_ALLOWED

Here is the not working shader code,

Shader "Hamza/TwoTextures"{
Properties{
[NoScaleOffset]
_Texture1 ("Texture 1",2D) = "white"{}

[NoScaleOffset]
_Texture2 ("Texture 2",2D) = "white"{}

_Mixer ("Mixer", Range(0,1)) = 0
}

Pass{
CGPROGRAM

#pragma vertex vert
#pragma fragment frag

sampler2D   _Texture1;
sampler2D   _Texture2;
float       _Mixer;

struct appdata{
fixed4 vertex   : POSITION;
fixed2 tex      : TEXCOORD0;
};

struct v2f{
fixed4 pos      : SV_POSITION;
fixed2 tex      : TEXCOORD0;
fixed4 col      : COLOR;
};

v2f vert(appdata i){

v2f o;
o.pos = mul(UNITY_MATRIX_MVP,i.vertex);
o.tex = i.tex;

// Giving error on this line
o.col = (tex2D(_Texture1,i.tex) * _Mixer) + (tex2D(_Texture2,i.tex) * (1 - _Mixer));
return o;
}

fixed4 frag(v2f v) : COLOR
{
return v.col;
}

ENDCG
}
}
}


And if I write same expression to throw it as return fixed4 value in fragment method then everything is working fine.

Shader "Hamza/TwoTextures"{
Properties{
[NoScaleOffset]
_Texture1 ("Texture 1",2D) = "white"{}

[NoScaleOffset]
_Texture2 ("Texture 2",2D) = "white"{}

_Mixer ("Mixer", Range(0,1)) = 0
}

Pass{
CGPROGRAM

#pragma vertex vert
#pragma fragment frag

sampler2D   _Texture1;
sampler2D   _Texture2;
float       _Mixer;

struct appdata{
fixed4 vertex   : POSITION;
fixed2 tex      : TEXCOORD0;
};

struct v2f{
fixed4 pos      : SV_POSITION;
fixed2 tex      : TEXCOORD0;
};

v2f vert(appdata i){

v2f o;
o.pos = mul(UNITY_MATRIX_MVP,i.vertex);
o.tex = i.tex;
return o;
}

fixed4 frag(v2f i) : COLOR
{
// It is giving me no error
return (tex2D(_Texture1,i.tex) * _Mixer) + (tex2D(_Texture2,i.tex) * (1 - _Mixer));
}

ENDCG
}
}
}


Can anyone explain me that why it is happening? And what is the difference between them?

As I mentioned that I did start learning only two days before. I'm sort of noob in this.

The error here is that you're trying to sample from a texture in a vertex shader the way you would in a fragment or pixel shader.

Vertex texture fetches are a little bit special. They're only supported in Shader Model 3 and up, and they're unable to use the tex2d() function.

That may sound odd, but tex2D() is really a shortcut that says "figure out the right mip level to sample automatically" - in a fragment shader this is done using implicit derivatives, but those aren't available at the vertex stage.

So, we need to use the more explicit tex2dlod() form (which works at both the vertex and fragment stages). This takes a 4-component vector, whose x and y are the familiar texture coordinates in uv space, and w indicates which mip level to sample from (0 being the highest resolution available).

• This mean second one is optimised and right way? right? – Hamza Hasan Jan 14 '16 at 12:46
• @HamzaHasan Which one are you asking about? Your second shader example with the texture fetch in the fragment shader? Or the option of using tex2dlod in the vertex shader? It all depends on what you're trying to do. – DMGregory Jan 14 '16 at 12:47
• My second shader example, what about the current case? Means about to transform textures, what I'm doing in it – Hamza Hasan Jan 14 '16 at 12:48
• @HamzaHasan It's not clear to me what you're trying to do. If your second shader is accomplishing what you need though, then it sounds like you're on a good track. – DMGregory Jan 14 '16 at 12:49
• I'm trying to change textures from a Range value. If range is 0 then only 1st texture will be visible on mesh, if range is 1 then only second texture will be visible and if range is 0.5 then both textures (blended, if I'm not wrong) will show up on mesh. Well Thank You so much for your response. I was just curious about that issue. Thanks again. – Hamza Hasan Jan 14 '16 at 12:54