We’ve been working for a while on a planetary shader for rendering the Earth. I’ve posted our solution (in two parts: a planet shader and a clouds shader) below; the planet shader is also posted to the Unify Community Wiki.
You can download an asset bundle with the shaders and textures here.
Version 1 of this shader was created using the Strumpy Shader Editor. The original tutorial for creating the earth (minus night lights and night-side coloring) can be found here. The shader was then modified for nighttime lights and coloring.
This shader was created for the TerraViz project and may be considered open source with attribution.
Day and night lighting.
The night side of the earth is ever-so-slightly desaturated (greyed-out) and tinted blue. Both of these effects are very subtle, so feel free to play with these numbers. The corresponding lines are:
c.g -= .01 * s.Alpha; //lower green by .01 on the dark side - desaturate c.r -= .03 * s.Alpha; //lower red by .03 on the dark side - desaturate c.b = saturate(c.b + s.Alpha * .02); //raise blue by .02; saturate() clamps the value between 0 and 1 |
Night lights.
Lights appear on the dark side and fade in during ‘dusk’. The code that sets this is
half invdiff = 1 - saturate(16 * diff); //change the '16' to adjust how far dusk should extend) |
Lights are tinted slightly yellow. The two lines below apply the rgb of the lights to the world:
c.rg += min(s.Custom, s.Alpha); c.b += 0.75 * min(s.Custom, s.Alpha); |
If you want the lights to be white, just get rid of the ‘c.b’ line and make the other line ‘c.rgb’. If you want them bright yellow, get rid of the ‘c.b’ line with no change to the other line.
Bump map
Supports a bump map for mountains and other features. The bump is taken into account with night lights (e.g. cities that are behind mountains ‘turn on’ earlier than those atop mountains – each changes when it becomes ‘dark.’
Atmospheric shading
A slight light scattering due to the atmosphere is created at the edges of the planet. The color and intensity can be set from the inspector.
If you’re looking for Earth textures to use with this shader, we used Blue Marble (from NASA) as the Earth texture. You can find black & white topo images (which you can import to Unity as bump maps) and nighttime lights many places; here‘s an example.
You can also download an asset bundle with the shader and sample textures here.
Shader "TerraViz/Earth-NightLights" { //Earth Shader created by Julien Lynge @ Fragile Earth Studios //Upgrade of a shader originally put together in Strumpy Shader Editor by Clamps //Feel free to use and share this shader, but please include this attribution Properties { _MainTex("_MainTex", 2D) = "black" {} _Normals("_Normals", 2D) = "black" {} _Lights("_Lights", 2D) = "black" {} _LightScale("_LightScale", Float) = 1 _AtmosNear("_AtmosNear", Color) = (0.1686275,0.7372549,1,1) _AtmosFar("_AtmosFar", Color) = (0.4557808,0.5187039,0.9850746,1) _AtmosFalloff("_AtmosFalloff", Float) = 3 } SubShader { Tags { "Queue"="Geometry" "IgnoreProjector"="False" "RenderType"="Opaque" } Cull Back ZWrite On ZTest LEqual ColorMask RGBA Fog{ } CGPROGRAM #pragma surface surf BlinnPhongEditor #pragma target 2.0 sampler2D _MainTex; sampler2D _Normals; sampler2D _Lights; float _LightScale; float4 _AtmosNear; float4 _AtmosFar; float _AtmosFalloff; struct EditorSurfaceOutput { half3 Albedo; half3 Normal; half3 Emission; half3 Gloss; half Specular; half Alpha; half4 Custom; }; inline half4 LightingBlinnPhongEditor_PrePass (EditorSurfaceOutput s, half4 light) { half3 spec = light.a * s.Gloss; half4 c; c.rgb = (s.Albedo * light.rgb + light.rgb * spec); c.g -= .01 * s.Alpha; c.r -= .03 * s.Alpha; c.rg += min(s.Custom, s.Alpha); c.b += 0.75 * min(s.Custom, s.Alpha); c.b = saturate(c.b + s.Alpha * .02); c.a = 1.0; return c; } inline half4 LightingBlinnPhongEditor (EditorSurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { half3 h = normalize (lightDir + viewDir); half diff = max (0, dot ( lightDir, s.Normal )); float nh = max (0, dot (s.Normal, h)); float spec = pow (nh, s.Specular*128.0); half4 res; res.rgb = _LightColor0.rgb * diff; res.w = spec * Luminance (_LightColor0.rgb); res *= atten * 2.0; //s.Alpha is now 1 where the earth is dark. The value of night lights has been saved to Alpha half invdiff = 1 - saturate(16 * diff); s.Alpha = invdiff; return LightingBlinnPhongEditor_PrePass( s, res ); } struct Input { float3 viewDir; float2 uv_MainTex; float2 uv_Normals; float2 uv_Lights; }; void surf (Input IN, inout EditorSurfaceOutput o) { o.Gloss = 0.0; o.Specular = 0.0; o.Custom = 0.0; o.Alpha = 1.0; float4 Fresnel0_1_NoInput = float4(0,0,1,1); float4 Fresnel0=(1.0 - dot( normalize( float4( IN.viewDir.x, IN.viewDir.y,IN.viewDir.z,1.0 ).xyz), normalize( Fresnel0_1_NoInput.xyz ) )).xxxx; float4 Pow0=pow(Fresnel0,_AtmosFalloff.xxxx); float4 Saturate0=saturate(Pow0); float4 Lerp0=lerp(_AtmosNear,_AtmosFar,Saturate0); float4 Multiply1=Lerp0 * Saturate0; float4 Sampled2D2=tex2D(_MainTex,IN.uv_MainTex.xy); float4 Add0=Multiply1 + Sampled2D2; float4 Sampled2D0=tex2D(_Normals,IN.uv_Normals.xy); float4 UnpackNormal0=float4(UnpackNormal(Sampled2D0).xyz, 1.0); o.Albedo = Add0; o.Normal = UnpackNormal0; //o.Emission = Multiply0; o.Emission = 0.0; //float4 Multiply0=Sampled2D1 * _LightScale.xxxx; o.Custom = tex2D(_Lights,IN.uv_Lights.xy).r * _LightScale; o.Normal = normalize(o.Normal); } ENDCG } Fallback "Diffuse" } |
The much simpler companion to the planet shader. This shader is a simple alpha diffuse shader with some additional coloration on the night side.
This shader was created for the TerraViz project and may be considered open source with attribution.
Night coloring
The clouds on the night side of the earth are ever-so-slightly desaturated (greyed-out) and tinted blue. This effect is very subtle, so feel free to play with the numbers. The corresponding lines are:
void nightcolor (Input IN, SurfaceOutput o, inout fixed4 color) { color.r = saturate(o.Albedo.r - (o.Albedo.r - color.r) * 1.1); color.g = saturate(o.Albedo.g - (o.Albedo.g - color.g) * 1.05); //color.rgb = saturate(o.Albedo - (o.Albedo - color.rgb) * 1.1); } |
The nightcolor function is a final color application that lowers the red and green color by an amount relative to how much shadow has been applied (by a factor of around 10% and 5% respectively). If you wish to darken the clouds uniformly, remove lines 3 & 4 and uncomment line 5.
Global clouds can be a bit tricky to find. There are a few websites out there with greyscale clouds (try this site). Under the Unity texture import settings, select ‘Generate alpha from greyscale.’ to give these greyscale images transparency. Alternatively, you can use the images as a mask in programs like Photoshop or GIMP on a white image to create a semitransparent cloud image.
You can also download an asset bundle with the shaders and textures here.
Shader "TerraViz/Clouds" { Properties { _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {} } SubShader { Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} LOD 200 Offset -1, -2 CGPROGRAM #pragma surface surf Lambert finalcolor:nightcolor alpha sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } void nightcolor (Input IN, SurfaceOutput o, inout fixed4 color) { color.r = saturate(o.Albedo.r - (o.Albedo.r - color.r) * 1.1); color.g = saturate(o.Albedo.g - (o.Albedo.g - color.g) * 1.05); //color.rgb = saturate(o.Albedo - (o.Albedo - color.rgb) * 1.1); } ENDCG } Fallback "Transparent/VertexLit" } |
Any chance of putting together a Unity package so mere mortals can try out your code? Just an empty scene with a sphere and enough assets to support your shaders?
Happily. There’s now a link at the top of this page to a project with all the textures and a sample scene.