Search Unity

Question Shader with two textures and different color each

Discussion in 'Shaders' started by zmatiaki, Apr 1, 2021.

  1. zmatiaki

    zmatiaki

    Joined:
    Nov 21, 2018
    Posts:
    13
    Hi to community,

    I am working on a similar game like sims and I want to make wall textures with changing color capabilities.I am not using shader graphs cause I had some issues with batching so I desided to write my own shader. I am using below to pick colors via script

    Code (CSharp):
    1. var propBlock = new MaterialPropertyBlock();
    2.         this.gameObject.GetComponent<Renderer>().GetPropertyBlock(propBlock);
    3.         // Assign our new value.
    4.         _propBlock.SetColor("_Color", OrigColor);
    5.         // Apply the edited values to the renderer.
    6.         GetComponent<Renderer>().SetPropertyBlock(_propBlock);

    Let me explain what I need to achieve. In below picture I have a wall paint made in photoshop and I have made two textures : One for red , and one for white

    Code (CSharp):
    1. Shader "Custom/FloorBlock_settedProp" {
    2.     Properties{
    3.         _Color("Color", Color) = (1,1,1,1)
    4.         _ColorOverlay("ColorOverlay", Color) = (1,1,1,1)
    5.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    6.         _SecondaryTex("Overlay Texture Color (RGB) Alpha (A)", 2D) = "white" {}
    7.         [NoScaleOffset] _NormalMap("Normals", 2D) = "bump" {}
    8.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    9.         _Metallic("Metallic", Range(0,1)) = 0.0
    10.     }
    11.      
    12.         SubShader{
    13.  
    14.          
    15.             Tags { "RenderType" = "Opaque" }
    16.             LOD 200
    17.             CGPROGRAM
    18.             // Physically based Standard lighting model, and enable shadows on all light types
    19.             #pragma surface surf Standard fullforwardshadows
    20.             // Use Shader model 3.0 target
    21.             #pragma target 3.0
    22.             sampler2D _MainTex;
    23.             sampler2D _NormalMap;
    24.             //additional
    25.             sampler2D _SecondaryTex;
    26.          
    27.             struct Input {
    28.                 float2 uv_MainTex;
    29.                 //float2 uv_SecondTex;
    30.                 float2 uv_NormalMap;
    31.             };
    32.  
    33.             //additional          
    34.             //fixed4 _Color;
    35.  
    36.             half _Glossiness;
    37.             half _Metallic;
    38.             UNITY_INSTANCING_BUFFER_START(Props)
    39.                UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
    40.                 UNITY_DEFINE_INSTANCED_PROP(fixed4, _ColorOverlay)
    41.              
    42.             UNITY_INSTANCING_BUFFER_END(Props)
    43.             void surf(Input IN, inout SurfaceOutputStandard o) {
    44.  
    45.                 //additional
    46.                 float4 mainTex = tex2D(_MainTex, IN.uv_MainTex);
    47.                 float4 overlayTex = tex2D(_SecondaryTex, IN.uv_MainTex);
    48.                 half3 mainTexVisible = mainTex.rgb * (1 - overlayTex.a);
    49.                 half3 overlayTexVisible = overlayTex.rgb * (overlayTex.a);
    50.  
    51.                 //float3 finalColor = (mainTexVisible + overlayTexVisible) * _Color;
    52.  
    53.                 //Main              
    54.                 //fixed4 c = (tex2D(_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color) + tex2D(_SecondaryTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _ColorOverlay));
    55.                 //o.Albedo = c.rgb;
    56.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
    57.                 o.Albedo = lerp(UNITY_ACCESS_INSTANCED_PROP(Props, _Color), UNITY_ACCESS_INSTANCED_PROP(Props, _ColorOverlay), c.r);
    58.                 o.Metallic = _Metallic;
    59.                 o.Smoothness = _Glossiness;
    60.                 o.Alpha = c.a;
    61.                 o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
    62.             }          
    63.                    
    64.  
    65.             ENDCG
    66.         }
    67.  
    68.             FallBack "Diffuse"
    69. }
     

    Attached Files:

    Last edited: Apr 2, 2021
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Color_A5FB8792
    !=
    _Color
    ?

    Also you're just adding the two colored textures together. Presumably you want to lerp between them?
     
    zmatiaki likes this.
  3. zmatiaki

    zmatiaki

    Joined:
    Nov 21, 2018
    Posts:
    13
    Thanks bgolus for the reply.I have tested lerp and it works!

    Color_A5FB8792 was wrong as I was trying to use shader graph and havent change it (edit original post). I made some adjustments to the shader code as well and changed texture to the one bellow(red and green)
    upload_2021-4-2_2-12-7.png

    But I have another issue that I want your assist. Currently batching and color changing works great.
    If I want to change textures via script will the batch break (GPU Instancing)? Here is my material

    upload_2021-4-2_2-23-5.png


    I want the user to be able to choose from collection of textures and use them to paint the wall ,with the textures of his choise and colors tha he will pick. Is that possible without breaking batch? Where should I store textures?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You cannot change textures and retain either batching or instancing (which is different than batching). With instancing you can changed instanced numerical properties (float, vector, or color), but you cannot change textures. If you want to support changing textures with instancing you have to use a Texture2dArray and have one of the instanced properties be the layer index.

    Batching is when Unity merges several meshes together into a single mesh either at build time / starting play mode (static batching) or at run time (dynamic batching). For those you cannot change the material properties at all. Not even with a material property block.
     
    zmatiaki likes this.
  5. zmatiaki

    zmatiaki

    Joined:
    Nov 21, 2018
    Posts:
    13
    yes its still bit blur on my head as you can see! Ok I will leave batching out of equation for the moment as Instancing works great.

    So , regarding instancing!

    1.you have to use a texture array : texture arrays will be on the shader itself or on other script?(yep just started with shaders)
    2.instanced properties be the layer index : you are reffering to shader -> UNITY_DEFINE_INSTANCED_PROP etc?
    And what about layers? I only know the layers we use on inspector. Are others that are used for shaders?Keep in mind that wer are talking about more than 100 textures?

    Is possible to make material for each one and merge them on atlases..or something like that?
     
    Last edited: Apr 2, 2021
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    A texture array, or Texture2DArray, is a texture asset type. Basically it's a 3D texture where the z axis is treated as separate layers. If you're using 2020.2+ these can be imported from texture atlases. If you're using a Unity 2020.1 or older you have to create them with a custom script. After that they're just a texture asset you assign to the material, assuming your shader has a
    2DArray
    property to accept it and you change the rest of the shader code to handle it properly. You can search around on your own to find examples.
     
    zmatiaki likes this.
  7. zmatiaki

    zmatiaki

    Joined:
    Nov 21, 2018
    Posts:
    13
    Perfect bgolus!I would look into it this weekend and get back to discuss the results.
    thanks a lot for you assist
     
  8. zmatiaki

    zmatiaki

    Joined:
    Nov 21, 2018
    Posts:
    13
    I have managed to make a shader with Texture2DRay,index and colors for each channel(R,G,B) as predefined props and change index of shader with script,using Material property ike bellow. GPU - Instance works as charm.

    CubeText.gif

    I was thinking.. Is it better to have a shader with Texture2DRay and a script to pass index with the help of material properties(like above) or to have a Texture2DRay assigned to the script and pass texture to the shader with material property?

    The reason is, that I need to have 2xTexture2DRay(different dimmensions for each one) and I am thinking it may be easier to execute logic on script, than have shader with two Texture2DRay and decide inside shader which Texture2DRay to use. Any reccomendation ?