cameras and scenes?

@John @Simeon i would like to have two scenes that i can switch between, each one having an independent OrbitViewer. I was able to make this partially work but unfortunately if i move the camera in the first scene it is also moved in the second scene. Is it possible to have two cameras/orbitViewers with independent locations or do i have to memorise the camera position for each scene and refined the starting position of the single camera at each scene switch?

@piinthesky Is this close to what you’re looking for.

function setup()
    parameter.boolean("red",true)
    fill(255)
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")   
         
    scene1 = craft.scene()    
    v1=scene1.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
    createSphere1(scene1,vec3(-15,0,0),255,0,0)
    
    scene2 = craft.scene()    
    v2=scene2.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
    createSphere1(scene2,vec3(15,0,0),0,255,0)
end

function draw()
    update(DeltaTime)
    text("Slide you finger to move balls.",WIDTH/2,HEIGHT-50)
    text("Move slider to switch scenes.",WIDTH/2,HEIGHT-100)
end

function update(dt)
    if red then
        scene1:update(dt)
        scene1:draw()
    else
        scene2:update(dt)
        scene2:draw()
    end
end

function touched(t)
    if t.state==MOVING then
        if red then
            v1.rx=v1.rx+1
            v1.ry=v1.ry+1
        else
            v2.rx=v2.rx+2
            v2.ry=v2.ry+2
        end
    end
end

function createSphere1(sc,p,r,g,b)
    local pt=sc:entity()
    pt.position=vec3(p.x,p.y,p.z)
    pt.model = craft.model.icosphere(2,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=color(r,g,b)
end

@dave1707 that is what essentially i am doing currently. i don’t see why you need your touches function as the orbitviewer handles the touches itself. if i comment out your touches function, then only the scene2 viewer reacts to touches.

@piinthesky That’s why I added my own touched function. The 2 scenes can be seperated whereas using the OrbitViewer touched function doesn’t seperate them. The OrbitViewer touched function uses the last scene it was added to.

@dave1707 yes that’s the issue. The touch handler in the orbitviewer is not unique to each scene-not sure how to fix that in an elegant way.

@piinthesky - have you tried having two cameras defined which stay at the same relative offset to each other. I thought about that for use in a 3D application. I’m sure Ignatz did that with his spitfire project with a camera view from inside the cockpit and one to the rear. In fact it’s one camera with an offset when you need to switch views.

@piinthesky Not sure what you’re exactly after, here’s another example of 2 different scenes. I altered code from my starter game 22 code to create this. Tap screen to start, tilt screen to turn and slide the parameter slider to change screen. A lot of different scenes could be created, I would do it different though.

function setup() 
    parameter.boolean("xxx",true)
    assert(craft, "Please include Craft as a dependency")

    hgx1,hgx2=Gravity.x,Gravity.x
    speed1,speed2=0,0
    ey1,ey2,ang1,ang2=45,45,0,0
    cameraX1,cameraZ1,cameraX2,cameraZ2=-205,-205,-205,-205
    
    scene1 = craft.scene()
    scene1.camera.position = vec3(cameraX,0,cameraZ)
    scene1.sun.rotation = quat.eulerAngles(45,0,45)
    scene1.ambientColor = color(90,90,90)
    skyMaterial1 = scene1.sky.material
    skyMaterial1.horizon = color(0, 203, 255, 255)    

    scene2 = craft.scene()
    scene2.camera.position = vec3(cameraX,0,cameraZ)
    scene2.sun.rotation = quat.eulerAngles(45,0,45)
    scene2.ambientColor = color(90,90,90)
    skyMaterial2 = scene2.sky.material
    skyMaterial2.horizon = color(255, 0, 162, 255)    
    
    createFloor1() 
    createFloor2() 
    
    for z=1,100 do 
        createSphere1(math.random(-200,200),math.random(-200,200))
        createSphere2(math.random(-200,200),math.random(-200,200))
    end
end

function update(dt)
    if xxx then
        speed2=0
        scene1:update(dt)
        scene1.camera.position = vec3(cameraX1,1,cameraZ1)
        scene1.camera.eulerAngles=vec3(0,ey1,0)
    else
        scene2:update(dt)
        speed1=0
        scene2.camera.position = vec3(cameraX2,1,cameraZ2)
        scene2.camera.eulerAngles=vec3(0,ey2,0)
    end
end

function draw()
    background(0)
    fill(255)
    update(DeltaTime)
    if xxx then
        scene1:draw() 
        if speed1==0 then
            text("Tap screen to start",WIDTH/2,HEIGHT-30)
        end
    else
        scene2:draw()  
        if speed2==0 then
            text("Tap screen to start",WIDTH/2,HEIGHT-30)
        end
    end
    updateCameraPos()        
    checkTilt()  
    drawShip()
end

function touched(t)
    if t.state==BEGAN then
        if xxx then
            ang1=0
            speed1=.5
        else
            ang2=0
            speed2=.5
        end
    end
end

function updateCameraPos()
    if xxx then
        ey1=ey1-ang1
        x1=speed1*math.sin(math.rad(ey1))
        z1=speed1*math.cos(math.rad(ey1)) 
        cameraX1=cameraX1+x1
        cameraZ1=cameraZ1+z1
    else
        ey2=ey2-ang2
        x2=speed2*math.sin(math.rad(ey2))
        z2=speed2*math.cos(math.rad(ey2)) 
        cameraX2=cameraX2+x2
        cameraZ2=cameraZ2+z2
    end
end

function checkTilt()
    if xxx then
        gx1=Gravity.x
        ang1=ang1+(gx1-hgx1)*4
        hgx1=gx1
        if gx1>-.001 and gx1<.001 then
            ang1=0
        end
    else
        gx2=Gravity.x
        ang2=ang2+(gx2-hgx2)*4
        hgx2=gx2
        if gx2>-.001 and gx2<.001 then
            ang2=0
        end
    end
end

function drawShip()
    pushMatrix()
    if xxx then
        translate(WIDTH/2,HEIGHT/2-100)
        rotate(ang1*-30)
        sprite("Tyrian Remastered:Boss A",0,0,300)    translate()
    else
        translate(WIDTH/2,HEIGHT/2-100)
        rotate(ang2*-30)
        sprite("Tyrian Remastered:Boss B",0,0,200)    translate()
    end
    popMatrix()
end

function createFloor1(x,z)
    c1=scene1:entity()
    c1.model = craft.model.cube(vec3(400,1,400))
    c1.position=vec3(x,-.5,z)
    c1.material = craft.material("Materials:Standard")
    c1.material.map = readImage("Surfaces:Desert Cliff Color")
    c1.material.offsetRepeat=vec4(0,0,50,50)
end

function createFloor2(x,z)
    c1=scene2:entity()
    c1.model = craft.model.cube(vec3(400,1,400))
    c1.position=vec3(x,-.5,z)
    c1.material = craft.material("Materials:Standard")
    c1.material.map = readImage("Surfaces:Desert Cliff Normal")
    c1.material.offsetRepeat=vec4(0,0,50,50)
end

function createSphere1(x,z)
    sphere1=scene1:entity()
    sphere1.model = craft.model.icosphere(2,1)
    sphere1.position=vec3(x,1,z)
    sphere1.material = craft.material("Materials:Specular")
    sphere1.material.diffuse=color(255,0,0)
end

function createSphere2(x,z)
    sphere1=scene2:entity()
    sphere1.model = craft.model.icosphere(2,1)
    sphere1.position=vec3(x,1,z)
    sphere1.material = craft.material("Materials:Specular")
    sphere1.material.diffuse=color(0,255,0)
end

@dave1707 @Bri_G i was hoping to ‘elegantly’ use the orbitviewer and the touches handler to treat independently the camera positioning, panning and zooming etc. for the multiple scene case, rather than having to reinvent the wheel.

@John, i think dave1707’s first example above ‘fails’ because the touch is captured by scene1 and never gets to scene2. How does one implement shared touches with touchhandler? there is some code for shared touches but it does not seem to be available as an option?

@dave1707 this seems to work…

function setup()
    parameter.boolean("red",true)
    fill(255)
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")   

    scene1 = craft.scene()    
    scene1.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
    createSphere1(scene1,vec3(-15,0,0),255,0,0)

    scene2 = craft.scene()    
    scene2.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
    createSphere1(scene2,vec3(15,0,0),0,255,0)
    
end

function draw()
    update(DeltaTime)
    text("Slide you finger to move balls.",WIDTH/2,HEIGHT-50)
    text("Move slider to switch scenes.",WIDTH/2,HEIGHT-100)
end

function update(dt)
    if red then
        scene1:update(dt)
        scene1:draw()
    else
        scene2:update(dt)
        scene2:draw()
    end
end

function touched(touch)
    if red then
       touches.handlers[1]:touched(touch)
    else
       touches.handlers[2]:touched(touch)
    end
end

function createSphere1(sc,p,r,g,b)
    local pt=sc:entity()
    pt.position=vec3(p.x,p.y,p.z)
    pt.model = craft.model.icosphere(2,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=color(r,g,b)
end

@piinthesky That sure does work a lot better. Thanks for sharing. I’ll have to keep a copy of that for reference. I wonder how many other things there are that we don’t know about.

@piinthesky I tried creating more scenes, but they don’t seem to work. Change the for loop value so you create different number of scenes. If the number of scenes are 1,2, or 3 they all seem to work OK. If you create 4 or 5 scenes, then only the first and last scenes work OK. Don’t know if it’s my code or the touch handler that not working right.

function setup()
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")  
     
    col={color(255,0,0),color(0,255,0),color(0,0,255),
            color(255,255,0),color(0,255,255)}
    
    parameter.integer("val",1,#col)
    
    sc={}   -- scene table
    
    for z=1,5 do    -- change this to create 1 then 2 then 3,4,5 scenes
        sc[z]=craft.scene()    
        sc[z].camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
        createSphere1(sc[z],vec3(-15,0,0),col[z])
    end
end

function draw()
    update(DeltaTime)
    fill(255)
    text("Scene  "..val,WIDTH/2,HEIGHT-50)
end

function update(dt)
    sc[val]:update(dt)
    sc[val]:draw()
end

function touched(touch)
    touches.handlers[val]:touched(touch)
end

function createSphere1(sc,pos,col)
    local pt=sc:entity()
    pt.position=pos
    pt.model = craft.model.icosphere(2,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=col
end

Hi guys, the whole Camera library and Touches library were never really meant to be used for multiple scenes. It’s probably better to just copy those projects into your project and then modify them as you see fit to fix any issues like this. Calling things manually like @dave1707 is doing is probably the best option.

@dave1707, another try! this might be the correct way to do it (nice to find a way reuse @John ‘s code)

— scenetest2
function setup()
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")  

    col={color(255,0,0),color(0,255,0),color(0,0,255),
            color(255,255,0),color(0,255,255)}

    parameter.integer("val",1,#col)

    sc={}   -- scene table

    for z=1,5 do    -- change this to create 1 then 2 then 3,4,5 scenes
        sc[z]=craft.scene()    
        sc[z].camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
        createSphere1(sc[z],vec3(-15,0,0),col[z])
    end
end

function draw()
    update(DeltaTime)
    fill(255)
    text("Scene  "..val,WIDTH/2,HEIGHT-50)
end

function update(dt)
    sc[val]:update(dt)
    sc[val]:draw()
end

function touched(touch)
    ov=sc[val].camera:get(OrbitViewer)
    ov:touched(touch)
end

function createSphere1(sc,pos,col)
    local pt=sc:entity()
    pt.position=pos
    pt.model = craft.model.icosphere(2,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=col
end

note that the touch.handler is not necessary if there is an explicit touch function call in the main code. in fact in that case the touch.handler call in the orbitviewer.init can also be removed.

@piinthesky That seems to work, but you’re constantly creating the ov table in the touched function as you’re moving your finger.

@dave1707 third time lucky!?

-- scenetest2
function setup()
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")  

    col={color(255,0,0),color(0,255,0),color(0,0,255),
            color(255,255,0),color(0,255,255)}

    parameter.integer("val",1,#col)

    sc={}   -- scene table
    ov={}
    for z=1,5 do    -- change this to create 1 then 2 then 3,4,5 scenes
        sc[z]=craft.scene()    
        sc[z].camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
        createSphere1(sc[z],vec3(-15,0,0),col[z])
        ov[z]=sc[z].camera:get(OrbitViewer)
    end
end

function draw()
    update(DeltaTime)
    fill(255)
    text("Scene  "..val,WIDTH/2,HEIGHT-50)
end

function update(dt)
    sc[val]:update(dt)
    sc[val]:draw()
end

function touched(touch)
    ov[val]:touched(touch)
end

function createSphere1(sc,pos,col)
    local pt=sc:entity()
    pt.position=pos
    pt.model = craft.model.icosphere(2,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=col
end

@piinthesky Good job, that one looks OK. Since the touched function is in this code, the Touches dependency doesn’t have to be checked in Cameras. But it still needs to be checked for the other projects that use OrbitViewer.

@dave1707 - hi, just revisited some old code you provided when I was having trouble with viewers. It was in the a thread about 3D model viewing, and was the final code sample in the thread. You set up a cube of spheres with a line of spheres internally and a further sphere outside the cube. The code allowed you to rotate the camera around the models by changing the viewer x,y and z values.

I thought I’d revisit it after reading this thread and ran into a problem - probably my misinterpretation of the code or the conventions used in the 3D Codea universe. The problem is - when I change values in the X axis the models rotate on the Y axis and vice versa. The Z axis just acts like the expected zoom.

I have heard of some conventions exchanging the Y axis with the Z axis, is that the case here?

@Bri_G Can you give the exact name of the discussion. I’m not finding it and the code doesn’t sound familiar.

@Bri_G I found it, I just didn’t go far enough back. My understanding of the axis is the X axis goes left and right. The Y axis is up and down and the Z axis is forward and backward. When I adjust the sliders, the image rotated on the correct axis.