Howdy, Stranger!

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

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)?

Tagged:

Comments

  • edited January 18 Posts: 51

    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
  • Posts: 2,689

    @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 ?

  • Posts: 412

    @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
    
  • JohnJohn Admin Mod
    Posts: 762

    @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

  • Posts: 51

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

  • Posts: 2,689
    @John - thought that could be the case. Bravo on unification in 4. Thanks.
  • dave1707dave1707 Mod
    edited January 20 Posts: 9,977

    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
    
  • dave1707dave1707 Mod
    edited January 20 Posts: 9,977

    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
    
  • edited January 20 Posts: 2,689

    @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.

  • dave1707dave1707 Mod
    edited January 20 Posts: 9,977

    @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.

Sign In or Register to comment.