Need some help making a look at function.

Not too good at math, and i’ve been struggling to come up with a function to have a camera turn to a particular point. I figured I’d have to get the direction the camera is currently facing, and then some how calculate the direction it supposed to be at so I can use quat.fromToRotation()? I don’t know if i’m on the right track, but if anybody has done this before or wants to attempt it, help me out!

Something like lookAt(objectToRotate, position)?

@John @dave1707 - thought occured to me with this thread - how does the Craft camera relate to the Codea camera ? Are both configrable through a single routine ?

@arismoko This is what I’ve used in the past but not sure if it’s what you’re looking for.

The setDirection function may be useful.

Transform = class()

function Transform:init()
    self.pos = vec3(0, 0, 0)
    self.rot = vec3(0, 0, 0)
    self.scl = vec3(1, 1, 1)
end

function Transform:setDirection(dir, up)
    dir.z = -dir.z
    local q = quat.lookRotation(dir:normalize(), up or vec3(0, 1, 0))
    self.rot = q:angles()
end

function Transform:getDirection()
    return vec3(
        math.cos(self.rot.x) * math.sin(self.rot.y),
        math.cos(self.rot.x) * math.cos(self.rot.y),
        math.sin(self.rot.x)
    )
end

function Transform:getMatrix()
    resetMatrix()
    
    translate(self.pos.x, self.pos.y, self.pos.z)
    rotate(self.rot.y, 0, 1, 0)
    rotate(self.rot.x, 1, 0, 0)
    rotate(self.rot.z, 0, 0, 1)
    scale(self.scl.x, self.scl.y, self.scl.z)
    
    return modelMatrix()
end

function Transform:getAsViewMatrix()
    resetMatrix()
    
    rotate(self.rot.y, 0, 1, 0)
    rotate(self.rot.x, 1, 0, 0)
    rotate(self.rot.z, 0, 0, 1)
    translate(-self.pos.x, -self.pos.y, -self.pos.z)
    
    return modelMatrix()
end

@arismoko This is probably something I should have built-in to the entity class. For now I’ve made this:

    function lookAt(entity, target, up, t)
        local dir = (entity.position - target):normalize()
        local rot = quat.lookRotation(-dir, up or vec3(0, 1, 0))
        if t and t > 0 then 
            entity.rotation = entity.rotation:slerp(rot, t)
        else 
            entity.rotation = rot
        end
    end

This will point an entity towards a given target (I have to negate the direction to make the camera ‘see’ the position. It also lets you set an optional up value and t is used for interpolation if you want to turning to happen over time

@Bri_G Craft’s camera system is separate to Codea’s normal camera functionality. In Codea 4 I’ve unified these more so that you can use the camera class by itself or in a scene

@John Thanks a lot! That’s awesome! (:

This is what I have so far, but it’s definitely not correct lol

function cameraLook(look) local cam = ACTIVESCENE.camera:get(craft.camera) local camPos, camDir = cam:screenToRay(vec2(WIDTH/2,HEIGHT/2)) local forward = quat.lookRotation(camDir,vec3(0,1,0)):angles() return quat.fromToRotation(forward,look):angles() end

@John - thought that could be the case. Bravo on unification in 4. Thanks.

I took one of my examples and stripped it down to just a camera and sphere. I added code for the look at calculations. I don’t understand any quat stuff, but I got it to work anyways. When the program starts, the camera and red sphere are randomly placed somewhere in a 400x400x400 area. When you tap the screen, the camera will rotate to look at the sphere. You can use the sliders to change the x,y,z positions of the camera and sphere. Tap the screen again to point the camera at the sphere. The x,y,z positions are displayed along with the camera quat values and camera to sphere distance.

viewer.mode=STANDARD

function setup()
    print("slide window down")
    assert(craft, "Please include Craft as a dependency")
    parameter.integer("cxPos",-200,200,math.random(-200,200))
    parameter.integer("cyPos",-200,200,math.random(-200,200))
    parameter.integer("czPos",-200,200,math.random(-200,200))
    parameter.integer("sxPos",-200,200,math.random(-200,200),createSphere)
    parameter.integer("syPos",-200,200,math.random(-200,200),createSphere)
    parameter.integer("szPos",-200,200,math.random(-200,200),createSphere)
    direction=vec3(0,0,0)
    scene = craft.scene()    
    skyMaterial = scene.sky.material
    skyMaterial.horizon = color(0, 203, 255, 255)
    createSphere()
    fill(255)
end

function update(dt)
    scene:update(dt)
    scene.camera.position=vec3(cxPos,cyPos,czPos)
end

function draw()
    background(0)
    update(DeltaTime)
    scene:draw()
    dist()
    text("Sphere position  x="..sxPos.."  y="..syPos.."  z="..szPos,WIDTH/2,HEIGHT-50)
    text("Camera position  x="..cxPos.."  y="..cyPos.."  z="..czPos,WIDTH/2,HEIGHT-100)
    text("Camera quat direction  x="..direction.x.."  y="..direction.y.."  z="..direction.z ,WIDTH/2,HEIGHT-125)
    text("Distance from camere to sphere  "..distance,WIDTH/2,HEIGHT-150)
    text("Tap screen to point camera at sphere",WIDTH/2,HEIGHT-250)
    text("Move sliders to change camera and sphere positions",WIDTH/2,HEIGHT-280)

end

function createSphere()
    if sphere then
        sphere:destroy()
    end
    sphere=scene:entity()
    sphere.model = craft.model.icosphere(2,3)
    sphere.position=vec3(sxPos,syPos,szPos)
    sphere.material = craft.material(asset.builtin.Materials.Specular)
    sphere.material.diffuse=color(255,0,0)
end

function touched(t)
    if t.state==BEGAN then
        rotateCamera()
    end
end    

function rotateCamera()
    local diff=-(scene.camera.position-sphere.position):normalize()
    direction=quat.lookRotation(diff,vec3(0,1,0))
    scene.camera.rotation=direction
end

function dist()
    c,s=scene.camera.position,sphere.position
    distance=math.sqrt((c.x-s.x)^2+(c.y-s.y)^2+(c.z-s.z)^2)
end

As I mentioned above, I don’t understand the quat stuff, but I’ve been getting it to work. Here’s an example that uses the slerp function. It took awhile before I knew what it was supposed to do, but it works. This code creates 600 random green spheres just for reference, 1 random red sphere, and a randomly placed camera. When you tap the screen, the slerp function will rotate the camera at varying speeds to center the red sphere on the screen. To restart, just tap the restart icon again.

viewer.mode=FULLSCREEN

function setup()
    assert(craft, "Please include Craft as a dependency")
    scene = craft.scene()    
    skyMaterial = scene.sky.material
    skyMaterial.horizon = color(0, 203, 255, 255)
    
    -- 600 green spheres
    for z=1,600 do
        createSphere(math.random(-200,200),math.random(-200,200),
                math.random(-200,200),color(0,255,0))
    end
    
    -- random red sphere
    sxPos=math.random(-200,200)
    syPos=math.random(-200,200)
    szPos=math.random(-200,200)
    createSphere(sxPos,syPos,szPos,color(255,0,0))
    
    -- random camera position
    cxPos=math.random(-200,200)
    cyPos=math.random(-200,200)
    czPos=math.random(-200,200)

    direction=vec3(0,0,0)
    fill(255)
end

function update(dt)
    scene:update(dt)
    scene.camera.position=vec3(cxPos,cyPos,czPos)
    if rot then
       rotateCamera(.01) 
    end
end

function draw()
    background(0)
    update(DeltaTime)
    scene:draw()
    text("Red sphere position  x="..sxPos.."  y="..syPos.."  z="..szPos,WIDTH/2,HEIGHT-50)
    text("Camera position  x="..cxPos.."  y="..cyPos.."  z="..czPos,WIDTH/2,HEIGHT-100)
    text("Camera quat direction  x="..direction.x.."  y="..direction.y.."  z="..direction.z ,WIDTH/2,HEIGHT-150)
    text("Tap screen to point camera at red sphere",WIDTH/2,HEIGHT-200)
end

function createSphere(x,y,z,c)
    sphere=scene:entity()
    sphere.model = craft.model.icosphere(2,3)
    sphere.position=vec3(x,y,z)
    sphere.material = craft.material(asset.builtin.Materials.Specular)
    sphere.material.diffuse=c
end

function touched(t)
    if t.state==BEGAN then
        rot=true
    end
end    

function rotateCamera(v)
    local diff=-(scene.camera.position-sphere.position):normalize()
    direction=quat.lookRotation(diff,vec3(0,1,0))
    scene.camera.rotation=scene.camera.rotation:slerp(direction,v)
end

@dave1707 code above crashed on me after running several times then scrolling Codea off screen to the iOS apps screen and seconds later got Codea crash alert.

Edit: so far unable to reproduce it.

@Bri_G It doesn’t surprise me if it crashes after a few times. I’m creating a lot of entities each time and Codea might not be cleaning up with restarts. Maybe a collectgarbage() in draw would help it it continues. This was mostly just for show and needs to be coded differently if used for real.