Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

tex2Dfetch compiles with OpenGL but not DirectX ?

Discussion in 'Shaders' started by theFrenchDutch, Jan 20, 2016.

  1. theFrenchDutch

    theFrenchDutch

    Joined:
    May 5, 2014
    Posts:
    25
    Hi !

    I am writing a shader for wich I need to be able to fetch exact values in a texture at exact coordinates (like you would be able to with a simple 2D array).

    I tried using CG's solution for this, int4 tex2Dfetch(...) : http://http.developer.nvidia.com/Cg/tex2Dfetch.html
    But I get the error "undeclared identifier 'tex2Dfetch' at line 117 (on d3d11)". In fact, whatever I set the pragma target to, the only way I can get this error to go away is to surround the call to tex2Dfetch in a #if defined(SHADER_API_OPENGL) statement.

    Is there a way around that or a particular reason why this isn't supported ? I am also aware that I could set the texture to Point filtering and fetch the four surrounding values with some uv tricks, but simply using tex2Dfetch seems a lot simpler.

    Thanks for your attention ;)
     
  2. theFrenchDutch

    theFrenchDutch

    Joined:
    May 5, 2014
    Posts:
    25
    Side note : I need exact values because the texture is in the Alpha8 format and initialized from a byte array, where each value is an identifier. So I need the exact value to be able to identify what I need, and since tex2Dfetch can return an int4, it seems more reliable to me than the floats that a normal tex2D would return. (I've ran into issues with floats and exact values in shaders in the past)
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,972
    tex2Dfetch and tex2D will return a float or an int depending on the sampler type, but you can't define an integer sampler in Unity so int4 = tex2Dfetch(_Texture, uv, 0); will still be returning a float number that'll just get converted to an int. Enabling point sampling is the only way to ensure no bilinear filtering. When sampling RGB channels you need to ensure sRGB is disabled, but alpha is always linear.

    So set texture to Alpha8, disabled mip maps, point filtering.
    And In the shader: int = tex2D(_Texture, uv).a * 255.0;
    If you want to be extra sure you're getting an accurate value try int = tex2D(_Texture, uv).a * 255.0 + 0.5;
     
  4. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,608
    Side note, Unity "almost does not use Cg" these days. I've been replacing most/all mentions in the docs to say "Cg/HLSL", and more details on which compilers are used where is in this page. http://docs.unity3d.com/Manual/SL-ShadingLanguage.html

    Now, "texel fetch" is a DX10/GL3 level feature, and as such it does not exist on DX9, GLES2 and other similar platforms. The Cg compiler syntax for it is not really understood by the other compilers I think, so you probably want to make the shader compile into SM4.0 / ES3.0 target ("#pragma target es3.0", see http://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html) and use standard HLSL syntax for it. I forget what that is, possibly Sample or Load or similar.
     
  5. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    364
    The function is indeed Texture2D.Load()

    You can also use point filtering and sample at texel center. That will work on every platform.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,972
    @Aras - I would say this is an area of the Unity documentation that's lacking. Having a sampler2D _Tex in your shader and then trying to using _Tex.Load() or _Tex.Sample() doesn't work so you have to define it as texture2D _Tex within an #if for the appropriate compilers. It gets more muddy if you're trying to use .Load on a texture that already gets defined as a sampler2D elsewhere; as far as I can tell it's impossible (except for on the PS4 where you can just do _Tex.t to get the texture2D).
     
  7. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,608
    Indeed, will try to improve docs at some point.

    In this case using UNITY_DECLARE_TEX2D(_Tex) is probably best (see http://docs.unity3d.com/Manual/SL-BuiltinMacros.html), since that on DX11-style systems declares separate sampler+texture pair that you can use .Load etc on. I'm not sure if that works on PS4 though, but it should work on platforms where actual HLSL is used (DX11/12, XB1, GLES3, GLCore).
     
  8. theFrenchDutch

    theFrenchDutch

    Joined:
    May 5, 2014
    Posts:
    25
    Hey thanks for all your answers, it did shed light on things for me :)

    I've tried what you mentionned bgolus, and it did work. Just had to make sure I was sampling at the middle of each texels.
    Thanks a lot :)
     
unityunity