Spot lighting

Basic question of the day!

Is there a way to set the direction of a spot-type light source? For example, can I modify the provided Lights example to have the spot lights point not down, but towards the monkey? I figured I could adjust the eulerAngles of the light’s entity, but unless I goofed up somehow, I didn’t see that affecting the direction of the light.

@brianolive I don’t think you can change the direction of the spot light. You can change it’s location, but not where it’s pointed. At least I haven’t found a way yet.

Hmm. @John , @Simeon , any idea? Thanks!

Huh. Well, I came back to it this evening, set light.entity.eulerAngles as desired, and the light changed direction. I’ll look to put an interesting example together as soon as I can.

@brianolive I tried that long ago and all it did was rotate everything in the scene, not just the spotlight. Maybe you’re doing something different than I was if just the spotlight is changing.

Here are the lights below and in front of the monkey, with spot lighting pointing towards it.

It would be more interesting to see the light beams going through the air. How would one go about doing that?

It made me think of the scene fog feature, but haven’t figured that out yet. Perhaps fog just means the distance at which objects begin to come into view, so as not to render things in the distance?

@brianolive Did you actually change the spotlight direction, or did you just rotate things 180 degrees. As for the fog, I think it just alters the overall color of the scene and doesn’t act like real somyou can see the light cone thru it.

Here’s the modified ‘Lights’ project. Scene stays as is. Just needed to add the light.entity.eulerAngles assignment.

-----------------------------------------
-- Lights
-- Written by John Millard
-----------------------------------------
-- Description:
-- Demonstrates realtime lighting in Craft.
-----------------------------------------

-- Use this function to perform your initial setup
function setup()
    print("Hello Lighting!")
    
    -- Create and setup a basic scene
    scene = craft.scene()
    -- Disable the sky and sun to emphasise our custom lights
    scene.sun.active = false  
    scene.sky.active = false
    
    basicMat = craft.material("Materials:Standard")

    local floor = scene:entity()
    local r = floor:add(craft.renderer, craft.model.cube(vec3(50,0.1,50)))
    r.material = basicMat
    floor.z = 5
    floor.y = -1
    
    -- Create a monkey model to shine our lights on
    local monkey = scene:entity()
    monkey.scale = vec3(0.625, 0.625, 0.625)
    monkey.rotation = quat.eulerAngles(-20, 180, 0)
    r = monkey:add(craft.renderer, craft.model("Primitives:Monkey"))
    r.material = basicMat
    r.material.roughness = 0.6
    r.material.metalness = 0.25
    monkey.position = vec3(0, 0, 5)
    
    -- Set up some parameters to control the lights
    parameter.color("Ambient", 
    color(26, 26, 26, 255))
    parameter.integer("Type", DIRECTIONAL, SPOT, SPOT)
    types = {"DIRECTIONAL", "POINT", "SPOT"}
    parameter.watch("types[Type+1]")
    parameter.number("Height", -1, 10, -0.7)
    parameter.number("Angle", 0.0, 60, 17.5)
    parameter.number("Penumbra", 0.0, 60, 0.0)
    parameter.number("Intensity", 0.0, 10.0, 1.0)
    parameter.number("Decay", 0.0, 10.0, 1.0)
    parameter.boolean("Animate", false)
    
    lights = {}

    -- Define the initial light colors
    colors = 
    {
        color(255, 0, 0, 255),
        color(0, 255, 0, 255),
        color(0, 0, 255, 255)
    }
    
    for i = 1,3 do
        local light = scene:entity():add(craft.light, SPOT)
        light.angle = 17.5
        light.penumbra = Penumbra
        light.color = colors[i]
        light.entity.x = -2 + i
        light.entity.z = 3
        light.entity.eulerAngles = vec3(-110, 0, 0)

        -- Represent each of the lights with a basic material sphere (which is unlit)
        local r = light.entity:add(craft.renderer, craft.model.icosphere(0.05, 2))
        r.material = craft.material("Materials:Basic")
        r.material.diffuse = light.color
        table.insert(lights, light)
    end
end

function update(dt)
    scene:update(dt)
    
    -- Update ambient lighting based on the parameter
    scene.ambientColor = Ambient
    
    for k,light in pairs(lights) do
        if Animate then
            light.entity.x = math.cos(math.rad(90*ElapsedTime*1+(90*k)))
            light.entity.z = 5 + math.cos(math.rad(90*ElapsedTime*1+(-45*k)))
        end
            
        light.entity.y = Height
        light.type = Type
        light.penumbra = Penumbra
        light.angle = Angle    
        light.intensity = Intensity    
        light.decay = Decay
    end

end

-- This function gets called once every frame
function draw()
    update(DeltaTime)
    
    background(0, 0, 0, 255)
    scene:draw()    
end

@brianolive I had light.entity.eulerAngles also, but mine rotated the whole scene, not just the light. I’ll have to see what you did and compare it to what I did and see why mine didn’t work.

@brianolive I modified your version somewhat. Slide the xx, yy slider to move the spot.

function setup()
    parameter.integer("xx",-130,110,-110)
    parameter.integer("yy",-110,110,0)
    parameter.number("Height", -1, 10, -0.7)
    parameter.number("Angle", 0.0, 60, 10)
    parameter.number("Decay", 0.0, 10.0, 1.0)
    
    scene = craft.scene()
    scene.sun.active = false  
    scene.sky.active = false

    monkey = scene:entity()
    monkey.scale = vec3(0.625, 0.625, 0.625)
    monkey.rotation = quat.eulerAngles(-20, 180, 0)
    m = monkey:add(craft.renderer, craft.model("Primitives:Monkey"))
    monkey.position = vec3(0, .5, 7)

    light = scene:entity():add(craft.light, SPOT)
    light.color = color(255, 255, 255, 255)
    light.entity.position=vec3(0,0,3)
    light.type = SPOT
    light.penumbra = 20
    light.intensity = 3    

    local r = light.entity:add(craft.renderer, craft.model.icosphere(0.05, 2))
    r.material = craft.material("Materials:Basic")
    r.material.diffuse = light.color
    scene.ambientColor = color(26, 26, 26, 255)
    
    block = scene:entity()
    block.model = craft.model.cube(vec3(6,6,.1))
    block.material = craft.material("Materials:Standard")
    block.material.map = readImage("Blocks:Error")
    block.position=vec3(0,.5,11)
end

function update(dt)
    scene:update(dt)
    light.entity.y = Height
    light.angle = Angle    
    light.decay = Decay
    light.entity.eulerAngles=vec3(xx,yy,0)
end

function draw()
    update(DeltaTime)
    background(0, 0, 0, 255)
    scene:draw()    
end

Nice! The backdrop adds some depth and form to the ‘spotlight’, hitting first the monkey, then ‘spilling’ over to the E.