Search Unity

  1. 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

unrecognized identifier sampler2D_half

Discussion in 'Shaders' started by arkano22, Aug 20, 2020.

  1. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    Hi there,

    I have a shader that compiles and runs fine in all computers I've tried, except for one windows machine. There, this error is shown in the shader inspector:

    'unrecognized identifier sampler2D_half'

    replacing it with sampler2D works, but what's happening here? according to Unity's own docs (https://docs.unity3d.com/Manual/SL-DataTypesAndPrecision.html), sampler2D_half is a thing. Why does it only work *almost* everywhere, but not in some devices?
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Hi!
    What graphics API is used on this machine?
    Can you try replacing it with Texture2D_half?
     
  3. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    D3D11.
    Replacing it with Texture2D_half didn't work, unfortunately.
     
  4. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Can you paste your shader code here?
     
  5. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    Here's the full code for the cginc file that contains the unrecognized definition. Let me know if you need more details of any kind:

    Code (CSharp):
    1.  
    2. #ifndef OBIFLUIDS_INCLUDED
    3. #define OBIFLUIDS_INCLUDED
    4.  
    5. #include "../ObiUtils.cginc"
    6. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    7.  
    8.  
    9. float3 _FarCorner;
    10. float _ThicknessCutoff;
    11.  
    12. sampler2D _CameraOpaqueTexture; // background for refraction
    13. sampler2D _Foam;    // foam color / opacity.
    14. sampler2D_half _Normals; // normals <------------- HERE: unrecognized identifier sampler2D_half
    15. sampler2D_float _FluidSurface;  // depth
    16. sampler2D_float _CameraDepthTexture;
    17.  
    18. float Z2EyeDepth(float z)
    19. {
    20.     if (unity_OrthoParams.w < 0.5)
    21.         return LinearEyeDepth(z,_ProjectionParams); // Unity's LinearEyeDepth only works for perspective cameras.
    22.     else{
    23.  
    24.         // since we're not using LinearEyeDepth in orthographic, we must reverse depth direction ourselves:
    25.         #if UNITY_REVERSED_Z
    26.             z = 1-z;
    27.         #endif
    28.  
    29.         return ((_ProjectionParams.z - _ProjectionParams.y) * z + _ProjectionParams.y);
    30.     }
    31. }
    32.  
    33. // returns eye space position from linear eye depth.
    34. float3 EyePosFromDepth(float2 uv,float eyeDepth)
    35. {
    36.  
    37.     if (unity_OrthoParams.w < 0.5){
    38.         float3 ray = (float3(-0.5f,-0.5f,0) + float3(uv,-1)) * _FarCorner;
    39.         return ray * eyeDepth / _FarCorner.z;
    40.     }else{
    41.         return float3((uv-half2(0.5f,0.5f)) * _FarCorner.xy,-eyeDepth);
    42.     }
    43. }
    44.  
    45. void SetupEyeSpaceFragment(in float2 uv, out float3 eyePos, out float3 eyeNormal)
    46. {
    47.     float eyeZ = tex2D(_FluidSurface, uv).r; // we expect linear depth here.
    48.  
    49.     // reconstruct eye space position/direction from frustum corner and camera depth:
    50.     eyePos = EyePosFromDepth(uv,eyeZ);
    51.  
    52.     // get normal from texture:
    53.     eyeNormal = (tex2D(_Normals,uv)-0.5) * 2;
    54. }
    55.  
    56. void GetWorldSpaceFragment(in float3 eyePos, in float3 eyeNormal,
    57.                            out float3 worldPos, out float3 worldNormal, out float3 worldView)
    58. {
    59.     // Get world space position, normal and view direction:
    60.     worldPos     = mul(_Camera_to_World,half4(eyePos,1)).xyz;
    61.     worldNormal = mul((float3x3)_Camera_to_World,eyeNormal);
    62.     worldView   = normalize(_WorldSpaceCameraPos.xyz - worldPos.xyz);
    63. }
    64.  
    65. float OutputFragmentDepth(in float3 eyePos)
    66. {
    67.     float4 clipPos = mul(unity_CameraProjection,float4(eyePos,1));
    68.     float depth = clipPos.z/clipPos.w;
    69.  
    70.     depth = 0.5*depth + 0.5;
    71.  
    72.     // DX11 and some other APIs make use of reverse zbuffer since 5.5. Must inverse value before outputting.
    73.     #if UNITY_REVERSED_Z
    74.         depth = 1-depth;
    75.     #endif
    76.  
    77.     return depth;
    78. }
    79.  
    80. #endif
    81.  
     
    Last edited: Sep 1, 2020
  6. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Ah, that's easy :)

    SRP uses macros instead: use TEXTURE2D_HALF(_Normals), TEXTURE2D(_Foam), TEXTURE2D_FLOAT(_FluidSurface) and so on.
     
  7. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    Thanks! these can't be used for the built-in render pipeline, right? So there needs to be separate files for each pipeline, correct? I hoped to be able to wrap up common functionality for all pipelines in cginc files, but this kinda breaks the way I structured things. Not a big deal, but still an unnecessary friction point imho. Also, the fact that sampler2D works in SRP, but there's an equivalent TEXTURE2D() macro makes things even more redundant and confusing.

    Is this documented anywhere? even now that I know about these macros and I'm actively looking for info about them, I can't find a single place in the documentation/manual that mentions their existence.
     
    Last edited: Sep 1, 2020
  8. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Builtin declares Texture2D_half and sampler2D_half as macros that resolve to Texture2D and sampler2D on DX11 (see HLSLSupport.cginc).
    "sampler*" syntax is from DX9, so SRP went with a more modern Texture2D.
    For builtin you can create those macros manually and it will work, e.g.
    #ifndef TEXTURE2D_HALF
    #define TEXTURE2D_HALF(name) Texture2D_half name;
    #endif
    If you do this, it will work with the same syntax across SRP and builtin.

    I'm not sure, TBH :) I just checked, what SRP does with those.
     
  9. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    Thanks a lot! Defining the macros with the same names in case they aren’t defined sounds good to me.
     
    aleksandrk likes this.
  10. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    The plot thickens.

    Seems that tex2D() and similar functions are replaced by macros too, and we are forced to use the separate sampler/texture approach seen in DX11 (afaik this was optional in the built-in pipeline). The built-in approach of using sampler2D + tex2D still works, but only on certain APIs. So coming from the built-in pipeline, it's easy to assume your shaders are correctly written and will compile, when in fact they won't... sometimes.

    Once you use TEXTURE2D(_TexName) instead of sampler2D _TexName, the compiler will choke at tex2D(), tex2Dlod() and company. This is because SAMPLE_TEXTURE2D() should be used instead, but it takes both a texture and a sampler identifier as parameters. So you also need to declare the sampler using TEXTURE2D_SAMPLER2D(_TexName, sampler_TexName). Am I correct in my assumptions?

    If so, this *really* should be documented somewhere. With no real docs stating how to do things properly, people that transition from built-in to SRP will generate and post around a lot of garbage shader code that works-but-not-quite, leading others to repeat (read: copy-paste) their mistakes and perpetuating the myth that SRPs are buggy and incomplete.

    The only reference to TEXTURE2D_SAMPLER2D I could find anywhere (once I knew it existed, after wading trough URP source files) is a sample for the 2.1 post processing stack: https://docs.unity3d.com/Packages/c...ing-Custom-Effects.html?q=TEXTURE2D_SAMPLER2D, which contains a vague indication that "Texture declaration is done using macros."
     
    Last edited: Sep 9, 2020
    svobodajak likes this.
  11. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Somewhat :)

    SRP does the following:

    #define TEXTURE2D_FLOAT(name) Texture2D_float name; SamplerState sampler##name;

    So it basically declares both in one macro.

    It absolutely should be. There's a push towards having proper documentation, but that takes time.
     
  12. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    744
    Thanks for shedding some light on the matter, aleksandrk.

    The sources for URP 7.4.1 (D3D11.hlsl file) declare it as:
    Code (CSharp):
    1. #define TEXTURE2D_FLOAT(textureName)          TEXTURE2D(textureName)
    If I don't use SAMPLER(sampler_textureName) in my code, I get a compilation error in SAMPLE_TEXTURE2D complaining about the sampler identifier being undefined. Also, I've seen the TEXTURE2D(textureName) SAMPLER(sampler_textureName) combo used in the URP sources. So sampler and texture do not seem to be declared at once. Am I missing something here? Maybe this is a thing in newer URP versions only?

    Btw, I discovered that TEXTURE2D_SAMPLER2D is only defined in the postprocessing stack package, so not available in SRPs in general. It's shorthand for
    Code (CSharp):
    1. sampler2D
    in DX9 and
    Code (CSharp):
    1. Texture2D texName; SamplerState samplerName;
    in DX11.
     
    Last edited: Sep 9, 2020
    svobodajak likes this.
  13. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,662
    Sorry, looks like I mixed this up with something else...

    There's a separate
    #define SAMPLER(samplerName) SamplerState samplerName
    declaration there.
     
    arkano22 likes this.
unityunity