Search Unity

How to sample a texture in vertex shader

Discussion in 'Shaders' started by GreatWall, Jan 23, 2018.

  1. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    I want to sample texture in vert shader. I write like this

    void vert(inout appdata_full vertex)
    {

    vertex.vertex.y -= tex2Dlod(_SnowTrackTex, vertex.texcoord)

    }
    works well, but when I use tex2D like this:

    void vert(inout appdata_full vertex)
    {

    vertex.vertex.y -= tex2D(_SnowTrackTex,vertex.texcoord.xy)

    }
    It can’t works.error message as follow:

    cannot map expression to vs_5_0 instruction set.
     
    Xtro likes this.
  2. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I don't know which shader version you are using but I think the proper call is Tex2dlod instead of tex2d, I haven't testes it myself and kind forgot the rational, but I remember searching about that once.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    The tex2D function is only allowed in the fragment shader. It cannot be used in the vertex shader or any other shader stage.

    The reason is mip mapping. Specifically the way GPUs calculate the proper mip level to display when using tex2D. This is calculated by measuring how much the UV changes per pixel, which is only known during the fragment shader stage.

    You must use tex2Dlod in the vertex shader.
     
    jacksonkr and neoshaman like this.
  4. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    So "mip mapping" and "level of detail of a texture " are different? I always confused about these terms.
     
  5. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    LOD controls which mip-map is used. As he stated, the automated value for choosing which mip-map level to use isn't know till fragment stage. Thus, you use the tex2Dlod method because it requires you state a specific mip-map level to sample from.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    When it comes to textures they can be thought of the same thing. The texture's mip and level of detail aren't necessarily the same thing though. You'll note I used the term "mip level", which would more accurately be the "mip map level of detail". I'll explain a bit more, but first some additional information.

    As stated the tex2D function calculates the texture's mip level during the fragment shader stage. As such you only need to pass in the texture (in the form of a sampler2D) and the UV (in the form of a float2) to get an appropriately filtered color back.

    The tex2Dlod function requires you define the mip level manually. As such you need to pass in the texture (a sampler2D again), and the uv (again a float2), but also an LOD value. Now if your examples above you're using this example:

    tex2Dlod(_SnowTrackTex, vertex.texcoord)

    That vertex.texcoord from appdata_full is already a float4 value, so that works with out any error. By default most meshes are going to have the z and w components of the float4 be 0.0, which works out perfectly for this case. However you're better off doing this:

    tex2Dlod(_SnowTrackTex, float4(vertex.texcoord.xy, 0.0, 0.0));

    That last zero is the mip level. If you change that to a 1.0 or 2.0 you'd use the first or second mip instead, assuming your texture has mip maps.

    Note, if you pass a float4 as the UV for a tex2D it would automatically cull it down to a float2 on most platforms, but might also error on others and fail to compile. Be wary of this because a shader that compiles on your computer might not on someone else's if you're not careful!


    So what's the difference between mip maps and level of detail and why do I say "mip level" or "mip map level of detail"? Mip mapping refers to taking a texture and making successively smaller pre-filtered versions of the texture. Each texture is half the size of the previous mip, and each pixel is (usually) an average of the 4 pixels of the larger texture it's a mip of. Now, when rendering a mesh using that texture it can pick the texture that's closest in size to how it's currently being rendered.

    When the mip level is calculated by the GPU, it's not going to always be whole numbers. Usually it's going to come up with fractional numbers, ie: a mip level of 0.66. For point and bilinear filtering, this just gets pushed up to the next whole number mip. However for trilinear filtering it takes both mip 0 and mip 1 and blends between them, 34% of mip 0 and 66% of mip 1.


    So the term mip mapping can refer to both the mip maps themselves and the basic idea of choosing a mip based on the viewed scale of the texture. It is one of many methods of doing level of detail for texturing, though it is by far and away the most common and also the only one really supported by current GPUs. Also, this all gets quite pedantic and most likely when people talk about mip mapping or level of detail, or anything else around this they're probably talking about the same thing.
     
  7. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Also, OP should probably keep in mind that operations done in the Vertex shader are typically only done for the 3 points of the triangle and the value is interpolated between the results of those 3 points. So if you were hoping to use any complex texture detail in this way, it wouldn't really work, you'll just end up with a gradient of color between each vertex of the mesh.
     
  8. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    Thanks for your detailed explanation. I think I get the point.
    Then because there is no mip map in vertex shader, I test the following lines in my code, and they have the same result:
    tex2Dlod(_SnowTrackTex, float4(vertex.texcoord.xy, 0.0, 0.0));
    tex2Dlod(_SnowTrackTex, float4(vertex.texcoord.xy, 0.0, 1.0));
    It just uses the level 0 texture for sample.because there is no level 1 texture??
     
  9. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    If the texture you're supplying has no mip-maps, then yes it uses the level 0 texture. He didn't say there is no mip-map in the vertex shader, he's saying that the "level of detail" functionality that is part of tex2D cannot happen in the vertex shader, and thus you have to manually choose which mip-map to sample instead of letting the level-of-detail value control it.

    If your texture has mip-maps, then your second line there would select the second mip level.
     
  10. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    Can you show result? because mip map level are similar, especially if you are using a low resolution output like vertex
     
  11. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    Group.png
     
  12. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    I just output in fragment.
     
  13. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    Does that means the "level of detail" function can't exist in vertex shader even through the texture has mipmap?
    In other word, no matter mipmap exists or not,tex2D can't be used in vertex? So "tex2D can't be used in vertex" has no matter with the texture's mipmap, just because it use a function which can't be done in vertex shader?
     
  14. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    No. What I was saying, like bgolus was saying, is that the automatic LOD "functionality" that is in "tex2D" cannot happen in in the vertex shader. But, you can manually define a specific mipmap by using tex2Dlod instead, just like you're doing now.
     
  15. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    That means there are two kinds of LOD functions "automatic" and "manually". And the "automatic" one must happen in fragment shader .
    tex2D choses the "automatic" one.So it can't be used in vertex shader.No matter with whether the texture has mipmap.
    tex2Dlod choses the "manually" one. So it can be used in vertex shader.No matter with whether the texture has mipmap.
     
  16. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Basically yes. Though I wouldn't say they use different kinds of LOD functions.

    It's just that, with tex2D, since you aren't providing your own LOD/MIP value, tex2D needs to get the LOD value from somewhere else. That "somewhere else" is the screen-space derivatives (ddx/ddy) that are calculated by the GPU during the Pixel shader process.

    At it's core, it is the same sampling method, you are simply changing where the source of the LOD value comes from.
     
    BBxiaoge and senkal_ like this.
  17. GreatWall

    GreatWall

    Joined:
    Aug 7, 2014
    Posts:
    57
    Thank you Invertex,I think I get the point this time.
     
  18. kino919

    kino919

    Joined:
    Feb 12, 2021
    Posts:
    1
    oh it is really helpful for beginners, solved my problem, thx
     
  19. Hzz_xingtu

    Hzz_xingtu

    Joined:
    Apr 19, 2017
    Posts:
    2
    Wonderful discussion! thx;)