D
D
Daniil Bakalin2017-11-11 06:20:05
Shaders
Daniil Bakalin, 2017-11-11 06:20:05

How to multiply textures in Unity shader?

Unity3D has a projector shader that allows you to project texture onto scene objects. I'm trying to add the ability to mask the projected image to this shader, but I don't have enough experience in creating shaders.
In a normal object shader, you can easily merge textures, but in a projector shader, tex2Dproj is used, and I can't figure it out in any way. In my opinion, the easiest way is to mix two textures in advance (image and mask), and place them in a separate texture, which is then applied to the object. But I can't figure out how to do it? Everywhere the option is considered when two textures are mixed and immediately displayed on the object, and I need to temporarily place the result in a third texture, and only then output ...
Of course, this can be done with a script, but I want to use a shader so that I can develop the approach, for example, by adding dynamic / rotating masks, etc.
Below is the code for the standard projector shader. I would be grateful for any advice. Thank you!

Shader Projector/Multiply
Shader "Projector/Multiply" {
  Properties {
    _ShadowTex ("Cookie", 2D) = "gray" {}
    _FalloffTex ("FallOff", 2D) = "white" {}
  }
  Subshader {
    Tags {"Queue"="Transparent"}
    Pass {
      ZWrite Off
      ColorMask RGB
      Blend DstColor Zero
      Offset -1, -1

      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      #pragma multi_compile_fog
      #include "UnityCG.cginc"
      
      struct v2f {
        float4 uvShadow : TEXCOORD0;
        float4 uvFalloff : TEXCOORD1;
        UNITY_FOG_COORDS(2)
        float4 pos : SV_POSITION;
      };
      
      float4x4 unity_Projector;
      float4x4 unity_ProjectorClip;
      
      v2f vert (float4 vertex : POSITION)
      {
        v2f o;
        o.pos = UnityObjectToClipPos (vertex);
        o.uvShadow = mul (unity_Projector, vertex);
        o.uvFalloff = mul (unity_ProjectorClip, vertex);
        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
      }
      
      sampler2D _ShadowTex;
      sampler2D _FalloffTex;
      
      fixed4 frag (v2f i) : SV_Target
      {
        fixed4 texS = tex2Dproj (_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
        texS.a = 1.0-texS.a;

        fixed4 texF = tex2Dproj (_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff));
        fixed4 res = lerp(fixed4(1,1,1,0), texS, texF.a);

        UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1,1,1,1));
        return res;
      }
      ENDCG
    }
  }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Daniil Basmanov, 2017-11-11
@Quiensabe

Shaders for spotlights work exactly the same, just the uv map is calculated differently:

Projector/Multiply
Shader "Projector/Multiply"
{
    Properties
    {
        _ShadowTex("Cookie", 2D) = "gray" {}
        _FalloffTex("FallOff", 2D) = "white" {}
        // Добавляем свойство
        _MaskTex("Mask", 2D) = "white" {}
    }
    Subshader
    {
        Tags {"Queue"="Transparent"}
        Pass
        {
            ZWrite Off
            ColorMask RGB
            Blend DstColor Zero
            Offset -1, -1

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float4 uvShadow : TEXCOORD0;
                float4 uvFalloff : TEXCOORD1;
                UNITY_FOG_COORDS(2)
                float4 pos : SV_POSITION;
            };
            
            float4x4 unity_Projector;
            float4x4 unity_ProjectorClip;
            
            v2f vert (float4 vertex : POSITION)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                o.uvShadow = mul(unity_Projector, vertex);
                o.uvFalloff = mul(unity_ProjectorClip, vertex);
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }
            
            sampler2D _ShadowTex;
            sampler2D _FalloffTex;
            // Добавляем переменную, чтобы использовать текстуру внутри прохода
            sampler2D _MaskTex;
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 texS = tex2Dproj(_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
                texS.a = 1.0 - texS.a;

                fixed4 texF = tex2Dproj(_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff));
                fixed4 res = lerp(fixed4(1, 1, 1, 0), texS, texF.a);

                // Сэмплируем текстуру
                fixed4 mask = tex2Dproj(_MaskTex, UNITY_PROJ_COORD(i.uvShadow));
                // Применяем маску
                res *= mask;

                UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1, 1, 1, 1));
                return res;
            }
            ENDCG
        }
    }
}

To better understand what uvShadow and uvFalloff are, you can display them in the fragment shader:
fixed4 frag (v2f i) : SV_Target
{
    float2 uvShadow = UNITY_PROJ_COORD(i.uvShadow);
    float2 uvFalloff = UNITY_PROJ_COORD(i.uvFalloff);
    return fixed4(uvShadow, 0.0, 1.0);
    //return fixed4(uvFalloff, 0.0, 1.0);
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question