I created a customized skybox shader that includes a black sky with solely the moon and its halo. The moon responds realistically to the scene’s directional mild (daylight), which creates a convincing impact. Nonetheless, for a while now, I’ve been attempting to use the identical impact to the halo in order that it resembles the moon, but it surely hasn’t labored.
And I would like is to make the middle of the moon’s illuminated half the place of the middle of seen half from the halo, in order that the halo at all times seems centered on the lit portion of the moon, which might make it look extra life like — however all my makes an attempt have failed.
To manage the moon’s path and simulate life like lighting, I exploit a easy script that passes two parameters to the shader globally:
_MoonDir:
the moon’s ahead path in world area, used to orient the moon within the sky and decide its obvious place from the digital camera.
_MoonSpaceMatrix:
a metamorphosis matrix constructed from the moon’s proper, up, and ahead vectors. That is used to accurately rework normals into moon-local area and pattern the moon texture accordingly.
The script runs each body and ensures that the shader at all times receives the right orientation and alignment of the moon relative to the scene’s mild supply (sometimes the sun). This setup makes it attainable to use directional lighting to the moon floor.
Is it attainable to use daylight impact to the halo (as it’s performed for the moon) and align the middle of its seen half (after making use of the impact) with the middle of the moon’s illuminated space?
Notice:
I exploit Texture2D for each the moon and the halo to maintain the shader light-weight, as I intend to apply it to cellular units.
- The moon itself is simply rendered as a white circle — no texture element is required at the moment.
- The halo texture is an easy clear radial gradient:
Shader Code:
Shader "Skybox/SimpleSkybox_Moon"
{
Properties
{
_SkyColor ("Sky Coloration", Coloration) = (0,0,0,1)
(area(10))
(NoScaleOffset)_MoonTex ("Moon Texture 2D", 2D) = "white" {}
_MoonSize ("Moon Dimension", Vary(0.1,20)) = 9
_MoonTint ("Moon Tint", Coloration) = (1,1,1,1)
_MoonExposure ("Moon Publicity", Vary(-6,6)) = 1
(NoScaleOffset)_MoonHaloTex ("Moon Halo Texture 2D", 2D) = "white" {}
_MoonHaloSize ("Moon Halo Dimension", Vary(1, 10)) = 1.7
_MoonHaloExposure ("Moon Halo Publicity", Vary(-6, 6)) = -4
_MoonHaloFadeThreshold ("Moon Halo Fade Threshold", Vary(0.01,1)) = 0.186
}
SubShader
{
Tags { "Queue"="Background" "RenderType"="Opaque" }
Cull Off ZWrite Off ZTest All the time // No depth testing or writing, since it is a skybox
Go
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#embody "UnityCG.cginc"
// Sky and moon parameters
fixed4 _SkyColor;
sampler2D _MoonTex;
float _MoonSize;
fixed4 _MoonTint;
float _MoonExposure;
float3 _MoonDir; // Moon path in world area (set by script)
float4x4 _MoonSpaceMatrix; // Transforms path to moon UV area (set by script)
sampler2D _MoonHaloTex;
float _MoonHaloSize;
float _MoonHaloExposure;
float _MoonHaloFadeThreshold;
// Enter vertex construction
struct appdata { float4 vertex : POSITION; };
struct v2f { float4 pos : SV_POSITION; float3 vDir : TEXCOORD0; };
// Vertex shader: outputs view path in world area
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.vDir = normalize(mul((float3x3)unity_ObjectToWorld, v.vertex.xyz));
return o;
}
// Intersect ray with sphere (for moon visibility)
float sphIntersect(float3 rayDir, float3 middle, float r)
{
float3 oc = -center;
float b = dot(oc, rayDir);
float c = dot(oc, oc) - r*r;
float h = b*b - c;
if (h < 0) return -1;
h = sqrt(h);
float t = -b - h;
return t < 0 ? -1 : t;
}
// Compute the moon halo look based mostly on view angle and publicity
float3 GetMoonHalo(float3 viewDir, float3 dir, float measurement, float moonSize, float moonMask, float moonNdotL)
{
float cosAngle = dot(viewDir, normalize(dir));
float maxCosAngle = cos(radians(moonSize) * measurement);
float r = saturate((1.0 - cosAngle) / (1.0 - maxCosAngle));
float2 haloUV = float2(0.5 + r * 0.5, 0.5);
float haloMask = r <= 1.0 ? 1.0 : 0.0;
// Elective fade-out when moon is illuminated
float haloFade = 1.0;
if (moonMask > 0.0)
haloFade = saturate(1.0 - moonNdotL / _MoonHaloFadeThreshold);
float3 haloColor = tex2D(_MoonHaloTex, haloUV).rgb;
return haloColor * _MoonTint.rgb * exp2(_MoonHaloExposure) * haloMask * haloFade;
}
// Fragment shader: determines last pixel coloration
fixed4 frag(v2f i) : SV_Target
{
float3 viewDir = normalize(-i.vDir); // View path from digital camera
float3 moonDir = normalize(_MoonDir); // Moon path
float rad = tan(radians(_MoonSize)); // Moon radius (angular)
float t = sphIntersect(viewDir, moonDir, rad); // Ray-sphere intersection
float moonMask = t > 0 ? 1.0 : 0.0;
float3 moonColor = 0;
float moonNdotL = 0;
if (moonMask > 0.0)
{
float3 hitPt = viewDir * t;
float3 moonNormal = normalize(hitPt - moonDir);
// Convert moon regular to texture UVs
float3 localDir = mul(_MoonSpaceMatrix, float4(moonNormal,0)).xyz;
float2 uv = localDir.xy * 0.5 + 0.5;
uv.y = 1.0 - uv.y;
if (all(uv >= 0.0) && all(uv <= 1.0))
{
float3 texCol = tex2D(_MoonTex, uv).rgb;
float3 lightDir = normalize(-_WorldSpaceLightPos0.xyz); // Directional mild
moonNdotL = saturate(dot(moonNormal, lightDir)); // Lighting issue
moonColor = texCol * moonNdotL * _MoonTint.rgb * exp2(_MoonExposure); // Closing moon lighting
}
}
// Compute the moon halo
float3 moonHalo = GetMoonHalo(viewDir, _MoonDir, _MoonHaloSize, _MoonSize, moonMask, moonNdotL);
// Closing sky coloration = base sky + moon + halo
float3 col = _SkyColor + moonColor + moonHalo;
return float4(col, 1);
}
ENDCG
}
}
FallBack Off
}
The script code to set the moon’s path and matrix information:
utilizing UnityEngine;
// Ensures this script runs in Edit Mode (contained in the editor, with out hitting Play)
(ExecuteInEditMode)
public class MoonShaderController : MonoBehaviour
{
// Reference to the moon object within the scene (have to be set within the Inspector)
(SerializeField) Rework _moon;
// Shader property title for moon path (as seen within the shader)
(SerializeField) string _moonDirId = "_MoonDir";
// Shader property title for the matrix used to transform world path to UV area
(SerializeField) string _moonSpaceMatrixId = "_MoonSpaceMatrix";
// Referred to as in spite of everything Replace() features — helpful for digital camera/sky updates
void LateUpdate()
{
if (_moon)
{
// Passes the moon's ahead vector to the shader (_MoonDir), which represents its path in world area
Shader.SetGlobalVector(_moonDirId, _moon.rework.ahead);
// Constructs a metamorphosis matrix from the moon's native axes (proper, up, ahead)
// and transposes it to align with the shader's anticipated coordinate area
Shader.SetGlobalMatrix(_moonSpaceMatrixId,
new Matrix4x4(
_moon.rework.proper, // X-axis
_moon.rework.up, // Y-axis
_moon.rework.ahead, // Z-axis
Vector4.zero // No translation
).transpose
);
}
}
}