Monday, July 28, 2025
HomeGame Developmentunity - How can I dynamically make a distance discipline form of...

unity – How can I dynamically make a distance discipline form of the lit a part of the moon to make use of it as a halo in a customized skybox shader?


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 gentle (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, nevertheless it 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 all the time seems centered on the lit portion of the moon, which might make it look extra real looking — however all my makes an attempt have failed.

To regulate the moon’s course and simulate real looking lighting, I take advantage of a easy script that passes two parameters to the shader globally:

_MoonDir: the moon’s ahead course in world area, used to orient the moon within the sky and decide its obvious place from the digicam.

_MoonSpaceMatrix: a change 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 all the time receives the right orientation and alignment of the moon relative to the scene’s gentle supply (usually the sun). This setup makes it potential to use directional lighting to the moon floor.

Is it potential 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?

Word:
I take advantage of 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 present.
  • The halo texture is a straightforward clear radial gradient:

enter image description here

[Update]

Somebody instructed me that my objective can be troublesome to realize and suggested me:

What you are able to do, for instance, is to dynamically make a distance discipline
form of the lit a part of the moon, and use it to attract a dynamic halo.

Shader Code:

Shader "Skybox/SimpleSkybox_Moon"
{
    Properties
    {
        _SkyColor ("Sky Colour", Colour) = (0,0,0,1)

        [space(10)]

        [NoScaleOffset]_MoonTex ("Moon Texture 2D", 2D) = "white" {}
        _MoonSize ("Moon Dimension", Vary(0.1,20)) = 9
        _MoonTint ("Moon Tint", Colour) = (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 At all times // No depth testing or writing, since it is a skybox

        Move
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #embrace "UnityCG.cginc"

            // Sky and moon parameters
            fixed4   _SkyColor;

            sampler2D _MoonTex;
            float    _MoonSize;
            fixed4   _MoonTint;
            float    _MoonExposure;

            float3   _MoonDir; // Moon course in world area (set by script)
            float4x4 _MoonSpaceMatrix; // Transforms course 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 course 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 heart, 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 primarily based on view angle and publicity
            float3 GetMoonHalo(float3 viewDir, float3 dir, float dimension, float moonSize, float moonMask, float moonNdotL)
            {
                float cosAngle = dot(viewDir, normalize(dir));
                float maxCosAngle = cos(radians(moonSize) * dimension);
                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 remaining pixel shade
            fixed4 frag(v2f i) : SV_Target
            {
                float3 viewDir = normalize(-i.vDir); // View course from digicam
                float3 moonDir = normalize(_MoonDir); // Moon course
                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 gentle
                        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 shade = base sky + moon + halo
                float3 col = _SkyColor + moonColor + moonHalo;

                return float4(col, 1);
            }
            ENDCG
        }
    }
    FallBack Off
}

The script code to set the moon’s course and matrix knowledge:

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] Remodel _moon;

    // Shader property identify for moon course (as seen within the shader)
    [SerializeField] string _moonDirId = "_MoonDir";

    // Shader property identify for the matrix used to transform world course to UV area
    [SerializeField] string _moonSpaceMatrixId = "_MoonSpaceMatrix";

    // Referred to as in any case Replace() capabilities — helpful for digicam/sky updates
    void LateUpdate()
    {
        if (_moon)
        {
            // Passes the moon's ahead vector to the shader (_MoonDir), which represents its course in world area
            Shader.SetGlobalVector(_moonDirId, _moon.rework.ahead);

            // Constructs a change 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
            );
        }
    }
}

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments