reckfellENGINE

3D lighting: sources, layers and shadows

Create a lit level with actual shadows, check light coverage and distinguish visual masks from physics.

On this page

Run a lit level

Use C# SDK 1.0.0, net10.0 and an Entity3D-rooted .rscene level. Save LightingMaterials.cs from the material guide and LightingLab3D.cs below. Run dotnet build, attach LightingLab3D.cs to the root and run. No external assets are required.

The level shows a white cube, blue sphere and floor. Key is a DirectionalLight3D with shadows enabled. Point and Spot exist but start with Visible=false so they can be compared individually rather than accumulated together.

LightingLab3D.cs
C#
using Reckfell;

public partial class LightingLab3D : Entity3D
{
    public MeshInstance3D Floor { get; private set; } = null!;
    public MeshInstance3D Cube { get; private set; } = null!;
    public MeshInstance3D MetalSphere { get; private set; } = null!;
    public DirectionalLight3D Key { get; private set; } = null!;
    public OmniLight3D Point { get; private set; } = null!;
    public SpotLight3D Spot { get; private set; } = null!;
    public Camera3D Camera { get; private set; } = null!;
    public WorldEnvironment World { get; private set; } = null!;

    public override void _Ready()
    {
        World = new WorldEnvironment { Environment = LightingMaterials.Environment() };
        AddChild(World);
        Floor = new MeshInstance3D
        {
            Mesh = new PlaneMesh { Size = new Vector2(10, 10) },
            MaterialOverride = LightingMaterials.Surface(new Color(0.48f, 0.5f, 0.55f))
        };
        Cube = new MeshInstance3D
        {
            Mesh = new BoxMesh { Size = new Vector3(1.4f, 2, 1.4f) },
            Position = new Vector3(0, 1, 0),
            MaterialOverride = LightingMaterials.Surface(Colors.White)
        };
        MetalSphere = new MeshInstance3D
        {
            Mesh = new SphereMesh { Radius = 0.8f, Height = 1.6f },
            Position = new Vector3(-2.2f, 0.8f, 0),
            MaterialOverride = LightingMaterials.Surface(new Color(0.08f, 0.25f, 1), 0.2f, 0.8f)
        };
        AddChild(Floor); AddChild(Cube); AddChild(MetalSphere);
        Key = new DirectionalLight3D
        {
            RotationDegrees = new Vector3(-50, -25, 0),
            LightColor = Colors.White,
            LightEnergy = 1,
            ShadowEnabled = true
        };
        Point = new OmniLight3D
        {
            Position = new Vector3(0, 3, 1),
            OmniRange = 8,
            LightEnergy = 3,
            Visible = false
        };
        Spot = new SpotLight3D
        {
            Position = new Vector3(0, 4, 3),
            SpotRange = 10,
            SpotAngle = 35,
            LightEnergy = 4,
            Visible = false
        };
        AddChild(Key); AddChild(Point); AddChild(Spot);
        Spot.LookAt(Vector3.Zero);
        Camera = new Camera3D { Current = true, Position = new Vector3(5, 4, 7), Fov = 55 };
        AddChild(Camera);
        Camera.LookAt(new Vector3(0, 0.7f, 0));
    }
}

Directional illumination, highlights and actual cube/sphere shadows in Compatibility

Current local 1.0.0 build, Compatibility/OpenGL, 512×384. This example has no collision or character controller.

Choose a source

TypeUseCheck
DirectionalLight3DSun or general directional lightRotation and shadow coverage distance; position does not locate a point lamp
OmniLight3DA lamp illuminating around itselfPosition, OmniRange and attenuation
SpotLight3DFlashlight or spotlightLocal -Z direction, SpotRange and SpotAngle
AreaLight3DExtended light sourceTarget renderer support; source configuration excludes its shadows and textured area lighting in Compatibility

The first three types are verified in the current runtime. AreaLight3D is not exercised here. After adding Spot, LookAt(Vector3.Zero) aims its cone toward the floor instead of relying on an incidental rotation.

LightEnergy is a multiplier, not a universal correct brightness. Material, distance, physical-unit settings and environment affect output. More energy cannot fix a range that stops short or a cone aimed elsewhere.

Isolate light problems

After _Ready, Key, Point, Spot and World.Environment are available. Disable Key.Visible, set AmbientLightEnergy=0 and enable only Point.Visible. Then disable Point.Visible and enable Spot.Visible. Make changes after those objects are created; their properties are not ready before _Ready.

Point lights the geometry at OmniRange=8 but fails to reach it at 0.2. Spot illuminates geometry inside its aimed cone. AmbientLightSource=Color with energy 1 also lights the level without Key, but creates no directional shadow.

LightCullMask matches geometry visual Layers. Changing the light mask from 1 to 2 excludes geometry left on the first visual layer. Physics CollisionLayer/CollisionMask are unrelated.

Obtain a shadow

Check the entire chain:

  1. The light has ShadowEnabled, and its type/renderer support the required shadows.
  2. Geometry is within influence and permitted visual layers.
  3. Casting geometry has CastShadow other than Off.
  4. The receiver has a material responding to the required lighting/shadows and is in view.
  5. Shadow coverage distance and map quality suit the level scale.

Native checks remove shadows through ShadowEnabled=false, then separately through CastShadow=Off on the cube/sphere without hiding their meshes. ShadowBias and ShadowNormalBias reduce self-shadowing, but excessive values detach shadows and damage thin details. Tune them after scale and coverage rather than using them as substitutes.

A light shadow, material AO and screen-space SSAO are distinct effects. SSAO adds contact darkening from visible depth; it does not replace a light casting shadows across a level. See the runnable SSAO/glow example.

Distinguish brightness from illumination

Emission brightens the material. Glow adds a halo around bright pixels. Neither alone supplies a direct Light3D for the floor or nearby objects. Add a light for such a lamp; indirect illumination and reflections require separate configuration.

If the editor looks different, compare the project’s actual lights and WorldEnvironment. This example creates them explicitly instead of treating editor preview as game configuration.

Diagnosis

SymptomCheck
Black cubeMaterial, enabled light/ambient, LightCullMask and Layers
Point has no effectSurface distance and OmniRange
Spot misses the targetRotation/LookAt, SpotAngle and SpotRange
Object is lit but has no shadowShadowEnabled, CastShadow, source type and coverage
Shimmering or detached shadowScale, resolution/coverage, then bias
Many lights reduce FPSProfile the target level; reduce overlap, range and dynamic shadows

Checks cover basic lights and directional shadows in Compatibility. They do not establish all shadow-atlas modes, physical-unit behavior, GI, export or large-level performance.

Light3D API

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.