Rendering three/four camera views on a single screen?

Does anyone recall ‘Imagine’ on the PC? Or any modern 3D editor? Three screens of 2D top, left, side and a 3d view of the model. I’d like to create that, but I can’t seem to figure out how to render more than one camera.

I thought that I could setContext() and render to an image, then composite, but I can’t seem to get a 3D viewport onto an image. I haven’t even tried the 2d part yet…

Ideas? Thoughts? Help?

Render your scene three times and change the matrix in between each rendering.

Won’t sure how that will be composited…I’m sure I can google up how to render the scene and change the matrix…the compositing of the 3d output wasn’t working for me.

Is there a function in codea comparable to OpenGL viewport() to limit the drawing to a part of the screen? Because without that, how is it possible to draw on 1/4 th of the screen by just changing the matrix?

Right…hence the idea of drawing o a bitmap and compositing. Probably slow, but could work. I’m going to try to render a 3D view onto a bitmap…

Ah, the good old days on the Amiga. I still have TurboSilver and Imagine on floppy disks in my storage room along with an Amiga 1200. I gave away my Amiga 500 many moons ago. Never tried on a PC though.

Good idea for a similar interface.

Unfortunately, setContext() does not capture the 3D eye, or more specifically, mesh draws are not redirected based on camera eye and context.

Just use clip to limit the viewport. That’s unaffected by the current matrix.

Clipping is a good idea. But you have to take care of the center of your scene then to move it in the right quarter before rendering.

Here’s a prototype for you. I’m not convinced that I have the touch handing quite right, but it moves it roughly in the right direction. Of course, to do it properly one would put everything in a viewport class.

function setup()
    m = mesh()
    ver = {
        vec3(1,0,0),
        vec3(0,1,0),
        vec3(0,0,1),
        vec3(-1,0,0),
        vec3(0,1,0),
        vec3(0,0,1),
        vec3(1,0,0),
        vec3(0,-1,0),
        vec3(0,0,1),
        vec3(-1,0,0),
        vec3(0,-1,0),
        vec3(0,0,1),
        vec3(1,0,0),
        vec3(0,1,0),
        vec3(0,0,-1),
        vec3(-1,0,0),
        vec3(0,1,0),
        vec3(0,0,-1),
        vec3(1,0,0),
        vec3(0,-1,0),
        vec3(0,0,-1),
        vec3(-1,0,0),
        vec3(0,-1,0),
        vec3(0,0,-1)
    }
    c = {}
    vv = {}
    for k,v in ipairs(ver) do
        table.insert(c,color(128+v.x*127,128+v.y*127,128+v.z*127,255))
        table.insert(vv,v)
    end
    
    m.vertices = vv
    m.colors = c
    
    parameter("azimuth",0,2*math.pi,math.pi)
    parameter("zenith",0,math.pi,0)
    parameter("size",.1,5,1)
    dx,dy,dz = 0,0,0
end

function draw()
    background(40, 40, 50)
    clip(0,HEIGHT/2,WIDTH,HEIGHT)
    camera(0,0,10,0,0,0,0,1,0)
    drawObj(vec3(0,2,0))
    clip(0,0,WIDTH,HEIGHT/2)
    camera(0,10,10,0,0,0,1,0,0)
    drawObj(vec3(-2,0,0))
end
    
function drawObj(o)
    perspective(45,WIDTH/HEIGHT)
    
    local ca = math.cos(azimuth)
    local sa = math.sin(azimuth)
    local cz = math.cos(zenith)
    local sz = math.sin(zenith)
    local mt = 
        matrix(
        size,0,0,0,
        0,size,0,0,
        0,0,size,0,
        0,0,0,1        
        )*
        matrix(
        ca,-sa,0,0,
        sa,ca,0,0,
        0,0,1,0,
        0,0,0,1
        ) * matrix(
        1,0,0,0,
        0,cz,-sz,0,
        0,sz,cz,0,
        0,0,0,1
        ) * 
        GravityToMatrix() *
        matrix(
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        o.x+dx,o.y+dy,o.z+dz,1
        )
        
        local j,k,l
    for i = 0,7 do
        j = 2*(i%2)-1
        k = 2*(math.floor(i/2)%2)-1
        l = 2*(math.floor(i/4)%2)-1
    modelMatrix(
        matrix(
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        j,k,l,1
        ) *
        mt
    )
    m:draw()
    end
end

function touched(touch)
    if touch.y > HEIGHT/2 then
        dx = dx + 2*touch.deltaX/WIDTH
        dy = dy + 2*touch.deltaY/HEIGHT
    else
        dx = dx + 2*touch.deltaY/WIDTH
        dy = dy - 2*touch.deltaX/HEIGHT
    end
end

function GravityToMatrix()
    local gxy, gy, gygxy, a, b, c, d
    if Gravity.x == 0 and Gravity.y == 0 then
        a,b,c,d = 1,0,0,0
    else
        gy = - Gravity.y
        gxy = math.sqrt(math.pow(Gravity.x,2) + math.pow(Gravity.y,2))
        gygxy = gy/gxy
        a = math.sqrt(1 + gxy - gygxy - gy)/2
        b = math.sqrt(1 - gxy - gygxy + gy)/2
        c = math.sqrt(1 - gxy + gygxy - gy)/2
        d = math.sqrt(1 + gxy + gygxy + gy)/2
        if Gravity.y > 0 then
                a = a
                b = b
        end
        if Gravity.z < 0 then
                b = - b
                c = - c
        end
        if Gravity.x > 0 then
                c = - c
                d = - d
        end
    end
    a,b,c,d = a,d,-c,-b
    local aa = 2*a*a
    local ab = 2*a*b
    local ac = 2*a*c
    local ad = 2*a*d
    local bb = 2*b*b
    local bc = 2*b*c
    local bd = 2*b*d
    local cc = 2*c*c
    local cd = 2*c*d
    return matrix(
        1 - bb - cc,
        ab - cd,
        ac + bd,
        0,
        ab + cd,
        1 - aa - cc,
        bc - ad,
        0,
        ac - bd,
        bc + ad,
        1 - aa - bb,
        0,
        0,0,0,1
    )
end


Ok, that’s AMAZING! I didn’t think you could have one camera, and then another camera… All in the same draw call, rendering different views! I removed the clip, and then I was even more amazed!

I guess I was stuck in the paradigm of the physical world, where I expected one camera to move around and cause only one draw on the screen.

I see the value of the clip. But I didn’t expect the camera calls to do it to do what they did!

Yes, your touch function was off. Adding the gravity Feature was value above the touch.

Thanks so much for this example!

Yes, your touch function was off.

Well, I had to leave something for others to figure out!

Re Gravity: Partly this was some code I had left over from some experiments with meshes and matrices, which was what made it easy to adapt for this, and partly I really like the idea of using the fact that you can pick up and move an iPad to interact with it.

I’s viewport a class or primitive function? I,m searching for it…

Neither! What I meant was that you would want to define a viewport class. Something like:

Viewport = class()

Viewport:init(t)
    t = t or {}
    self.centre = t.centre -- where I'm looking at
    self.eye = t.eye -- where I'm looking from
    self.up = t.up -- which way is up?
    self.bl = t.bottomLeft -- bottom left corner of region on screen
    self.tr = t.topRight -- top right corner of region on screen
end

Viewport:invoke(object)
    clip(self.bl.x,self.bl,y,self.tr.x,self.tr.y)
    camera(self.centre.x,self.centre.y,self.centre.z,<you get the idea>)
    -- some junk with matrices
    object:draw()
end

But it would need a bit of sitting down with a pen and paper (or finger and iPad) to work out the transformations. You’d also want to know how to transform a vector into and out of the viewport for transmitting, say, touch data.

Gotcha. I can use that to split my screen in quads. As far as translating touch, that’s probably next week…when I figure out how to draw edges without faces…we don’t have a wireframe mode!

Cheap wireframe is with a wireframe texture. But then you have issues with transparency in that what’s underneath won’t be drawn if it is drawn afterwards (so you can’t make use of OpenGL’s depth buffering, you have to do it yourself). Expensive way is to make a new mesh that is a wireframe version of the old one. With a load of auxiliary classes, it’s not an unfeasible task.

I’m thinking that I’ll rip through the mesh vertices and make the expensive version (later) I’m not relaly doing too well on my texture mapping; I can’t seem to really get my head around the uv maps and vertices vs. faces (which I will need to understand later)

The ehole point of this thing is to create something that can read X3D objects (already have that part done) as well as try to create very fundamental ones with the iPad. I’d like a simple “tree” with a few leaves and a brown trunk, for example, so that I can load a mesh and replicate it. I really don’t like putting vertext code in LUA classes. The editor is tooooo slow for that, also.

Andrew, am i correctly interpreting the modelmatrix code to basically mean, “render 8 copies of this object”? Off of the same mesh?

Yes. It’s a cheap way to get a slightly more complicated figure for my original experiments. That’s what gave me the idea for the viewports for your code.

Interesting, because something like this could be used to create a large set of walls or a grid (which is what i started doing originally), i wrote a mesh merge function originally, but I’m likely to try to change it to the modelmatrix. Pretty neat.