Lighting System

The Lighting System in Raftel Engine provides a robust framework for illuminating your 3D scenes with various types of lights, including directional, point, spot, and ambient lights. The system also supports shadow mapping for creating realistic lighting effects.

Lighting Demo
Lighting Demo

Light Types

Raftel Engine supports multiple light types, each with specific behaviors and use cases:

Directional Light

Simulates light from a distant source like the sun. All light rays are parallel and have the same direction, casting shadows in the same direction regardless of object position.

Point Light

Emits light in all directions from a specific point in space. Ideal for light bulbs, torches, or other localized light sources with a defined range.

Spot Light

Creates a cone of light from a specific position and direction. Features inner and outer cone angles to control the light's falloff and focus.

Ambient Light

Provides a base level of illumination to all objects in the scene regardless of their position or orientation. Used to simulate indirect lighting.

Light Component

In Raftel Engine, lights are managed as components in the Entity Component System (ECS). The LightComponent is the primary class that handles all lighting functionality.

Creating a Light
#include "raftel/ecs.hpp"
#include "raftel/components.hpp"

// Create an entity
Raftel::EntityManager entityManager;
auto entity = entityManager.CreateEntity();

// Add a transform component
Raftel::TransformComponent transform(
    glm::vec3(0.0f, 10.0f, 0.0f),   // position
    glm::vec3(0.0f, 0.0f, 0.0f),    // rotation
    glm::vec3(1.0f, 1.0f, 1.0f)     // scale
);
entity.addTransformComp(std::move(transform));

// Add a directional light component
Raftel::LightComponent directionalLight(
    Raftel::LightComponent::LightType::DIRECTIONAL, // light type
    glm::vec3(1.0f, 1.0f, 1.0f),    // color (white)
    1.5f,                           // intensity
    100.0f,                         // range
    0.0f,                           // inner cone (not used for directional)
    0.0f,                           // outer cone (not used for directional)
    glm::ivec2(1024, 1024)          // shadow map resolution
);
entity.addLightComp(std::move(directionalLight));

Light Properties

Each light type has specific properties that can be configured to achieve the desired lighting effect:

Property Description Applicable To
color RGB color of the light All light types
intensity Brightness multiplier for the light All light types
range Maximum distance the light affects Point, Spot
innerCone Inner angle of the spotlight cone in degrees Spot
outerCone Outer angle of the spotlight cone in degrees Spot
near Near plane distance for shadow mapping All lights with shadows
far Far plane distance for shadow mapping All lights with shadows

Shadow Mapping

Raftel Engine supports shadow mapping for creating realistic shadows. When a light is created, you can enable shadow mapping by specifying the shadow map resolution.

Shadow Map Resolution

Higher shadow map resolutions provide more detailed shadows but require more GPU memory and processing power. For most applications, a resolution of 1024x1024 or 2048x2048 provides a good balance between quality and performance.

Shadow mapping works differently depending on the light type:

Enabling Shadow Rendering
// In your rendering loop
void YourApplication::render() {
    // Update the camera
    camera.update();

    // Render the scene with shadows
    Raftel::RenderSystem::UpdateRenderSystem(
        entityManager,
        camera,
        glm::ivec2(windowWidth, windowHeight),
        true  // Enable shadow rendering
    );
}

Ambient Light

Unlike directional, point, and spot lights that are added as components to entities, ambient light is set globally through the Engine singleton:

Configuring Ambient Light
#include "raftel/engine.hpp"

// Enable ambient light
Raftel::Engine::Instance().has_ambient_light = true;

// Set ambient light color (RGB values between 0.0 and 1.0)
Raftel::Engine::Instance().ambient_light = glm::vec3(0.1f, 0.1f, 0.15f);  // Slight blue tint

Ambient Light Intensity

Keep ambient light values relatively low (typically around 0.1 to 0.2) to maintain contrast and prevent your scene from looking flat. Ambient light should merely provide some illumination in areas not directly lit by other light sources.

Light Blending

Raftel Engine supports multiple lights affecting the same objects through an additive blending mechanism. This is handled automatically by the RenderSystem:

  1. The first light is rendered normally, overwriting the framebuffer.
  2. Subsequent lights are blended additively, enhancing the illumination where multiple lights overlap.
  3. Depth writing is disabled after the first light to prevent occlusion issues.

Performance Considerations

Lighting and shadows can be computationally expensive. Here are some tips to optimize performance:

Shadow Rendering Toggle

If your application experiences performance issues, you can disable shadow rendering by setting the shadow parameter to false when calling UpdateRenderSystem. This allows you to implement quality settings or dynamic LOD systems.

Complete Example

The following example demonstrates setting up a scene with multiple light types:

Complete Lighting Setup Example
#include "raftel/ecs.hpp"
#include "raftel/components.hpp"
#include "raftel/engine.hpp"
#include "raftel/camera.hpp"

// Set up global ambient light
void setupAmbientLight() {
    auto& engine = Raftel::Engine::Instance();
    engine.has_ambient_light = true;
    engine.ambient_light = glm::vec3(0.1f, 0.1f, 0.12f);  // Slight blue tint
}

// Create a directional light (like the sun)
Raftel::Entity createDirectionalLight(Raftel::EntityManager& entityManager) {
    auto entity = entityManager.CreateEntity();
    
    // Position and orient the light
    Raftel::TransformComponent transform(
        glm::vec3(0.0f, 50.0f, 0.0f),  // High position
        glm::vec3(-45.0f, 30.0f, 0.0f), // Angled downward
        glm::vec3(1.0f, 1.0f, 1.0f)
    );
    entity.addTransformComp(std::move(transform));
    
    // Create the light component
    Raftel::LightComponent light(
        Raftel::LightComponent::LightType::DIRECTIONAL,
        glm::vec3(1.0f, 0.95f, 0.8f),  // Warm sunlight color
        1.2f,                         // Intensity
        0.0f,                         // Range (not used)
        0.0f,                         // Inner cone (not used)
        0.0f,                         // Outer cone (not used)
        glm::ivec2(2048, 2048)        // Shadow resolution
    );
    entity.addLightComp(std::move(light));
    
    return entity;
}

// Create a point light (like a lamp)
Raftel::Entity createPointLight(Raftel::EntityManager& entityManager, 
                              const glm::vec3& position,
                              const glm::vec3& color) {
    auto entity = entityManager.CreateEntity();
    
    // Position the light
    Raftel::TransformComponent transform(
        position,
        glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(1.0f, 1.0f, 1.0f)
    );
    entity.addTransformComp(std::move(transform));
    
    // Create the light component
    Raftel::LightComponent light(
        Raftel::LightComponent::LightType::POINT,
        color,
        2.0f,                         // Intensity
        15.0f,                        // Range
        0.0f,                         // Inner cone (not used)
        0.0f,                         // Outer cone (not used)
        glm::ivec2(1024, 1024)        // Shadow resolution
    );
    entity.addLightComp(std::move(light));
    
    return entity;
}

// Create a spotlight (like a flashlight)
Raftel::Entity createSpotlight(Raftel::EntityManager& entityManager,
                             const glm::vec3& position,
                             const glm::vec3& direction) {
    auto entity = entityManager.CreateEntity();
    
    // Position and orient the light
    Raftel::TransformComponent transform(
        position,
        direction,
        glm::vec3(1.0f, 1.0f, 1.0f)
    );
    entity.addTransformComp(std::move(transform));
    
    // Create the light component
    Raftel::LightComponent light(
        Raftel::LightComponent::LightType::SPOT,
        glm::vec3(1.0f, 1.0f, 0.9f),  // Slightly yellow
        2.5f,                         // Intensity
        30.0f,                        // Range
        15.0f,                        // Inner cone angle
        30.0f,                        // Outer cone angle
        glm::ivec2(1024, 1024)        // Shadow resolution
    );
    entity.addLightComp(std::move(light));
    
    return entity;
}

// In your application's initialization
void initializeScene() {
    Raftel::EntityManager entityManager;
    
    // Set up ambient light
    setupAmbientLight();
    
    // Create directional light (sun)
    auto sunLight = createDirectionalLight(entityManager);
    
    // Create some point lights
    auto redLight = createPointLight(entityManager, 
        glm::vec3(-5.0f, 1.0f, 2.0f), 
        glm::vec3(1.0f, 0.2f, 0.2f));  // Red
        
    auto blueLight = createPointLight(entityManager, 
        glm::vec3(5.0f, 1.0f, -2.0f), 
        glm::vec3(0.2f, 0.4f, 1.0f));  // Blue
    
    // Create a spotlight
    auto spotlight = createSpotlight(entityManager,
        glm::vec3(0.0f, 5.0f, 0.0f),
        glm::vec3(-45.0f, 0.0f, 0.0f));  // Pointing downward
    
    // Create a camera
    
    // In your render loop
    while (isRunning) {
        // Update entities, handle input, etc.
        
        // Render the scene with shadows
        Raftel::RenderSystem::UpdateRenderSystem(
            entityManager,
            ...,
            ...,
            true  // Enable shadows
        );
    }
}

Next Steps

Now that you understand how to work with the lighting system in Raftel Engine, you might want to explore:

Lighting Tutorial

A step-by-step guide to creating and configuring lights in your scenes.

Materials

Learn how materials interact with lights in Raftel Engine.

Shaders

Understand how to create custom shaders that work with the lighting system.

Render System

Dive deeper into the rendering pipeline and how it handles lighting.