4
\$\begingroup\$

I have some basic shapes in the background of a scene that represent a small city. There is a stage where the scene becomes a nights scene. I would like to have the city come to life at night with some lights.

I know that I can use a texture with emissions to achieve this effect, but the texture is extremely repetitive and the lack of variation stands out. It is a bit boring, but works relatively well.

As I am trying to learn shaders, I thought it might be a good project to attempt. The shader just divides the UV and then draws a base color or a window color. It is also more random and lights could be switched on or off over time.

enter image description here

So far so good, but there is a problem the moment the camera moves a bit away. enter image description here enter image description here

It looks like there is some strolling or banding effect. The "lights" seem to flicker a lot. I think I understand why this is happening. Maybe because the pixels visible at that instant, that determine if its a window or wall just ends up all being walls ? Or the window is smaller than 1 pixel ?

Like I said, I am just starting with shaders and have no real clue what I am doing. Can this be done with a simple shader ?

Here is what I have so far:

Shader "Custom/EmeraldCityLights"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}  // These will not be used 
        _Glossiness ("Smoothness", Range(0,1)) = 0.5// These will not be used 
        _Metallic ("Metallic", Range(0,1)) = 0.0    // These will not be used 
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldNormal;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)



        float random2(float2 uv)
        {
            return  frac(sin(uv.x * 12.11 + uv.y * 88.44) * 4497.1546);
        }

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            //fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            half4 col = half4(0, .1, 0, 1.0);  // Building's base color
            half4 windowW = half4(1, 1, 1, 1.0);  // white window color
            half4 windowO = half4(.05, .05 ,.05, 1.0); // Windows that have no lights behind them (off)
            half4 windowY = half4(1, 1, .1, 1.0); // Yellow windows
            
            float2 t = IN.uv_MainTex;  // Get the UV x,y of this pixel

            float2 gt = float2(t.x * 12, t.y*20.5);  // Multiply to repeat the pattern. 12 windows by 20.5
            float2 gv = frac(gt);       //Use the frac part to draw this window.
            float2 windowID = float2((int)gt.x, (int)gt.y);  // the integer part is the windows index.

            float rnd = random2(windowID);  // get a random number based on this window's ID. All the pixels in this window will be the same color.

            fixed4 c =  lerp(lerp(windowW,windowY,rnd*1.429), windowO, step(0.7,rnd)) * 13.0; // if the random number is less than 0.7, the light is on.
                                                                                              // if the light is on, then lerp from white to yellow based on the random number.
                      
            c = lerp(col, c, step(abs(IN.worldNormal.g), 0));   // Get the pixel's world normal. if the normal points up or down, make it the building's base color
            c = lerp(col, c, step(0.15, gv.x)); // if this pixel is on the left edge of the window, make it the building's base color
            c = lerp(c, col, step(0.85, gv.x));// if this pixel is on the right edge of the window, make it the building's base color
            c = lerp(c, col, step(gv.y - .25,0.25 )); // if its at the top or bottom, make it the building's base color
            
             o.Albedo = c.rgb;

            // not used yet
            //o.Metallic = _Metallic;
            //o.Smoothness = _Glossiness;
            //o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ If you're seeking feedback on a shader, it's helpful to post the entire shader (rather than just some of the functions) so we can try it out. \$\endgroup\$ Commented Nov 3, 2023 at 2:34
  • \$\begingroup\$ @Kevin Thanks for the tip. I updated the code block. \$\endgroup\$ Commented Nov 3, 2023 at 7:16

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.