Optimizing craft lights - Crashing when multiple lights are added to the scene quickly.

Has anybody experimented with this? I’ve been working on a particle system and today I decided to implement point lights, since I was having a lot of trouble when I first attempted it, I pushed it off. Since starting the project, I’ve purchased a new device and I’m happy to report that there has been a measurable increase in performance, however, whenever the particles light intensity is beyond 0, and if those particles lifespans are longer than a half a second, then the entire application crashes.

I was unable to even get a few lit particles on the screen with my iphone 8, however with an iphone 11, I can have up to 30 lit particles with a pretty heavy performance loss. The real problem occurs when I turn up the lifespan of the particles.

This leads me to assume, as I originally thought, that the lights are optimized for static entities, and not for runtime instantiation. Am I wrong in assuming so? The particle system works flawlessly with 1000s of particles as long as there are no lights involved.

Should I try to use shade to create a material with emission? is that even compatible with craft.renderer? I would have gone with that, but I assumed it’s not possible.

So if you’ve tried something similar and figured out a workaround, or some way to fake emission please enlighten me :smiley:

You can try this, My test code?

-- MultiLights

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- ?? OrbitViewer ??????????????????????
    viewer = scene.camera:add(OrbitViewer, vec3(0,2,0),5, 0, 1000) 
    modelInit()
    
    -- ????????????P[1].Color?P[2].Color
    P = {}
    -- ????????
    lights = {}
    for i=1,6 do
        P[i] = { Color = color(230, 249, 18), Type=2, Intensity=1, Penumbra=30,
        Decay=0, Height=5, X=2, Z=2, Angle=30}
        local l = scene:entity():add(craft.light, POINT)
        lights[i] = Light(i, l, 1, 1, 1, true)  
    end
    
    -- ??????
    showParameter()      
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
    lights[ID]:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
end

function modelInit()
    models = {}
    -- ??????
    local ground = scene:entity()
    ground.position = vec3(0,0,0)
    ground.model = craft.model.cube(vec3(50,0.1,50))
    ground.material = craft.material.preset("Surfaces:Basic Bricks")
    -- ground.material = craft.material(asset.builtin.Materials.Standard)
    -- ground.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Color)
    -- ground.material.normalMap = readImage(asset.builtin.Surfaces.Basic_Bricks_Normal)
    -- ground.material.diffuse = color(146, 82, 69)
    ground.material.offsetRepeat = vec4(1,20,20,20)
    -- ground.active = false
    
    -- ??????:?????????
    cube = scene:entity()
    cube.position=vec3(-1,1.5,3)
    cube.model = craft.model.cube(vec3(0.2,0.2,0.2),vec3(1,0.5,1))   
    cube.material = craft.material(asset.builtin.Materials.Specular)
    -- cube.material.diffuse = color(238, 237, 237, 255)
    cube.active = true    
end

-- ???
Light = class()
-- light ????scene:entity():add(craft.light)?scene.sun:get(craft.light)
function Light:init(id,light,x,y,z)
    self.id = id
    self.light = light
    self.light.color = P[self.id].Color or color(18, 66, 249)
    self.light.type = Type or SPOT        
    self.light.intensity = Intensity or 1  
    self.light.penumbra = Penumbra or 30 
    self.light.decay = Decay or 0    
    self.light.entity.y = Height  or 4
    self.light.entity.x = X or 2   
    self.light.entity.z = Z or 2   
    self.light.angle = Angle  or 30
end

function Light:update(dt)   
    self.light.color = P[self.id].Color
    self.light.intensity = P[self.id].Intensity    
    self.light.type = P[self.id].Type         
    self.light.angle = P[self.id].Angle  
    self.light.decay = P[self.id].Decay
    self.light.penumbra = P[self.id].Penumbra 
    self.light.entity.y = P[self.id].Height  
    self.light.entity.x = P[self.id].X  
    self.light.entity.z = P[self.id].Z   
end

function showParameter()
    types = {"DIRECTIONAL", "POINT", "SPOT"}  
    parameter.watch("scene.camera.position")  
    parameter.integer("ID",1,6,1)    
    parameter.color("Color",color(249, 93, 18),function() P[ID].Color = Color end)
    parameter.integer("Type", DIRECTIONAL, SPOT, SPOT, function() P[ID].Type = Type end)    
    parameter.watch("types[Type+1]")
    parameter.number("Intensity", 0.0, 10.0, 1.0,function() P[ID].Intensity =  Intensity end)
    parameter.number("Penumbra", 0.0, 90, 30.0, function() P[ID].Penumbra = Penumbra end)
    parameter.number("Decay", 0.0, 10.0, 0.1, function() P[ID].Decay = Decay end)
    parameter.number("Height", -1, 50, 5, function() P[ID].Height = Height end)
    parameter.number("X", -25, 25, 2, function() P[ID].X = X end)
    parameter.number("Z", -25, 25, 2, function() P[ID].Z = Z end)
    parameter.number("Angle", 0.0, 90, 30, function() P[ID].Angle = Angle end)
end

I’m talking about potentially having 30-100 point light entities instantiated at nearly the same time, each having there own update functions affecting things like gravity, scale, and speed. I have this system working for standard unlit models, but as soon as you apply lights to them. At least, on my device, the performance is really, really bad. I don’t have any issues with using lights normally, just in this particular way. Sorry if I wasn’t clear! @binaryblues

Shade totally works. It’s extremely simple in my case. Just make a new shader with a color property node and hook that up into the emission and the diffuse input ports on the surface shader. Rename the color node from “Color” to “diffuse” and move that into your Codea folder. Also, make sure the render queue is set to transparent. Oh and I turned off the rest of the fancy stuff I could find in shade, for some extra performance.

I finally have a bunch of “lit” particles on the screen. (:

Check it out!

can you make a video tutorial of how you got Shade to work with Codea?

@arismoko Sorry for my misunderstanding. In my test code, the max numbers of craft.light is nine. If I set ten lights, it will disappear.

No worries @binaryblues, and here you go @skar
https://youtu.be/rWMmvNw6mQ0

Hey guys, lights in craft aren’t implemented very optimally, all lights effect all geometry in the scene and passed into lit shaders, meaning that at some point you’ll get very bad performance or exceed uniform block limits and it’ll break in some way or another…

In Codea 4 I’m working on getting clustered forward rendering working so there will be effectively much better performance and much higher light limits, but for now it’s a bit crappy

@John that’s really exciting stuff, until then some bloom and an emission shader works just fine for my purposes (: i’m excited for that though! All craft needs at this point is a pathfinding/navmesh system plus some collision callbacks and we’re golden.

Thanks. When I get the change I want to look at integrating this tool for navmesh and navigation stuff: https://github.com/recastnavigation/recastnavigation

@John i was literally just learning about recast a few nights ago, it seems to be the go-to library for implementing navmesh generation. Great choice, should be performant as well. I think Roblox and Unreal Engine both use it.