Search Unity

Sampler count limit for pixel shader in Shader Model 5.0?

Discussion in 'Shaders' started by mrtkhosravi, Jan 25, 2017.

  1. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    In shader model 5 is there a limit on how many sampler2Ds can we have on a shader? I looked up and didn't find any limitation. I'm pretty sure SM3.0 has a limit of 16 samplers and I guess SM4.0 has 32 sampler limit.
     
  2. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    DX11 limit is 16 samplers and 128 textures. That means only 16 textures in Unity since samplers and textures are connected here. You could use texture arrays to get over the limitation...
     
  3. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    Thanks for the link. I see that now. I don't understand what do you mean by 128 textures. In terms of shader code I understand sampler is sampler2D uniform but I don't get the concept of a texture in a shader.
     
  4. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    Textures and samplers are two separate things in every modern rendering API. Sampler object only tells what filter to use (point, bilinear, trilinear), what wrap mode to use etc. It is not connected to any texture. You can use it to sample any texture. Multiple textures. You usually need only handful of different samplers and you use them to sample any number of textures (up to 128). For example, this is how you sample textures in HLSL shader model 5:
    Code (CSharp):
    1. Texture2D texture1;
    2. Texture2D texture2;
    3. SamplerState sampler;
    4. float2 uv;
    5. ...
    6. float4 c1 = texture1.Sample(sampler, uv);
    7. float4 c2 = texture2.Sample(sampler, uv);
    sampler2D, tex2D() etc. are from DX9 (shader model 3). They simply don't exist in shader model 4 or 5. You can still use them in Unity because Unity cross-compiles shaders to target platform. From shader model 3 into shader model 5 in this example. Just like it cross-compiles HLSL to GLSL for OpenGL.

    Edit: little correction. Microsoft shader compiler has backwards compatibility mode that lets you use old syntax in shader model 4/5. So Unity doesn't have to cross-compile.
     
    Last edited: Jan 25, 2017
    ModLunar, nirvanajie and mrtkhosravi like this.
  5. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    WOW!! This is amazing. I like the idea but it seems this does not work in a unity surface shader!! It gave me this error:

    Code (CSharp):
    1. Shader "Uplus/EditTerrain/WaterFast" {
    2.     Properties {
    3.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    4.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    5.         _Metallic ("Metallic", Range(0,1)) = 0.0
    6.     }
    7.     SubShader {
    8.             Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
    9.         LOD 200
    10.         Offset -30, -30
    11.         CGPROGRAM
    12.         // Physically based Standard lighting model, and enable shadows on all light types
    13.         #pragma surface surf Standard vertex:vert tessellate:tessDistance alpha:fade nolightmap
    14.         #pragma target 4.6
    15.         #include "Tessellation.cginc"
    16.  
    17.  
    18.  
    19.         sampler2D _MainTex,_heightTex,_waterTex;
    20.         Texture2D texture1;
    21.         Texture2D texture2;
    22.  
    23.         struct Input {
    24.             float2 uv_MainTex;
    25.             float2 uv_waterTex;
    26.         };
    27.  
    28.         half _Glossiness;
    29.         half _Metallic;
    30.         float _size, _resolution;
    31.         float3 _terrainPos, _camPos;
    32.  
    33.         struct appdata {
    34.             float4 vertex : POSITION;
    35.             float4 tangent : TANGENT;
    36.             float3 normal : NORMAL;
    37.             float2 texcoord : TEXCOORD0;
    38.         };
    39.  
    40.         void vert(inout appdata v)
    41.         {
    42.             //v.texcoord.xy = mul(unity_ObjectToWorld, v.vertex).xz / _size;
    43.             float4 pos = float4(v.texcoord.xy, 0, 0);
    44.             v.vertex.y = unity_ObjectToWorld[1][3] +
    45.                 dot(tex2Dlod(_heightTex, pos).xy, float2(1, 1)) + tex2Dlod(_waterTex, pos).xy;
    46.             v.normal = float3(0,1,0);
    47.         }
    48.  
    49.         float4 tessDistance(appdata v0, appdata v1, appdata v2)
    50.         {
    51.  
    52.             float3 pos0 = mul(unity_ObjectToWorld, v0.vertex).xyz;
    53.             float4 pos = float4(v0.texcoord.xy, 0, 0);
    54.             pos0.y = unity_ObjectToWorld[1][3] + dot(tex2Dlod(_heightTex, pos).xy, float2(1, 1))
    55.                 + tex2Dlod(_waterTex, pos).xy;
    56.             float3 pos1 = mul(unity_ObjectToWorld, v1.vertex).xyz;
    57.             pos = float4(v1.texcoord.xy, 0, 0);
    58.             pos1.y = unity_ObjectToWorld[1][3] + dot(tex2Dlod(_heightTex, pos).xy, float2(1, 1))
    59.                 + tex2Dlod(_waterTex, pos).xy;
    60.             float3 pos2 = mul(unity_ObjectToWorld, v2.vertex).xyz;
    61.             pos = float4(v2.texcoord.xy, 0, 0);
    62.             pos2.y = unity_ObjectToWorld[1][3] + dot(tex2Dlod(_heightTex, pos).xy, float2(1, 1))
    63.                 + tex2Dlod(_waterTex, pos).xy;
    64.             float4 tess;
    65.  
    66.             if (UnityWorldViewFrustumCull(pos0, pos1, pos2, 100))
    67.             {
    68.                 tess = 0;
    69.             }
    70.             else
    71.             {
    72.  
    73.                 float maxTess = _resolution / 256+2;
    74.                 float dist = distance(pos0, _camPos);
    75.                 float tanHalfAlpha = tan(0.5235); //PI/6
    76.                 float l = 2 * dist * tanHalfAlpha;
    77.                 float pixErr = 8 / l * 500;
    78.                 float distFact = min(pixErr, maxTess);
    79.                 float sideFact = distFact + 3;// min(distFact, distFact * 1.2 - 0.2);
    80.                 tess = clamp(ceil(float4(sideFact, sideFact, sideFact, distFact)), 1, 32);
    81.             }
    82.             return tess;
    83.         }
    84.         void surf (Input IN, inout SurfaceOutputStandard o) {
    85.             // Albedo comes from a texture tinted by color
    86.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    87.             float water = tex2D(_waterTex, IN.uv_waterTex);
    88.             o.Albedo = c.rgb;
    89.             // Metallic and smoothness come from slider variables
    90.             o.Metallic = _Metallic;
    91.             o.Smoothness = _Glossiness;
    92.             o.Alpha = water;
    93.         }
    94.         ENDCG
    95.     }
    96.     FallBack "Diffuse"
    97. }
    98.  
     
  6. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    Yeah, looks like it really doesn't work in surface shaders. Well, there's very little to gain anyway. As I originally said, Unity doesn't support separated samplers and textures. Every texture in Unity has its own sampler. Just like the old days. Not every platform supports this to be fair so it is easier for Unity to keep it like this.
    Here's a working example that uses new syntax in pixel shader for what's it worth
    Code (CSharp):
    1.  
    2. Shader "Unlit/NewUnlitShader"
    3. {
    4.     Properties
    5.     {
    6.         _MainTex ("Texture", 2D) = "white" {}
    7.     }
    8.     SubShader
    9.     {
    10.         Tags { "RenderType"="Opaque" }
    11.         LOD 100
    12.  
    13.         Pass
    14.         {
    15.             CGPROGRAM
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.            
    19.             #include "UnityCG.cginc"
    20.  
    21.             struct appdata
    22.             {
    23.                 float4 vertex : POSITION;
    24.                 float2 uv : TEXCOORD0;
    25.             };
    26.  
    27.             struct v2f
    28.             {
    29.                 float2 uv : TEXCOORD0;
    30.                 float4 vertex : SV_POSITION;
    31.             };
    32.  
    33.             Texture2D _MainTex;
    34.             SamplerState sampler_MainTex;
    35.  
    36.             float4 _MainTex_ST;
    37.            
    38.             v2f vert (appdata v)
    39.             {
    40.                 v2f o;
    41.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    42.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    43.                 UNITY_TRANSFER_FOG(o,o.vertex);
    44.                 return o;
    45.             }
    46.            
    47.             fixed4 frag (v2f i) : SV_Target
    48.             {
    49.                 // sample the texture
    50.                 fixed4 col = _MainTex.Sample(sampler_MainTex, i.uv);
    51.                 return col;
    52.             }
    53.             ENDCG
    54.         }
    55.     }
    56. }
    57.  
     
    mrtkhosravi likes this.
  7. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    Even so it's great news. Actually most of my work is in classic vert/frag shaders. Thank you very much I hadn't even heard of this before.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Unity's lightmap sampling shader code uses some special macros for this.
     
    mrtkhosravi likes this.
  9. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    Nice catch. Here is what I found in HLSLSupport.cginc:

    upload_2017-1-26_6-20-3.png

    Now I get it. The shaders basically should use the current language for HLSL but because DX is backward compatible older shaders still work. So unity does not see the need to update surface shader code generators to support the new language. That feels rational to me.
     
  10. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Use the Unity defines for declaring sampler texture and non-sampler texture.

    Code (CSharp):
    1. UNITY_DECLARE_TEX2D(_SomeTex);
    2. UNITY_DECLARE_TEX2D_NOSAMPLER(_SomeTex2);
    3. UNITY_DECLARE_TEX2D_NOSAMPLER(_SomeTex3);
    4.  
    5. struct Input
    6. {
    7.     float2 uv_SomeTex;
    8. };
    9.  
    10. void surf (Input IN, inout SurfaceOutputStandard o)
    11. {
    12.     float2 UV = IN.uv_SomeTex;
    13.  
    14.     float4 someTex = UNITY_SAMPLE_TEX2D(_SomeTex, UV);
    15.     float4 someTex2 = UNITY_SAMPLE_TEX2D_SAMPLER(_SomeTex2, _SomeTex, UV);
    16.     float4 someTex3 = UNITY_SAMPLE_TEX2D_SAMPLER(_SomeTex3, _SomeTex, UV);
    17.  
    18.     //Do whatever else
    19. }

    This way it handles differences in target API as well. TEX2D_SAMPLER has it's second field to choose an existing "UNITY_DECLARE_TEX2D" to use as the sampler for the first input.
     
    nirvanajie and mrtkhosravi like this.
  11. mrtkhosravi

    mrtkhosravi

    Joined:
    Nov 9, 2014
    Posts:
    198
    That is fantastic. Now I can draw my terrains in a single pass. Thank you very much.
     
  12. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Hi,
    can someone provide a full example how to set _SomeTex2, eg. _SomeTex3 please?
    I do not understand to reference _SomeTex2, eg. _SomeTex3 in the shader to any texture.
    This does not work an cause an error.
    Code (CSharp):
    1.     Properties {
    2.         _Color ("Color", Color) = (1,1,1,1)
    3.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    4.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    5.         _Metallic ("Metallic", Range(0,1)) = 0.0
    6.         _SomeTex("_SomeTex Albedo (RGB)", 2D) = "white" {}
    7.         _SomeTex2("_SomeTex2 Albedo (RGB)", 2D) = "white" {}
    8.         _SomeTex3("_SomeTex3 Albedo (RGB)", 2D) = "white" {}
    9.     }
    10.     SubShader {
    11.         Tags { "RenderType"="Opaque" }
    12.         LOD 200
    13.  
    14.         CGPROGRAM
    15.         // Physically based Standard lighting model, and enable shadows on all light types
    16.         #pragma surface surf Standard fullforwardshadows
    17.  
    18.         // Use shader model 3.0 target, to get nicer looking lighting
    19.         #pragma target 5.0
    20.  
    21.         UNITY_DECLARE_TEX2D(_SomeTex);
    22.         UNITY_DECLARE_TEX2D_NOSAMPLER(_SomeTex2);
    23.         UNITY_DECLARE_TEX2D_NOSAMPLER(_SomeTex3);
    24.  
    25.         struct Input
    26.         {
    27.             float2 uv_SomeTex;
    28.         };
    29.  
    30.         void surf(Input IN, inout SurfaceOutputStandard o)
    31.         {
    32.             float2 UV = IN.uv_SomeTex;
    33.  
    34.             float4 someTex = UNITY_SAMPLE_TEX2D(_SomeTex, UV);
    35.             float4 someTex2 = UNITY_SAMPLE_TEX2D_SAMPLER(_SomeTex2, _SomeTex, UV);
    36.             float4 someTex3 = UNITY_SAMPLE_TEX2D_SAMPLER(_SomeTex3, _SomeTex, UV);
    37.  
    38.             // Error on using someTex2
    39.             o.Albedo = someTex2;
    40.  
    41.             //Do whatever else
    42.         }
    43.  
    44.         ENDCG
    45.     }
    46.     FallBack "Diffuse"
    47. }
    48.  

     
    Last edited: Dec 24, 2017
  13. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Try importing the shader into a fresh project, it might be a shader compile bug, as I notice the error message is saying no "sampler_sometex2" with no capital "T" in it, which your shader doesn't have, so that's strange...
     
  14. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Unfortunately its a Shaderlap bug because of optimization.

    This works fine without an error
    o.Albedo = someTex2 + someTex1;

    This does not work again
    someTex1 = 0;
    o.Albedo = someTex2 + someTex1;

    This works fine without an error again
    someTex1 = 0.001;
    o.Albedo = someTex2 + someTex1;

    Code (csharp):
    1. Shader "Custom/sampleTex2D" {
    2.    Properties{
    3.        _Color("Color", Color) = (1,1,1,1)
    4.        _MainTex("Albedo (RGB)", 2D) = "white" {}
    5.        _Glossiness("Smoothness", Range(0,1)) = 0.5
    6.        _Metallic("Metallic", Range(0,1)) = 0.0
    7.        _SomeTex("_SomeTex Albedo (RGB)", 2D) = "white" {}
    8.        _SomeTex2("_SomeTex2 Albedo (RGB)", 2D) = "white" {}
    9.    }
    10.        SubShader{
    11.        Tags{ "RenderType" = "Opaque" }
    12.        LOD 200
    13.        CGPROGRAM
    14. #pragma surface surf Standard fullforwardshadows
    15. #pragma target 5.0
    16.    UNITY_DECLARE_TEX2D(_SomeTex);
    17.    UNITY_DECLARE_TEX2D_NOSAMPLER(_SomeTex2);
    18.   struct Input
    19.    {
    20.        float2 uv_SomeTex;
    21.    };
    22.    void surf(Input IN, inout SurfaceOutputStandard o)
    23.    {
    24.        float2 UV = IN.uv_SomeTex;
    25.  
    26.        float4 someTex1 = UNITY_SAMPLE_TEX2D(_SomeTex, UV);
    27.        float4 someTex2 = UNITY_SAMPLE_TEX2D_SAMPLER(_SomeTex2, _SomeTex, UV);
    28.  
    29.        // Error on:  o.Albedo = someTex2;
    30.        // No Error on: o.Albedo = someTex2 + someTex1;
    31.        // Again Error on:  someTex1 =0; o.Albedo = someTex2 + someTex1;
    32.        o.Albedo = someTex2 + someTex1;
    33.       //Do whatever else
    34.    }
    35.    ENDCG
    36.    }
    37.    FallBack "Diffuse"
    38. }
    I cannot get rid of the error. :confused:+:confused:+:confused:
     
    Last edited: Dec 29, 2017
    R2-RT likes this.
  15. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    I'd at least try making your casting explicit.... I've seen surface shaders complain about that sort of thing before.

    Code (csharp):
    1. o.Albedo = someTex2.xyz + someTex1.xyz;
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    That won't be the Surface Shader itself complaining, that'll be the shader compiler when compiling the generated shader. Different shader compilers are more or less strict about vector sizes. Android, Mac OpenGL, and to a lesser extent AMD are known for being quite strict about making sure the vector components match up, where as Nvidia will happily throw away (or sometimes fill in values) if they don't line up, to make sure the shader compiles, but not always producing the results you expect.

    Sometimes there are issues with Surface Shaders excessively optimizing stuff, like with texture uvs, but in this case this is the shader compiler throwing an error and not anything Shader Lab or Surface Shader specific. By not using the _SomeTex, or by multiplying it by an in shader constant of zero, the shader compiler correctly assumes you're not using the texture at all and will simply skip it. However this means Unity skips the creation of the sampler itself since there's no longer any texture to pass. Ultimately there's not actually a bug here, you can't setup a sampler for a texture if that texture is not not being used as the sampler won't know what state it needs to be in. The state of a sampler comes from the texture asset. While the error might be annoying, the shader compiler is correct here and saying "you shouldn't do that".

    So there are a few solutions.

    The simplest solution is if you're not going to use _SomeTex, don't try to use it's sampler. Use _SomeTex2 instead, or another texture you do know you're going to use.

    The brute force solution is something you got close to with that *= 0.001; line. You can multiply the value by something very small, like 0.00001, or do someTex1 = saturate(someTex1 - 1.0); which will ensure a value of zero, or multiply it by a material float parameter set to zero. In these cases you can remove the texture's effect on the output with out it being optimized away ... but that also means you're still paying the cost of that texture being sampled. Don't do this.

    Possibly the "best" option is simply define your own inline sampler state in the shader. This lets you setup a sampler you can reuse for all of your textures, and if you decide to not use a texture it won't cause the shader compiler to get upset since no texture is necessary for the sampler to exist, only the use of the sampler matters. However this does have one draw back in that you can't control the quality of the sampling from the game's quality settings as it's explicitly defined in the shader, like enabling or disabling anisotropic filtering. I don't know if you can support anisotropic filtering with Unity's inline sampler states. There's also some hassle with using inline sampler states with Surface Shaders since it doesn't respect #pragma exclude_renderers or #pragma target and will still try to compile the shader for older APIs that don't support inline sampler states
    https://docs.unity3d.com/Manual/SL-SamplerStates.html

    So, my personal recommendation is to use the simple solution. Don't use the sampler from a texture you're not using.
     
    Last edited: Dec 30, 2017
    AshwinMods, R2-RT and Quatum1000 like this.
  17. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Thanks for your great explanation!
    A by side question. Further I'd like to use the sampler states to hold a lot of textures in VRAM with one Material only at runtime to prevent swapping them and reduce bandwidth.

    Would openGL load the Textures into the VRAM if they simply declared in the shader by UNITY_DECLARE_TEX2D(_Tex); or a inline sampler state.. (and for sure use on a material visible by the cam) ?

    Or would the textures load into VRAM only, if they addressed through any UNITY_SAMPLE_TEX2D() or tex2D(), etc. command?
     
  18. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    If the texture is not actually accessed and used somewhere in the body of the vertex or fragment functions, it will be excluded. You must call tex2D() or similar on a texture and have it contribute to the output color value.

    In all honesty you're probably better off not reusing samplers for this purpose, you're not really saving any bandwidth by reusing them, you may in fact just be adding additional bandwidth bottlenecks. My suggestion would be to use a simple vertex fragment shader with 16 texture slots, each using a sampler2D, and set it to be alpha blended with the output alpha to zero. Render this on a quad as small as possible, but that you can be sure is still at least 1 pixel on screen. If you want to be fancy you can render it once with different textures assigned each frame until you run out, or several times. Too many at once, regardless of if you use a single shader that can load 1000 textures, or multiple materials with different textures set, the biggest bandwidth hog is simply going to be the textures uploading themselves.

    Also, the sampler states in themselves hold no texture information, they are literally only the state the sampler should be in when it reads the textures. The sampler itself is a physical part of the GPU itself that gets set to a state when the shader stage is started, is fed (a part of) the texture during the execution of the shader, and hands back a value after a few cycles for the shader to use. If you use one sampler state for multiple textures, the same physical sampler gets used for all of those textures and it'll take longer to sample them all than if you use all 16 samplers in parallel.
     
    Last edited: Dec 30, 2017
    AshwinMods and Quatum1000 like this.
  19. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Wondering there is no gpu side command to hold textures or meshes in memory. The newer desktop cards own a lot VRAM but meshes and texture get unloaded from the VRAM if they are out of the frustum. Seems a old days behavior to keep memory usage low as possible and benefit from the fast north bridge.
     
  20. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Why not use a texture array if you're going to be dealing with a lot of them and need any number of them to be instantly accessable?
     
  21. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    A texture array has some limitations like needing all textures in the array to be the same size and format. It also means you have to make all your other shaders use arrays since the data in the arrays is not the same as the data in individual textures.

    It’s not instant, the texture data still has to be uploaded like any other. Using a texture array doesn’t necessarily mean every index in the array gets loaded when one does, likely only the indices that get accessed do, and those that aren’t used may get unloaded. A texture array is more like an abstraction to access many individual textures than it is a group of textures in itself, at least as far as the GPU is concerned. It also has the same inherent problem as reusing a single sampler to access multiple textures in that it’s likely slower than using all 16 samplers in parallel, though you could just assign the same texture array to 16 texture inputs or use inline sampler states to get around that.

    None that I know of, at least with DX11 or OpenGL. Might be something for DX12 or Vulkan since memory management is much more manually exposed, but I don’t think there’s anyway to get access to those things through Unity. However I’m a little surprised that the textures are getting unloaded as soon as they’re out of view, to me that sounds more like there’s some significant memory usage happening that’s causing the drivers to do that. It’s certainly not the behavior I’ve seen on games I’ve worked on, usually it seems like once the textures are loaded they never get removed, though the games I’ve worked on lately are often small enough that the entire game could get loaded into GPU ram with out running out.
     
    Quatum1000 likes this.
  22. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    328
    Example of using more than 16 textures in Surface Shader (works properly in Unity 2018.4.28 and Unity 2019.4.8). In both cases, to get correct values from uv_texcoord, it seems we have to pass them also to the dummy function and use into one of render target. For example, to see a difference, replace:
    o.Smoothness = ReturnZero(i.uv_texcoord);
    with
    o.Smoothness = 0.5;

    Code (CSharp):
    1. /*
    2.     Surface shader uses 24 textures and blends them, with 1 texture sampler.
    3.     To enable anisotropic filtering, set "aniso level" to 16 in import settings
    4.     for texture assigned to first slot (Texture 01).
    5.     To get correct values from uv_texcoord, it seems we have to pass them also to
    6.     the dummy function and use into one of render target (for example o.Normal, o.Smoothness etc).
    7.     To see a difference, replace:
    8.     o.Smoothness = ReturnZero(i.uv_texcoord);
    9.     with
    10.     o.Smoothness = 0.5;
    11. */
    12.  
    13. Shader "Metallic"
    14. {
    15.     Properties
    16.     {
    17.         _Texture01 ("Texture 01", 2D) = "black" {}
    18.         _Texture02 ("Texture 02", 2D) = "black" {}
    19.         _Texture03 ("Texture 03", 2D) = "black" {}
    20.         _Texture04 ("Texture 04", 2D) = "black" {}
    21.         _Texture05 ("Texture 05", 2D) = "black" {}
    22.         _Texture06 ("Texture 06", 2D) = "black" {}
    23.         _Texture07 ("Texture 07", 2D) = "black" {}
    24.         _Texture08 ("Texture 08", 2D) = "black" {}
    25.         _Texture09 ("Texture 09", 2D) = "black" {}
    26.         _Texture10 ("Texture 10", 2D) = "black" {}
    27.         _Texture11 ("Texture 11", 2D) = "black" {}
    28.         _Texture12 ("Texture 12", 2D) = "black" {}
    29.         _Texture13 ("Texture 13", 2D) = "black" {}
    30.         _Texture14 ("Texture 14", 2D) = "black" {}
    31.         _Texture15 ("Texture 15", 2D) = "black" {}
    32.         _Texture16 ("Texture 16", 2D) = "black" {}
    33.         _Texture17 ("Texture 17", 2D) = "black" {}
    34.         _Texture18 ("Texture 18", 2D) = "black" {}
    35.         _Texture19 ("Texture 19", 2D) = "black" {}
    36.         _Texture20 ("Texture 20", 2D) = "black" {}
    37.         _Texture21 ("Texture 21", 2D) = "black" {}
    38.         _Texture22 ("Texture 22", 2D) = "black" {}
    39.         _Texture23 ("Texture 23", 2D) = "black" {}
    40.         _Texture24 ("Texture 24", 2D) = "black" {}
    41.         [HideInInspector] _texcoord( "", 2D ) = "black" {}
    42.     }
    43.  
    44.     Subshader
    45.     {
    46.         CGPROGRAM
    47.         #pragma target 5.0
    48.         #pragma surface SurfaceShader Standard fullforwardshadows addshadow
    49.  
    50.         #ifdef SHADER_API_D3D11
    51.             Texture2D _Texture01,_Texture02,_Texture03,_Texture04,_Texture05,_Texture06,_Texture07,_Texture08;
    52.             Texture2D _Texture09,_Texture10,_Texture11,_Texture12,_Texture13,_Texture14,_Texture15,_Texture16;
    53.             Texture2D _Texture17,_Texture18,_Texture19,_Texture20,_Texture21,_Texture22,_Texture23,_Texture24;
    54.             SamplerState sampler_Texture01;
    55.         #endif
    56.  
    57.         struct Input
    58.         {
    59.             float2 uv_texcoord;
    60.         };
    61.  
    62.         float ReturnZero(float2 p)
    63.         {
    64.             return (p.x == 171076.61627) ? 1.0 : 0.0;
    65.         }
    66.  
    67.         void SurfaceShader (Input i, inout SurfaceOutputStandard o)
    68.         {
    69.             float4 albedo = 0;
    70.             #ifdef SHADER_API_D3D11
    71.                 albedo += _Texture01.Sample(sampler_Texture01, i.uv_texcoord);
    72.                 albedo += _Texture02.Sample(sampler_Texture01, i.uv_texcoord);
    73.                 albedo += _Texture03.Sample(sampler_Texture01, i.uv_texcoord);
    74.                 albedo += _Texture04.Sample(sampler_Texture01, i.uv_texcoord);
    75.                 albedo += _Texture05.Sample(sampler_Texture01, i.uv_texcoord);
    76.                 albedo += _Texture06.Sample(sampler_Texture01, i.uv_texcoord);
    77.                 albedo += _Texture07.Sample(sampler_Texture01, i.uv_texcoord);
    78.                 albedo += _Texture08.Sample(sampler_Texture01, i.uv_texcoord);
    79.                 albedo += _Texture09.Sample(sampler_Texture01, i.uv_texcoord);
    80.                 albedo += _Texture10.Sample(sampler_Texture01, i.uv_texcoord);
    81.                 albedo += _Texture11.Sample(sampler_Texture01, i.uv_texcoord);
    82.                 albedo += _Texture12.Sample(sampler_Texture01, i.uv_texcoord);
    83.                 albedo += _Texture13.Sample(sampler_Texture01, i.uv_texcoord);
    84.                 albedo += _Texture14.Sample(sampler_Texture01, i.uv_texcoord);
    85.                 albedo += _Texture15.Sample(sampler_Texture01, i.uv_texcoord);
    86.                 albedo += _Texture16.Sample(sampler_Texture01, i.uv_texcoord);
    87.                 albedo += _Texture17.Sample(sampler_Texture01, i.uv_texcoord);
    88.                 albedo += _Texture18.Sample(sampler_Texture01, i.uv_texcoord);
    89.                 albedo += _Texture19.Sample(sampler_Texture01, i.uv_texcoord);
    90.                 albedo += _Texture20.Sample(sampler_Texture01, i.uv_texcoord);
    91.                 albedo += _Texture21.Sample(sampler_Texture01, i.uv_texcoord);
    92.                 albedo += _Texture22.Sample(sampler_Texture01, i.uv_texcoord);
    93.                 albedo += _Texture23.Sample(sampler_Texture01, i.uv_texcoord);
    94.                 albedo += _Texture24.Sample(sampler_Texture01, i.uv_texcoord);
    95.                 albedo = albedo / 24.0;
    96.             #endif
    97.             o.Albedo = albedo;
    98.             o.Normal = float3(0,0,1);
    99.             o.Metallic = 0.0;
    100.             o.Smoothness = ReturnZero(i.uv_texcoord);
    101.         }
    102.  
    103.         ENDCG
    104.     }
    105. }
     
    FM-Productions likes this.