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.
So far so good, but there is a problem the moment the camera moves a bit away.
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"
}