0
\$\begingroup\$

I am experimenting with Unity and wanted to project a unit circle beneath a unit and my very first naive approach was to create a child plane below the unit, assign the material to it and stretch it using the Pro Builder UV editor but it looked horrible:

enter image description here

In order to figure out what's wrong I read a lot of various approaches to "fix" that issue which were mostly the following:

  • use a higher resolution for the texture
  • do not use any compression
  • do not use a POT resolution
  • change the filtering option from bilinear to point
  • ...

Eventually I figured that I have to do something completely different and that is how I stumbled upon the idea to use a shader attached to a projector game object in order to project a material. Unfortunately though it turns out the shader expects a grayscale image and only tints the projection based on a parameter. For reference this is the shader I have just copied from the web (source):

Shader "Projector/AdditiveTint" {
    Properties {
        _Color ("Tint Color", Color) = (1,1,1,1)
        _Attenuation ("Falloff", Range(0.0, 1.0)) = 1.0
        _ShadowTex ("Cookie", 2D) = "gray" {}
    }
    Subshader {
        Tags {"Queue"="Transparent"}
        Pass {
            ZWrite Off
            ColorMask RGB
            Blend SrcAlpha One // Additive blending
            Offset -1, -1

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f {
                float4 uvShadow : TEXCOORD0;
                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);
                return o;
            }

            sampler2D _ShadowTex;
            fixed4 _Color;
            float _Attenuation;

            fixed4 frag (v2f i) : SV_Target
            {
                // Apply alpha mask
                fixed4 texCookie = tex2Dproj (_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
                fixed4 outColor = _Color * texCookie.a;
                // Attenuation
                float depth = i.uvShadow.z; // [-1 (near), 1 (far)]
                return outColor * clamp(1.0 - abs(depth) + _Attenuation, 0.0, 1.0);
            }
            ENDCG
        }
    }
}

With that shader I was able to render the following effect:

enter image description here

Since I have no experience with shaders at all I just blatantly copy & pasted it and do not know (yet) how to customize them or even write custom ones in the first place.

Assuming my approach to combine a projector with such a shader is the way to go, I'd like to know whether there is any shader you can share that allows me to project an unlit texture with transparency and its own color such as the following example:

enter image description here

\$\endgroup\$
  • 2
    \$\begingroup\$ For an effect like this, unless you're trying to conform to a bumpy ground surface, I'd say your first solution of using quad was a better choice than a projector. Projectors don't do any special magic that solves pixelation or compression, and touching up your asset & shader can give you wins as great or greater with a simple flat UV-mapped quad. \$\endgroup\$ – DMGregory May 27 '18 at 6:20
  • \$\begingroup\$ @DMGregory Unfortunately with all suggestions as to how to fix the blurry/fuzzy texture on a plane I wasn't able to fix it at all. I tried almost everything possible from colors, compression, file format, filtering - it's just that I don't understand what is wrong since I am just starting out. And with regards to the bumpy surface: even though It won't be that bumpy in my case I'd appreaciate a solution like the current one that projects the texture on a specified layer. \$\endgroup\$ – Christian Ivicevic May 27 '18 at 10:34
1
\$\begingroup\$

After a lot of research I finally found a shader, that for the time being, does what I want to which was described in the Unity forums. The corresponding shader code is the following:

Shader "Projector/Tattoo" {
    Properties {
        _ShadowTex("Cookie", 2D) = "white" {}
    }

    Subshader {
        Tags {
            "RenderType" = "Transparent"
            "Queue" = "Transparent+100"
        }
        Pass {
            ZWrite Off
            Offset -1, -1

            Fog{ Mode Off }

            ColorMask RGB
            Blend OneMinusSrcAlpha SrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_fog_exp2
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 uv : TEXCOORD0;
            };

            sampler2D _ShadowTex;
            float4x4 unity_Projector;
            float4 _Color;

            v2f vert(appdata_tan v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = mul(unity_Projector, v.vertex);
                return o;
            }

            half4 frag(v2f i) : COLOR
            {
                half4 tex = tex2Dproj(_ShadowTex, i.uv);
                tex.a = 1 - tex.a;
                if (i.uv.w < 0)
                {
                    tex = float4(0,0,0,1);
                }
                return tex;
            }
            ENDCG
        }
    }
}

Since I don't know anything about shaders I'd appreciate if you have optimziation suggestions.

\$\endgroup\$
0
\$\begingroup\$

Well, for my bullet hole shader I find the issue to remove the transparent alpha effect by changing my "Blend" with your "Blend OneMinusSrcAlpha SrcAlpha".

// Upgrade NOTE: replaced '_Projector' with 'unity_Projector'
// Upgrade NOTE: replaced '_ProjectorClip' with 'unity_ProjectorClip'

Shader "Projector/Multiply" {
    Properties {
        _ShadowTex ("Cookie", 2D) = "gray" {}
        _FalloffTex ("FallOff", 2D) = "white" {}
    }
    Subshader {
        Tags {"Queue"="Transparent"}
        Pass {
            ZWrite Off
            ColorMask RGB
            Blend OneMinusSrcAlpha SrcAlpha
            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,1), texS, texF.a);

                UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1,1,1,1));
                return res;
            }
            ENDCG
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

The unity standard assets contains a projector game object, material, and shader. Just drag into your scene, reposition, drag material into projector, and drag image into shader “cookie” field.

\$\endgroup\$
  • \$\begingroup\$ Can you change the color via code then? Would you do that by getting the material color and changing it? \$\endgroup\$ – user441521 Feb 27 at 18:17
  • \$\begingroup\$ You would have different “cookie” textures. So you would say have a red circle for enemies and green circle for allies. Then depending on the type of unit you would swap the cookie texture. \$\endgroup\$ – Adam B Feb 28 at 6:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.