Scripting Support (C#)

advanced scripting

Cloud Shadows FX · Scripting Support (C#)

Control Cloud Shadows FX at runtime using the SSCS namespace. The effect is a MonoBehavior component — access it via GetComponent<CloudShadows>() on the GameObject that holds the component.

using SSCS;

CloudShadows cs = GetComponent<CloudShadows>();
cs.profile.coverage = 0.5f;
cs.UpdateMaterialProperties();

CloudShadows

MonoBehavior component that renders cloud shadows and optional volumetric clouds. Add it to any GameObject and assign a CloudShadowsProfile.

General

CloudShadowsProfile profile

Reference to the profile ScriptableObject that defines all cloud and shadow settings.

Light sun

Reference to the directional light used for shadow and cloud lighting calculations. If null, the main directional light is used automatically.

LayerMask cameraLayerMask

Layer mask that determines which cameras receive the cloud shadow effect.

int renderQueue

Render queue for the shadow pass. Clouds render at renderQueue + 1. Default 3001.

Custom Bounds

bool useCustomBounds

Enables limiting cloud shadows to a specific rectangular area instead of the entire scene.

Bounds bounds

The bounding box for custom bounds mode (center + size).

Transform boundsAnchor

Optional anchor transform. When set, the bounds center follows the anchor's XZ position.

Coverage Mask

bool coverageMask

Enables the coverage mask system for painting shadows on/off in specific areas.

Texture2D coverageMaskTexture

The coverage mask texture. Controls where shadows appear.

Vector3 coverageMaskWorldSize

World-space size of the area covered by the mask texture. Default (2000, 0, 2000).

Vector3 coverageMaskWorldCenter

World-space center of the coverage mask area.

bool coverageIncludeClouds

When enabled, the coverage mask also prevents clouds from rendering in masked areas (not just shadows).

Methods

void UpdateMaterialProperties()

Applies all property changes to the cloud shadow material. Call after modifying profile or component properties at runtime.

Bounds GetBounds()

Returns the current effective bounds of the cloud shadow area.

void SetBounds(Bounds bounds)

Sets the bounds of the cloud shadow area and enables custom bounds mode.

void MaskPaint(Vector3 pos, byte value, float brushWidth, float brushOpacity = 1f, float brushFuzziness = 0f)

Paints the coverage mask at a world position. value 0 = remove shadows, 255 = full shadows.

void MaskClear(byte value)

Clears the entire coverage mask to the specified value.

void MaskFillArea(GameObject go, byte value, float opacity = 1f, float border = 0f)

Fills the coverage mask area occupied by the given GameObject's bounds.

void MaskFillArea(MeshRenderer meshRenderer, byte value, float opacity = 1f, float border = 0f)

Fills the coverage mask area using a specific MeshRenderer's bounds.

Shadow Sampling

Reads the cloud shadow on the CPU at any world position, matching what the shader draws on screen. Useful for stealth visibility, plant growth, solar panels or any gameplay that reacts to cloud cover. The CPU copy of the cloud textures is built when the component is enabled and rebuilt only if the textures change.

float SampleShadowAtPosition(Vector3 worldPosition, Camera camera = null)

Amount of cloud shadow at a world position, from 0 (fully lit) to 1 (fully darkened). Pass a camera to also apply the view distance fade used on screen.

CloudShadowSample SampleShadowDetailsAtPosition(Vector3 worldPosition, Camera camera = null)

Full cloud shadow breakdown at a world position. See CloudShadowSample.

void SampleShadowAtPosition(Vector3[] positions, float[] results, int count, Camera camera = null)

Fills results with the shadow amount at each position. Both arrays belong to the caller, so this overload does not allocate.

CloudShadowQuery BeginQuery(Camera camera = null)

Snapshots the current cloud state once and returns a query that can be sampled many times. Use it when sampling more than a few positions in the same frame.

CloudShadowsProfile

ScriptableObject that holds all cloud and shadow visual settings. Create via Create > Cloud Shadows Profile. Multiple components can share the same profile.

Clouds

bool showClouds

Enables rendering of volumetric clouds in the sky.

float coverage

Cloud coverage amount. Higher values produce more clouds.

float cloudsOpacity

Opacity of the rendered clouds.

float cloudsThickness

Thickness of the cloud layer, affecting visual density and lighting.

float distanceFade

Distance at which clouds fade out from the camera. Default 2500.

Color sunColor

Sun light color applied to the clouds.

Color cloudsLightColor

Color of low-density cloud areas (thinner, more transparent parts).

Color cloudsDarkColor

Color of high-density cloud areas (thicker, darker parts).

float cloudsLightIntensity

Light reflectivity intensity on clouds. Range 0–1.

float cloudsAnisotropy

Sun light intensity shining through the clouds toward the camera.

float cloudsAmbientLight

Minimum light intensity on clouds. Range 0–1.

Shadows

bool showShadows

Enables rendering of cloud shadows on the scene geometry.

float shadowCoverage

Shadow coverage amount. Can differ from cloud coverage for artistic control.

float shadowOpacity

Opacity of the cloud shadows.

Color shadowTintColor

Tint color for the cloud shadows.

bool topDownOnly

When enabled, shadows render only on top-facing surfaces (skips ceiling checks for performance).

float normalBias

Affects shadow intensity on walls and ceilings. Range -0.5 to 0.5.

float shadowMinAltitude

Prevents cloud shadows below this altitude. Useful to avoid shadows under water or terrain. Default -10000.

float preserveDirectionalShadows

Reduces cloud shadow intensity where directional light shadows exist. Range 0–1. URP only.

General

float altitude

Altitude of the cloud layer in world units.

float scale

Scale of the cloud pattern. Smaller values produce larger cloud features.

Vector3 windSpeed

Wind direction and speed for cloud animation.

Vector2 offset

UV offset for the cloud pattern.

float contrast

Contrast of the cloud pattern edges.

float edgeNoise

Amount of noise applied to cloud edges for a more natural look.

float edgeAnimationSpeed

Speed of the edge noise animation.

float noiseMultiplier

Noise intensity multiplier.

Events

event OnSettingsChanged onSettingsChanged()

Fired when profile settings are validated or changed. Subscribe to react to profile modifications.

cs.profile.onSettingsChanged += () => {
    Debug.Log("Cloud settings changed");
};

CloudShadowSample

Struct returned by SampleShadowDetailsAtPosition with the intermediate values of the shadow calculation.

float haze

Cloud density at the position projected onto the cloud plane, before lighting and opacity are applied.

float shadow

Shadow factor after sun angle, normal bias, distance fade and coverage mask. Range 0–1.

float opacity

Shadow factor multiplied by the profile shadow opacity.

float darkness

Perceived darkening, from 0 (fully lit) to 1 (fully darkened). This is the value returned by SampleShadowAtPosition.

Vector3 colorMultiplier

RGB multiplier applied at that position, including the shadow tint color.

CloudShadowQuery

Read-only snapshot of the cloud state returned by BeginQuery(). Sampling through a query skips the per-call setup, so it is the cheapest way to test many positions in the same frame. Do not keep it across frames: it holds the wind and animation state of the frame it was created in.

bool isValid

False when shadows are disabled, the component is inactive or the cloud textures are not ready yet. An invalid query always reports a fully lit position.

float SampleShadowAtPosition(Vector3 worldPosition)

Shadow amount at a world position, assuming an upward facing surface.

float SampleShadowAtPosition(Vector3 worldPosition, Vector3 worldNormal)

Shadow amount at a world position on a surface with the given normal. Walls and slopes are affected by the normal bias setting.

CloudShadowSample SampleShadowDetailsAtPosition(Vector3 worldPosition)

Full shadow breakdown at a world position.

CloudShadowSample SampleShadowDetailsAtPosition(Vector3 worldPosition, Vector3 worldNormal)

Full shadow breakdown at a world position on a surface with the given normal.

void SampleShadowAtPosition(Vector3[] positions, float[] results, int count)

Batch version. The arrays belong to the caller and nothing is allocated.

void SampleShadowAtPosition(Vector3[] positions, Vector3[] normals, float[] results, int count)

Batch version with a surface normal per position.

void SampleShadowDetailsAtPosition(Vector3[] positions, CloudShadowSample[] results, int count)

Batch version returning the full breakdown for each position.

Code Examples

Basic Runtime Control

using UnityEngine;
using SSCS;

public class CloudController : MonoBehaviour {
    public CloudShadows cloudShadows;

    void Start() {
        cloudShadows.profile.coverage = 0.6f;
        cloudShadows.profile.shadowOpacity = 0.5f;
        cloudShadows.profile.windSpeed = new Vector3(0.2f, 0f, 0.1f);
        cloudShadows.UpdateMaterialProperties();
    }
}

Day/Night Cloud Cycle

using UnityEngine;
using SSCS;

public class CloudCycle : MonoBehaviour {
    public CloudShadows cloudShadows;

    void Update() {
        float t = Mathf.PingPong(Time.time * 0.1f, 1f);
        cloudShadows.profile.coverage = Mathf.Lerp(0.2f, 0.7f, t);
        cloudShadows.profile.shadowOpacity = Mathf.Lerp(0.3f, 0.8f, t);
        cloudShadows.profile.cloudsOpacity = Mathf.Lerp(0.5f, 1f, t);
        cloudShadows.UpdateMaterialProperties();
    }
}

Limit Shadows to Play Area

using UnityEngine;
using SSCS;

public class BoundedShadows : MonoBehaviour {
    public CloudShadows cloudShadows;
    public Transform player;
    public float areaSize = 500f;

    void Start() {
        cloudShadows.SetBounds(new Bounds(
            player.position,
            new Vector3(areaSize, 10f, areaSize)
        ));
        cloudShadows.boundsAnchor = player;
    }
}

Coverage Mask — Clear Area

using UnityEngine;
using SSCS;

public class ShadowMasking : MonoBehaviour {
    public CloudShadows cloudShadows;
    public GameObject building;

    void Start() {
        cloudShadows.coverageMask = true;
        cloudShadows.MaskFillArea(building, 0, 1f, 5f);
    }
}

Is the Player Under a Cloud Shadow?

using UnityEngine;
using SSCS;

public class StealthVisibility : MonoBehaviour {
    public CloudShadows cloudShadows;
    public Transform player;

    public bool hidden;

    void Update() {
        float darkness = cloudShadows.SampleShadowAtPosition(player.position);
        // Two thresholds instead of one, so the state does not flicker at the shadow edge
        hidden = hidden ? darkness > 0.5f : darkness > 0.65f;
    }
}

Sampling Many Positions at Once

using UnityEngine;
using SSCS;

public class CloudCoverGrid : MonoBehaviour {
    public CloudShadows cloudShadows;

    Vector3[] positions = new Vector3[256];
    float[] darkness = new float[256];

    void Update() {
        CloudShadowQuery query = cloudShadows.BeginQuery();
        if (!query.isValid) return;
        query.SampleShadowAtPosition(positions, darkness, positions.Length);
    }
}
Was this page helpful?