can quats do anything?

i’d expect to be able to rotate a vec with a quat, but no. can they do anything?

@RonJeffries - show us your code. I’m assuming you mean quaternions and they can rotate objects. Lots of code here. I posted an example in The Final Frontier.

Correction that was Euler angles.

I have no code, because quat*anything is an error. I see no connection between quat and anything useful. Thus my question. And yes, I see no use of quat in The Final Frontier. :smile:

Here’s an example.

Code updated below.

@RonJeffries Your comment “no, they can’t do much of anything” isn’t true. For Codea, they’re very useful for rotating an object in 3 dimensions without hitting a lock.

Drag your finger on the screen to rotate the box and you’ll notice that you’ll eventually reach points where you can’t rotate the box any more it the direction you were going. You have to change directions and rotate it again and you’ll hit another lock.

Using quat, you can rotate in any direction with hitting a lock.

Use the x,y,z sliders to rotate the box using quat in any direction from -1440 degrees to +1440 degrees. You can increase the slider values if you want and you’ll still not reach a lock.

As for what can be done with all the other quat functions, I don’t know. Not sure what they’re used for.

viewer.mode=STANDARD

function setup()
    limit=1440
    parameter.integer("x",-limit,limit,0)
    parameter.integer("y",-limit,limit,0)
    parameter.integer("z",-limit,limit,0)
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 200)
    v.rx,v.ry=20,20
    createRect()
end

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

function update(dt)
    scene:update(dt)
    c1.rotation = quat.eulerAngles(x,y,z)
end

function createRect() 
    c1=scene:entity()
    w=c1:add(craft.rigidbody,STATIC)
    c1.position=vec3(0,0,0)
    c1.model = craft.model.cube(vec3(25,10,10))
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)
end

I take that as mostly “no, they can’t do much of anything”? I guess we can compose them with each other, sometimes. Maybe? But they can’ t do what quaternions usually do?

@RonJeffries What do you want them to do. There’s a section in the documentation for different quat functions. I don’t use quarts, so I’m not sure exactly what they do other than if you use them, you don’t run into gimbal lock rotating objects.

normally I’d expect to be able to use a quat to rotate vectors. they’re not just a little closed algebra or group or whatever, they can do things like veg*quat = rotated vector.

Anyway I’m asking, can they do anything? Are they connected to anything else in Codea / Lua? @Simeon ?

The same is true of matrices. They can typically be multiplied times vectors to transform the vectors. That happens internally in Codea but can, in principle, be done outside. That requires special handling, if I recall, because you need a column vector x y z 0 on the left.

Anyway, just wondering if they are connected to anything and what they might be useful for.

if you want to connect quats to rotation and see it animate based on your quat you should add a tween, tweens literally make everything connected in Codea

@RonJeffries I don’t know much about it, but before Craft, matrices and quaternions seemed to be discussed an awful lot regarding 3-D stuff.

Is the problem down to the touch and the camera settings in the cameras dependency ?

@Bri_G Not sure what the problem is because Cameras uses quat for rotations.

I understand gymbal lock and that quats deal with that. But quats have math properties, like vectors and matrices, and in fact you can define vector*quat as an operation that rotates the vector according to the quat.

It does turn out that you can multiple two quats together to get a third. That basically “adds” the second “angle” to the first. You could increment an object’s rotation slowly that way.

Are there other operations like * that are undocumented? That’s my question.

@dave1707 @RonJeffries - both the first person viewer and the OrbitViewer cameras are clamped at -90 to +90 so you won’t see continuous circulation plus you’ve got to consider the further away from an object the lower the angle change from touch on the screen.

you can rotate an object slowly by adjusting a quat by multiplying by a quat with incremental angles. here’s dave’s demo modified.

viewer.mode=STANDARD

function setup()
    limit=1440
    parameter.integer("x",-limit,limit,0)
    parameter.integer("y",-limit,limit,0)
    parameter.integer("z",-limit,limit,0)
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 200)
    v.rx,v.ry=20,20
    createRect()
    qq = quat.eulerAngles(1,.1,.3)
    qa = quat.eulerAngles(0,0,0)
end

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

function update(dt)
    scene:update(dt)
    qa = qa*qq
    c1.rotation = qa
end

function createRect() 
    c1=scene:entity()
    w=c1:add(craft.rigidbody,STATIC)
    c1.position=vec3(0,0,0)
    c1.model = craft.model.cube(vec3(25,10,10))
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)
end

I realize it has been a few years, but I found this thread while trying to do the same.

For example, I wanted to draw the gnomon (the RGB lines that represent the XYZ axes of the transform matrix) of an entity.

Here is a simple function that you can use to rotate a vec3 by a quat:

--function rotateVecByQuat(v, q)
function rvq(v, q)
    local u = vec3(q.x, q.y, q.z)
    local s = q.w
    return 2.0 * u:dot(v) * u
         + (s*s - u:dot(u)) * v
         + 2.0 * s * u:cross(v)
end

Adapted from this C++ example:

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
           + (s*s - dot(u, u)) * v
           + 2.0f * s * cross(u, v);
}

In the top answer of the thread here: https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion

Here’s a brief example of how I am using it to draw the transform matrix of an entity:

function setup()
    viewer.mode = FULLSCREEN
    
    world = World()
    scene = world.scene
    cam = scene.camera:get(craft.camera)
    ball = Ball(scene, 1, 1)
    -- More setup code --
end

--function rotateVecByQuat(v, q)
function rvq(v, q)
    local u = vec3(q.x, q.y, q.z)
    local s = q.w
    return 2.0 * u:dot(v) * u
         + (s*s - u:dot(u)) * v
         + 2.0 * s * u:cross(v)
end

function line3D(a, b, c)
    local sa = cam:worldToScreen(a)
    local sb = cam:worldToScreen(b)
    if c then
        stroke(c)
    end
    line(sa.x, sa.y, sb.x, sb.y)
end

function drawMatrix(e, size)
    pushStyle()
    strokeWidth(10)
    local pos = e.position
    local rot = e.rotation
    local ox = rvq(vec3(size,0,0), rot)
    local oy = rvq(vec3(0,size,0), rot)
    local oz = rvq(vec3(0,0,size), rot)
    line3D(pos, pos + ox, color(233, 78, 80))
    line3D(pos, pos + oy, color(78, 233, 98))
    line3D(pos, pos + oz, color(78, 94, 233))
    popStyle()
end

function draw()
    world:update(DeltaTime, ball)

    scene:draw()
    
    drawMatrix(ball.e, 1)
end

Note: This is not a full example but rather a summary of how this can be used with your own entity, which in this case is stored in ball.e

The rvq (rotateVectorByQuat) calls are used to calculate the offsets ox, oy, and oz in the drawMatrix function.

It would be great if we could simply use quat * vec3 or vec3 * quat directly in Codea without needing to add a helper function. Same goes for matrix * vec3 rotation/transformation.