Craft Queries

@Simeon @John @dave1707 - one quick query. In changing aspects of a scene what do you need to destroy then reinitialize. I know you need to destroy an entity but what do you do if you need to destroy the environment - specifically a skybox?

@Bri_G i notice you use can entity:remove(component) to remove a component from an entity. Haven’t tried it myself.

@piinthesky - yes, it looks like the prescribed method for removing entities. I’ve used it in a few projects, but there doesn’t appear to be similar facilities for the Craft setup() including skyBoxes. So far I’ve managed to work this by running the changes in function update() and using collectgarbage() just after to clean up, but this stutters.

@dave1707 - has posted code for examples using entity.destroy()

@Bri_G I’m not sure what you mean by skyboxes. Do you have a simple example showing what it is. Maybe I’ve seen them before but I’m not sure what you’re trying to do so I can’t give any advice.

@dave1707 - the skybox is a 3d cube textured with a 3d scene. Your main object resides inside (usually central) and the images used are like a uniform cricifix on it’s side. @John set them up using the six separate square images originally, but if you remember, after a lot of fiddling he introduced the single combined image.
Typical use as follows:

scene.sky.material.envMap = craft.cubeTexture(desert)

I’ll probably be posting an example later in-line with a demo I’m building.

@Bri_G OK, that brings back memories. So, what exactly do you want to do. If I’m inside the cube looking at one of the walls (image), are you trying to change the image that you’re looking at or change the total image of the whole cube. Changing the image of the whole cube or just one wall is easy if I’m thinking of what you want to do.

Now I remember after looking at this link.

https://codea.io/talk/discussion/9431/skybox

@dave1707 - what I am trying to do is change the whole cube (scenario) programmatically within the project. Not having to drop out of the project and edit the code then rerunning. So basically change the whole cube image. Managed to do it but it needed the use of collectgarbage() - which I regard as a last resort and not the best way to program.

@Bri_G If you can, show a little demo of your skybox code so I can see what you’re having trouble with. That will let me know if my code will help.

@dave1707 - will do, might take a little time though.

@dave1707 - think I got this to work. The routine is part of a much bigger routine so I stripped out irrelevant code and modified slightly. My code is here:

-- skybox demo Bri_G

viewer.mode = FULLSCREEN
function setup()
    --
    cube = asset.documents.Dropbox.SBoxSingle
    mod = asset.builtin.CastleKit.sword_obj
    
    skybox = {
    "canyon2",
    "skyboxTexture",
    "space01a"
    }
    
    parameter.integer("box",1,#skybox,1)
    sb = box
    setScene()
    addModel(mod)
end

function update(dt)
    -- 
    if sb ~= box then
        scene.sky.material.envMap = craft.cubeTexture(cube[skybox[box]])
        sb = box
        collectgarbage()
    end
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()
end

function touched(t)
    --
    if t.state == ENDED then
        box = box + 1
        if box > #skybox then 
            box = 1
        end
    end
end

function setScene()
    --
    scene = craft.scene()
    skyMaterial = scene.sky.material
    skyMaterial.horizon = color(255)
    scene.ambientColor = color(247, 248, 248, 0)
    scene.sky.material.envMap = craft.cubeTexture(cube[skybox[box]])
    scene.camera.position = -scene.camera.forward * 10
end

function addModel(mod)
    -- Create a new entity
    if e then
        e:destroy()
    end
    output.clear()
    e = scene:entity()
    e.model = craft.model(mod)
    e.position = vec3(0,0,0)
    e.scale = vec3(1,1,1)
end

You may recognise a lot of this code, stripped from many demos on the forum. The idea was to be able to change the skybox from a table of several - files in my Dropbox pointed to by the two tables and cube path. This demo doesn’t stutter on changing. Also you can run without the collectgarbage() without problem. I’m saying that but I haven’t checked to see if there is any memory consumption without. My problem was I didn’t check for a change in skybox request so every function draw() completion resulted in a change skybox call - massive memory consumption (assumed).

Now I can work on manipulating either the model or skybox.

Oh, by the way exported my project to zipped file intending to post, but I can’t find the zipped file - where is it saved to? Will append if I find it.

@Bri_G Is there someplace I can get the skybox images for your code.

@Bri_G When you long press on a Codea project and you get a menu, select export, then export a zipped project. You get another menu to Open With. From there you can select where you want it to go. I usually send it to the Dropbox app.

@dave1707 - thanks for that, don’t use it very often so wasn’t sure which option to take. Now exported, unzipped and see only the icon, info.plist and Main.Lua files. So will try to post the image files here.

Got them, but what is SBoxSingle at the start of the code

@dave1707 - that’s just a Dropbox folder to hold a few single skybox images ie one image instead of six.

@Bri_G When you do the export of zipped file, you can also send it to the Files app, Downloads folder. From there it will extract a Codea project and execute it.

@dave1707 - thanks again, looking at that and the downloads folder seems to be on iCloud - I try to avoid using that, prefer Dropbox. Now working on rotating the object image and the skybox independently.

@Bri_G Looking at your above code, it looks like every time you switch skybox images, you’re rereading the image from the Dropbox folder. You should just read them once in setup and assign them to a variable and then use the variable name.
See the example below that I was using. That might speed things up and maybe save on program memory usage.

 function setup()
    canyon2=asset.documents.Dropbox.canyon2
    skyboxTexture=asset.documents.Dropbox.skyboxTexture    
    skybox = {canyon2,skyboxTexture}    
    box=1
    setScene()
end

PS. Sorry, wrong code above. Needed the readImage to read them only once.

function setup()
    canyon2=readImage(asset.documents.Dropbox.canyon2)
    skyboxTexture=readImage(asset.documents.Dropbox.skyboxTexture)   
    skybox = {canyon2,skyboxTexture}    
    box=1
    setScene()
end

@Bri_G Here’s a stripped version of your above code. If flips between the 2 skybox images 60 times per second. Doing the collectgarbage, the code runs without crashing. If I comment out the collectgarbage, it crashes after a few seconds. So I guess using the readImage in setup doesn’t really help because memory usage rises fast and causes the crash.

viewer.mode = FULLSCREEN

function setup()
    canyon2=readImage(asset.documents.Dropbox.canyon2)
    skyboxTexture=readImage(asset.documents.Dropbox.skyboxTexture)   
    skybox = {canyon2,skyboxTexture}    
    box=1
    setScene()
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 4, 4, 100)
end

function update(dt)
    scene:update(dt)
end

function draw()
    update(DeltaTime)
    scene:draw()
    collectgarbage()
    flip()
end

function flip()
    box = box + 1
    if box > #skybox then
        box = 1
    end
    scene.sky.material.envMap = craft.cubeTexture(skybox[box])
end

function setScene()
    scene = craft.scene()
    skyMaterial = scene.sky.material
    skyMaterial.horizon = color(255)
    scene.ambientColor = color(247, 248, 248, 0)
    scene.sky.material.envMap = craft.cubeTexture(skybox[box])
    scene.camera.position = -scene.camera.forward * 10
end

@dave1707 - thanks for the second view and the demo shows it works as expected. Reading the reference page on Craft the scene.sky.material.envMap is a builtin feature of the Craft engine so it may be simpler than we think. I tried to rerun the setupScene() again it works but seems to flip a little not a smooth transition. Still need to play a little to optimise this - thanks again.