Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Dijkstra fill style tile map lighting.

edited January 10 in Examples Posts: 18

I was reading about how someone was doing lighting inside a minecraft clone and this is where this example comes from. The main goal was to create a lighting system for my current 2d space mining game. I have already put it into it.

The code can be pasted inside codea and should show a lighted random map with a ai random runner with a light. Maybe you need to run it a couple of times for the right map to show up.

I have to figure out still how to do multiple lights. Some kind of temp array per light and blending maybe?

-- Map Torches


-- tilemap with lighting(no multiple torches-untested)
-- basically a 4way dijkstra fill with lower transparancy at every step
-- addtional less transparancy when block 1(solid)
-- ai is a move to target(random destination)

-- Use this function to perform your initial setup
function setup()
    print("Hello World! - restart if weird/stuck")
    mw = 50
    mh = 50
    tw = WIDTH/mw
    th = HEIGHT/mh
    map = {}
    lightmap = {}
    for x=0,mw do
        map[x]={}
        lightmap[x]={}
        for y=0,mh do
            map[x][y]=0
            lightmap[x][y]=0
        end
    end
    for i=1,3 do
        wallrect(math.random(5,30),math.random(5,30),20,3)
    end
    x = math.random(1,mw-1)
    y = math.random(1,mh-1)
    while map[x][y]==1 do
        x = math.random(1,mw-1)
        y = math.random(1,mh-1)
    end
    placetorch(x,y)
    lmpos = vec2(x,y)
    lmdes = vec2(10,10)
    cnt=0
end 

-- This function gets called once every frame
function draw() 
    -- This sets a dark background color 
    background(0,0,0)

    -- move the torch around
    cnt=cnt+1
    if cnt>8 then
        cnt=0

        oldx = lmpos.x
        oldy = lmpos.y
        if lmpos.x < lmdes.x then lmpos.x=lmpos.x+1 end
        if lmpos.y < lmdes.y then lmpos.y=lmpos.y+1 end
        if lmpos.x > lmdes.x then lmpos.x=lmpos.x-1 end
        if lmpos.y > lmdes.y then lmpos.y=lmpos.y-1 end
        if map[lmpos.x][lmpos.y]==1 then
            lmpos.x = oldx
            lmpos.y = oldy
        end
        if math.random()<.1 then
            lmdes.x = math.random(0,mw)
            lmdes.y = math.random(0,mh)
            while lightmap[lmdes.x][lmdes.y]<20 and lmdes:dist(vec2(oldx,oldy))<5 do
                lmdes.x = math.random(0,mw)
                lmdes.y = math.random(0,mh)
            end
        end
        clearlightmap()
        placetorch(lmpos.x,lmpos.y)
    end
    -- Do your drawing here
    drawmap()
    fill(255,255,0)
    stroke(255)
    rect(lmpos.x*tw,lmpos.y*th,tw,th)
end

function clearlightmap()
    for x=0,mw do
        lightmap[x]={}
        for y=0,mh do
            lightmap[x][y]=0
        end
    end
end

function placetorch(x,y)
    orig = vec2(x,y)
    openlist={}
    table.insert(openlist,vec2(x,y))
    lightmap[x][y]=255
    -- left top right bottom of our position
    --switch = {vec2(-1,0),vec2(0,-1),vec2(1,0),vec2(0,1)}
    switch = {vec2(-1,0),vec2(-1,-1),vec2(0,-1),vec2(1,-1),vec2(1,0),vec2(1,1),vec2(0,1),vec2(-1,1)}
    while #openlist>0 do
        x = openlist[1].x
        y = openlist[1].y
        table.remove(openlist,1)
        if lightmap[x][y]>10 and vec2(x,y):dist(orig)<12 then
            for i = 1,#switch do
                pos = vec2(x+switch[i].x,y+switch[i].y)
                if pos.x>=0 and pos.y>=0 and pos.x<mw and pos.y<mh then
                    if lightmap[pos.x][pos.y]==0 then
                        if map[x][y]==0 then
                            lightmap[pos.x][pos.y]=lightmap[x][y]/100*90
                        else
                            lightmap[pos.x][pos.y]=lightmap[x][y]/100*60
                        end
                        if map[pos.x][pos.y]==1 then
                            lightmap[pos.x][pos.y]=lightmap[pos.x][pos.y]/2
                        end
                        if lightmap[pos.x][pos.y]<0 then lightmap[pos.x][pos.y]=0 end
                        if lightmap[pos.x][pos.y]>0 then 
                            table.insert(openlist,vec2(pos.x,pos.y))
                        end
                    end
                 end
            end
        end

    end
    blendlight2(orig.x,orig.y)
end
function blendlight2(x,y)
    for x1 = x-10,x+10 do
    for y1 = y-10,y+10 do
        if x1>=0 and y1>=0 and x1<mw and y1<mh then
            z=0
            d=0
            for y2=y1-1,y1+1 do
                for x2=x1-1,x1+1 do
                    if x2>=0 and y2>=0 and x2<mw and y2<mh then
                        z=z+lightmap[x2][y2]
                        d=d+1

                    end
                end
            end
            lightmap[x1][y1]=z/d      
        end
        end
        end
end
-- this is a flickering style of lighting
function blendlight(x,y)
    for i = 1,(6*6)*100 do
        x1 = x+math.random(-6,6)
        y1 = y+math.random(-6,6)
        if x1>=0 and y1>=0 and x1<mw and y1<mh then
            z=0
            d=0
            for y2=y1-1,y1+1 do
                for x2=x1-1,x1+1 do
                    if x2>=0 and y2>=0 and x2<mw and y2<mh then
                        z=z+lightmap[x2][y2]
                        d=d+1

                    end
                end
            end
            lightmap[x1][y1]=z/d      
        end
    end
end
function wallrect(x,y,w,h)
    for y1=y,y+h do
        for x1=x,x+w do
            if x1>=0 and y1>=0 and x1<mw and y1<mh then
                map[x1][y1]=1
            end
        end
    end
end
function drawmap() 
    for y = 0,mh,1 do
        for x = 0,mw,1 do
            if lightmap[x][y]>0 then
            if map[x][y]==0 then
                fill(40,40,0,lightmap[x][y])
                stroke(40,40,0,lightmap[x][y])
                rect(x*tw,y*th,tw,th)
            end
            if map[x][y]==1 then
                fill(255,155,55,lightmap[x][y])
                stroke(255,155,55,lightmap[x][y])
                rect(x*tw,y*th,tw,th)
                end
            end
        end
    end
end

Comments

  • dave1707dave1707 Mod
    Posts: 9,808

    @Pakz Here’s something I thru together with 2 lights. Not sure if it’s what you’re after. I just put in a bunch of cubes instead of trying to do paths.

    function setup()
        parameter.number("lx1",-50,50,-5)
        parameter.number("lz1",-50,50,-5)
        parameter.number("lx2",-50,50,5)
        parameter.number("lz2",-50,50,0)
    
        scene = craft.scene()
        scene.sun.active = false
        scene.sky.active = false
        scene.ambientColor =  color(26,26,26,255)   
    
        v=scene.camera:add(OrbitViewer, vec3(0,0,0), 50, 0, 3000)
        v.rx,v.ry=30,30
    
        for x=-50,50 do
            for z=-50,50 do
                local floor = scene:entity()
                floor.position=vec3(x,-1,z)
                local r = floor:add(craft.renderer, craft.model.cube(vec3(.5,.5,.5)))
                r.material = craft.material(asset.builtin.Materials.Specular)
            end
        end
    
        light1 = scene:entity():add(craft.light, SPOT)
        light1.angle = 50
        light1.color = color(255)
        light1.entity.y = 5
    
        light2 = scene:entity():add(craft.light, SPOT)
        light2.angle = 50
        light2.color = color(255)
        light2.entity.y = 5
    
        s1=scene:entity()
        s1.position=vec3(0,-1,0)
        s1.model = craft.model.icosphere(.5,2)
        s1.material = craft.material(asset.builtin.Materials.Basic)
    
        s2=scene:entity()
        s2.position=vec3(10,-1,0)
        s2.model = craft.model.icosphere(.5,2)
        s2.material = craft.material(asset.builtin.Materials.Basic)
    end
    
    function draw()
        update(DeltaTime)    
        scene:draw()
    end
    
    function update(dt)
        scene:update(dt)
    
        light1.entity.z = lz1
        light1.entity.x = lx1   
    
        light2.entity.z = lz2
        light2.entity.x = lx2
    
        s1.z = lz1
        s1.x = lx1   
    
        s2.z = lz2
        s2.x = lx2   
    end
    
  • SimeonSimeon Admin Mod
    Posts: 5,759

    @Pakz very cool, tried it out and it looks good. For multiple lights, could you compute them all into a buffer (additively) then use that to render the output?

    @dave1707 I think your way might be considered cheating if the goal is to compute 2D light transport using an algorithm

  • Posts: 18

    I had modified the code and made it so there can be more torches. I did not understand it at first when I should of been adding up the light. I was taking the
    Avarage, but it works now.

    -- Multiple Map Torches
    
    
    -- tilemap with lighting(multiple torches)
    -- basically a 8way dijkstra fill with lower transparancy at every step
    -- walls lower light spread more.
    -- addtional less transparancy when block 1(solid)
    -- ai is a roamer, move to target(random destination inside lightmap)
    
    -- Use this function to perform your initial setup
    function setup()
        print("Hello World! - restart if weird/stuck")
        mw = 50
        mh = 50
        tw = WIDTH/mw
        th = HEIGHT/mh
        map = {}
        lightmap = {}
        lightmapbase = {}-- contains all stationary lights
        for x=0,mw do
            map[x]={}
            lightmapbase[x]={}
            lightmap[x]={}
            for y=0,mh do
                map[x][y]=0
                lightmapbase[x][y]=0
                lightmap[x][y]=0
            end
        end
        for i=1,3 do
            wallrect(math.random(5,30),math.random(5,30),20,3)
        end
    
    
        for i =0,3 do
            x = math.random(1,mw-1)
            y = math.random(1,mh-1)
            while map[x][y]==1 or (map[x][y+1]==0 and map[x][y-1]==0) do
                x = math.random(1,mw-1)
                y = math.random(1,mh-1)
            end
            clearlightmap()
            placetorch(x,y)
            mixlightmaptobase()
        end
        mixlightmaps()
    
        x = math.random(1,mw-1)
        y = math.random(1,mh-1)
        while map[x][y]==1 do
            x = math.random(1,mw-1)
            y = math.random(1,mh-1)
        end
    
        lmpos = vec2(x,y)
        lmdes = vec2(10,10)
        cnt=0
    end 
    
    -- This function gets called once every frame
    function draw() 
        -- This sets a dark background color 
        background(0,0,0)
    
        -- move the torch around
        cnt=cnt+1
        if cnt>8 then
            cnt=0
    
            oldx = lmpos.x
            oldy = lmpos.y
            if lmpos.x < lmdes.x then lmpos.x=lmpos.x+1 end
            if lmpos.y < lmdes.y then lmpos.y=lmpos.y+1 end
            if lmpos.x > lmdes.x then lmpos.x=lmpos.x-1 end
            if lmpos.y > lmdes.y then lmpos.y=lmpos.y-1 end
            if map[lmpos.x][lmpos.y]==1 then
                lmpos.x = oldx
                lmpos.y = oldy
            end
            if math.random()<.1 then
                lmdes.x = math.random(0,mw)
                lmdes.y = math.random(0,mh)
                while lightmap[lmdes.x][lmdes.y]<20 and lmdes:dist(vec2(oldx,oldy))<5 do
                    lmdes.x = math.random(0,mw)
                    lmdes.y = math.random(0,mh)
                end
            end
            clearlightmap()
            placetorch(lmpos.x,lmpos.y)
            --placetorch(lmpos.x,lmpos.y)
            --placetorch(lmpos.x,lmpos.y)
            mixlightmaps()
        end
        -- Do your drawing here
        drawmap()
        fill(255,255,0)
        stroke(255)
        rect(lmpos.x*tw,lmpos.y*th,tw,th)
    end
    -- add current lightmap to lightmap base. count up light particles.
    function mixlightmaptobase()
        for y=0,mh do
            for x=0,mw do
                lightmapbase[x][y]=lightmapbase[x][y]+lightmap[x][y]
                if lightmapbase[x][y]>255 then lightmapbase[x][y]=255 end
    
            end
        end
    end
    -- create our main lightmap for drawing the map
    -- adding the stationary lights(base) with current lightmap.
    -- add up all light particles.
    function mixlightmaps()
        for y=0,mh do
            for x=0,mw do
                lightmap[x][y]=(lightmapbase[x][y]+lightmap[x][y])
                if lightmap[x][y]>255 then lightmap[x][y]=255 end
    
            end
        end
    end
    
    function clearlightmapbase()
        for x=0,mw do
            lightmapbase[x]={}
            for y=0,mh do
                lightmapbase[x][y]=0
            end
        end       
    end
    
    function clearlightmap()
        for x=0,mw do
            lightmap[x]={}
            for y=0,mh do
                lightmap[x][y]=0
            end
        end
    end
    
    function placetorch(x,y)
        orig = vec2(x,y)
        openlist={}
        table.insert(openlist,vec2(x,y))
        lightmap[x][y]=255
        -- left top right bottom of our position
        --switch = {vec2(-1,0),vec2(0,-1),vec2(1,0),vec2(0,1)}
        switch = {vec2(-1,0),vec2(-1,-1),vec2(0,-1),vec2(1,-1),vec2(1,0),vec2(1,1),vec2(0,1),vec2(-1,1)}
        while #openlist>0 do
            x = openlist[1].x
            y = openlist[1].y
            table.remove(openlist,1)
            if lightmap[x][y]>10 and vec2(x,y):dist(orig)<12 then
                for i = 1,#switch do
                    pos = vec2(x+switch[i].x,y+switch[i].y)
                    if pos.x>=0 and pos.y>=0 and pos.x<mw and pos.y<mh then
                        if lightmap[pos.x][pos.y]==0 then
                            if map[x][y]==0 then
                                lightmap[pos.x][pos.y]=(lightmap[x][y]/100)*80
                            else
                                lightmap[pos.x][pos.y]=(lightmap[x][y]/100)*30
                            end
                            if map[pos.x][pos.y]==1 then
                                lightmap[pos.x][pos.y]=lightmap[pos.x][pos.y]/2
                            end
                            if lightmap[pos.x][pos.y]<0 then lightmap[pos.x][pos.y]=0 end
                            if lightmap[pos.x][pos.y]>0 then 
                                table.insert(openlist,vec2(pos.x,pos.y))
                            end
                        end
                     end
                end
            end
    
        end
        blendlight(orig.x,orig.y)
    end
    function blendlight2(x,y)
        for x1 = x-10,x+10 do
        for y1 = y-10,y+10 do
            if x1>=0 and y1>=0 and x1<mw and y1<mh then
                z=0
                d=0
                for y2=y1-1,y1+1 do
                    for x2=x1-1,x1+1 do
                        if x2>=0 and y2>=0 and x2<mw and y2<mh then
                            z=z+lightmap[x2][y2]
                            d=d+1
    
                        end
                    end
                end
                lightmap[x1][y1]=z/d      
            end
            end
            end
    end
    -- this is a flickering style of lighting
    function blendlight(x,y)
        for i = 1,(6*6)*100 do
            x1 = x+math.random(-6,6)
            y1 = y+math.random(-6,6)
            if x1>=0 and y1>=0 and x1<mw and y1<mh then
                z=0
                d=0
                for y2=y1-1,y1+1 do
                    for x2=x1-1,x1+1 do
                        if x2>=0 and y2>=0 and x2<mw and y2<mh then
                            z=z+lightmap[x2][y2]
                            d=d+1
    
                        end
                    end
                end
                lightmap[x1][y1]=z/d      
            end
        end
    end
    function wallrect(x,y,w,h)
        for y1=y,y+h do
            for x1=x,x+w do
                if x1>=0 and y1>=0 and x1<mw and y1<mh then
                    map[x1][y1]=1
                end
            end
        end
    end
    function drawmap() 
        for y = 0,mh,1 do
            for x = 0,mw,1 do
                if lightmap[x][y]>0 then
                if map[x][y]==0 then
                    fill(40,40,0,lightmap[x][y])
                    stroke(40,40,0,lightmap[x][y])
                    rect(x*tw,y*th,tw,th)
                end
                if map[x][y]==1 then
                    fill(255,155,55,lightmap[x][y])
                    stroke(255,155,55,lightmap[x][y])
                    rect(x*tw,y*th,tw,th)
                    end
                end
            end
        end
    end
    
Sign In or Register to comment.