reckfellENGINE

Manual fill lighting without GI

Create colored fill, limit its influence and verify shadows across an opaque divider.

On this page

When it fits

Manual fill can improve dark-side readability or add an artistic tint. The sample blue OmniLight3D approximates fill lighting. The developer chooses its color; it is not automatically derived from a neighboring wall.

It remains an ordinary direct light with range, layers, attenuation and shadows. Moving walls or editing materials does not automatically make its settings physically correct.

Run the complete example

Complete C# setup. Use SDK 1.0.0, net10.0 and an Entity3D-rooted .rscene level. Save both files below, run dotnet build and attach FillLightLab3D.cs to the root. Code creates the camera, cube, floor, divider and lights.

FillMaterials.cs
C#
using Reckfell;

public static class FillMaterials
{
    public static StandardMaterial3D Surface(Color color) => new() { AlbedoColor = color, Roughness = 0.7f };
    public static Reckfell.Environment Dark() => new()
    {
        BackgroundMode = Reckfell.Environment.BGMode.Color,
        BackgroundColor = Colors.Black,
        AmbientLightSource = Reckfell.Environment.AmbientSource.Color,
        AmbientLightColor = Colors.Black, AmbientLightEnergy = 1, AmbientLightSkyContribution = 0,
        ReflectedLightSource = Reckfell.Environment.ReflectionSource.Bg
    };
}
FillLightLab3D.cs
C#
using Reckfell;

public partial class FillLightLab3D : Entity3D
{
    public OmniLight3D Fill { get; private set; } = null!;
    public override void _Ready()
    {
        GetViewport().PositionalShadowAtlasSize = 1024;
        AddChild(new WorldEnvironment { Environment = FillMaterials.Dark() });
        AddChild(new MeshInstance3D
        {
            Mesh = new PlaneMesh { Size = new Vector2(8, 8) },
            MaterialOverride = FillMaterials.Surface(Colors.White)
        });
        AddChild(new MeshInstance3D
        {
            Mesh = new BoxMesh { Size = new Vector3(1.4f, 2, 1.4f) }, Position = new Vector3(0, 1, 0),
            MaterialOverride = FillMaterials.Surface(Colors.White)
        });
        AddChild(new MeshInstance3D
        {
            Mesh = new BoxMesh { Size = new Vector3(0.15f, 3, 4) }, Position = new Vector3(1.2f, 1.5f, 0),
            MaterialOverride = FillMaterials.Surface(Colors.White)
        });
        AddChild(new DirectionalLight3D { RotationDegrees = new Vector3(-45, -20, 0), LightEnergy = 0.5f, ShadowEnabled = true });
        Fill = new OmniLight3D
        {
            Position = new Vector3(2, 1.5f, 0), LightColor = new Color(0.08f, 0.25f, 1),
            LightEnergy = 1, OmniRange = 6, ShadowEnabled = false
        };
        AddChild(Fill);
        var camera = new Camera3D { Current = true, Position = new Vector3(-4, 3, 6), Fov = 55 };
        AddChild(camera);camera.LookAt(new Vector3(0, 0.8f, 0));
    }
}

Fill is available after _Ready. First compare Fill.Visible=false and true with unchanged camera/exposure. Change it after the source is created, not before _Ready.

Control frame with one directional light

Blue Omni fill added without shadows

Actual 512×384 frames from the current local 1.0.0 Compatibility/OpenGL runtime. Colored-pixel changes are separately verified in Forward+/Vulkan. This demonstrates direct fill, not GI calculation or performance.

Limit influence

  • Position the source on the intended fill side; more energy does not repair incorrect placement.
  • Limit OmniRange to the intended area. Range 0.1 removes the tested distant color contribution.
  • Choose LightEnergy/LightColor after base illumination. Strong blue makes this comparison clear.
  • LightCullMask matches visual Layers; physics CollisionLayer/CollisionMask do not restrict light.

Coordinated visual layers can target particular gameplay objects. Masks are manual light influence controls, not reconstruction of physical bounce paths.

Check wall leakage

Fill sits to the right of the opaque divider. With ShadowEnabled=false, it also lights some surfaces on the left: a visible wall does not automatically block this light.

Enable Fill.ShadowEnabled=true. The sample configures its viewport PositionalShadowAtlasSize=1024 first. This is a shared positional-shadow atlas, not a substitute for the light’s shadow flag. Geometry also needs suitable CastShadow.

Same source with shadows: less blue fill beyond the divider

Both checked renderers reduce blue contribution behind opaque geometry when shadows are enabled. This does not establish leak-free behavior everywhere: inspect thin surfaces, bias, scale and coverage. Dynamic shadows may cost more than a soft artistic fill needs; decide from output and project profiling.

Diagnosis

ProblemCheck
No color contributionFill.Visible, distance/range, LightCullMask and material
Fill passes through a wallShadowEnabled, viewport atlas, CastShadow and geometry
Lighting stops fitting after level editsRevisit manual source placement and coverage
Flat or overexposed imageLower energy and distinguish fill from the key light
Automatic colored bounce is expectedA selected GI method and data are needed, not a manual Omni

Direct and indirect light · OmniLight3D 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.