Skip to main content
Bumped by Community user
Mod Moved Comments To Chat
added 3701 characters in body
Source Link
Serg
  • 393
  • 5
  • 19

This is a simplified shader example (here I use colors instead of light/shadow effect and only 2 sides instead of 4):

Shader "Test/UnlitTest"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _TopColor ("TopColor", Color) = (1, 0, 0, 1)
        _BottomColor ("_BottomColor", Color) = (0, 0, 1, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        ZTest Off
        ZWrite Off
        Lighting Off
        Cull Off
        Fog { Mode Off }

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            fixed4 _TopColor, _BottomColor;            

            struct vertData
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;    
            };

            struct fragData
            {
                float2 uv : TEXCOORD0;
                float2 uvW : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            fragData vert (vertData v)
            {
                fragData f;
                f.vertex = UnityObjectToClipPos(v.vertex);
                f.uv = TRANSFORM_TEX(v.uv, _MainTex);
                f.uvW = mul(unity_ObjectToWorld, f.uv);
                return f;
            }

            fixed isTransparentPixel(fixed2 uv)
            {
                return step(tex2D(_MainTex, uv).a, 0.0);
            }

            fixed isEdgePixel(fixed2 uv)
            {
                uv = mul(unity_WorldToObject, uv); // back to object space
                return isTransparentPixel(uv);
            }

            fixed4 frag (fragData f) : SV_Target
            {
                fixed isTransparent = isTransparentPixel(f.uv);
                clip(-isTransparent);
                
                fixed4 c = tex2D(_MainTex, f.uv);
                float2 borderSize = float2(3, 3); // border size in tex pixels
                float dy = borderSize.y * _MainTex_TexelSize.y;
                fixed3 borderColor = fixed3(0, 0, 0);
                float borderColorsCount = 0;
                float2 uvW = f.uvW; // UV in the world space

                // Top edge:
                fixed isEdge = isEdgePixel(uvW + float2(0, dy));
                borderColor += isEdge * _TopColor.rgb;
                borderColorsCount += isEdge;

                // Bottom edge:
                isEdge = isEdgePixel(uvW + float2(0, -dy));
                borderColor += isEdge * _BottomColor.rgb;
                borderColorsCount += isEdge;

                fixed noBorderColor = step(length(borderColor), 0);
                fixed hasBorderColor = 1 - noBorderColor;
                c.rgb = c.rgb * noBorderColor + hasBorderColor * borderColor / max(borderColorsCount, 1);
                return c;
            }
            ENDCG
        }
    }
}

It gets a semi-transparent image as a texture. The image is completely transparent at the edges and contains an opaque shape in the center.

enter image description here

The shader colors the top edges of the non-transparent shape in red and the bottom ones in yellow. It uses unity_WorldToObject & unity_ObjectToWorld to check the edges facing directions in the world space.

enter image description here enter image description here


This is a simplified shader example (here I use colors instead of light/shadow effect and only 2 sides instead of 4):

Shader "Test/UnlitTest"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _TopColor ("TopColor", Color) = (1, 0, 0, 1)
        _BottomColor ("_BottomColor", Color) = (0, 0, 1, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        ZTest Off
        ZWrite Off
        Lighting Off
        Cull Off
        Fog { Mode Off }

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            fixed4 _TopColor, _BottomColor;            

            struct vertData
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;    
            };

            struct fragData
            {
                float2 uv : TEXCOORD0;
                float2 uvW : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            fragData vert (vertData v)
            {
                fragData f;
                f.vertex = UnityObjectToClipPos(v.vertex);
                f.uv = TRANSFORM_TEX(v.uv, _MainTex);
                f.uvW = mul(unity_ObjectToWorld, f.uv);
                return f;
            }

            fixed isTransparentPixel(fixed2 uv)
            {
                return step(tex2D(_MainTex, uv).a, 0.0);
            }

            fixed isEdgePixel(fixed2 uv)
            {
                uv = mul(unity_WorldToObject, uv); // back to object space
                return isTransparentPixel(uv);
            }

            fixed4 frag (fragData f) : SV_Target
            {
                fixed isTransparent = isTransparentPixel(f.uv);
                clip(-isTransparent);
                
                fixed4 c = tex2D(_MainTex, f.uv);
                float2 borderSize = float2(3, 3); // border size in tex pixels
                float dy = borderSize.y * _MainTex_TexelSize.y;
                fixed3 borderColor = fixed3(0, 0, 0);
                float borderColorsCount = 0;
                float2 uvW = f.uvW; // UV in the world space

                // Top edge:
                fixed isEdge = isEdgePixel(uvW + float2(0, dy));
                borderColor += isEdge * _TopColor.rgb;
                borderColorsCount += isEdge;

                // Bottom edge:
                isEdge = isEdgePixel(uvW + float2(0, -dy));
                borderColor += isEdge * _BottomColor.rgb;
                borderColorsCount += isEdge;

                fixed noBorderColor = step(length(borderColor), 0);
                fixed hasBorderColor = 1 - noBorderColor;
                c.rgb = c.rgb * noBorderColor + hasBorderColor * borderColor / max(borderColorsCount, 1);
                return c;
            }
            ENDCG
        }
    }
}

It gets a semi-transparent image as a texture. The image is completely transparent at the edges and contains an opaque shape in the center.

enter image description here

The shader colors the top edges of the non-transparent shape in red and the bottom ones in yellow. It uses unity_WorldToObject & unity_ObjectToWorld to check the edges facing directions in the world space.

enter image description here enter image description here

Source Link
Serg
  • 393
  • 5
  • 19

Is it possible to get object rotation in a shader for dynamically batched objects?

All the batched objects have the same rotation. To simulate the effect of directional light I need to determine the object sides actual (world) directions. Normally I would use unity_ObjectToWorld & unity_ObjectToWorld for that, which is not possible when the objects are batched.

Is it possible to pass the object rotation to the shader in one action (since it's the same for all of them) without breaking the batching?