Rotating camera in 3D?

This is a pretty good explanation of quaternions

https://www.youtube.com/watch?v=4mXL751ko0w

@ignatz @Crumble but according to this video quaternions are never needed for single axis rotations so why does this bother me when I am only rotating on the Y-axis? Could it be because I am misusing my eulers?

@jrohanian - I would have thought you would be ok rotating on just y. Maybe you should post some code that shows this behaviour.

its just me experimenting with some of the stuff in ignatz ebook

-- hello 3d

-- Use this function to perform your initial setup
function setup()
   camX,camY,camZ=5,100,-100
   lookX,lookY,lookZ=1,15,1
   X,Y,Z=50,0,-1000
   moveZ=5
   angle = 0
   arg = 1
   vy = 0
   camLook = vec3(0,0,0)
   argc = 1
   RX,RY,RZ=0,0,0
   RX2,RY2,RZ2=0,0,0
   targetAngle = 0
   rX,rY,rZ=0.1,0.5,1.0
   mapLevel = 0
   SetupCube(25)

end
function SetupCube(s)
--sprite("Platformer Art:Block Brick")    
   b = Tile(("Platformer Art:Block Brick"), 1)
   b:AddSurface(vec3(-400,0,0),vec3(400,0,-1000),1)
       a = Tile(("Platformer Art:Block Brick"), 3)
   a:AddSurface(vec3(-400,0,0),vec3(-400,200,-1000),0.25)
   a:AddSurface(vec3(-400,0,-1000),vec3(400,200,-1000),0.5)
   a:AddSurface(vec3(400,0,0),vec3(400,200,-1000),0.25)
   a:AddSurface(vec3(-400,0,0),vec3(400,200,0),0.25)
   h = Tile(("Platformer Art:Block Brick"),1)
   h:AddSurface(vec3(-400,200,0),vec3(400,200,-1000),1)

end
-- This function gets called once every frame
function draw()
           print("look x "..lookX.." and look z "..lookZ.." angle "..angle)
   -- This sets a dark background color 
   background(220)
   perspective() -- tells codea we is in the third dimension
   camera(camX,camY,camZ,camLook.x,camLook.y,camLook.z)

 a.mesh:draw()
 b.mesh:draw() 
 h.mesh:draw()


   if CurrentTouch.tapCount == 3 then vy = vy + 1 end
   AdjustCamLook(vy)

end   

function AdjustCamLook(r)
   r=math.rad(r)
   camLook=vec3(math.sin(r),1,math.cos(r))*100
end


wallFloorLibrary = class()

--This class tiles an image across a rectangle of any size and provides a mesh
--You can add as many rectangles as you like to the same mesh
--Each rectangle must be vertical or horizontal, not at an angle, ie floor, roof or walls
Tile=class()

--img = image name or the image itself
--s = scale of image (0.5 reduces by half, 2 doubles its size,
function Tile:init(img,s)
   --if type(img)=="text" then img=readImage(img) end
   img = readImage(img)
   --img=readImage("Platformer Art:Block Brick")
   self.img=img
   self.iw,self.ih=img.width,img.height
   self.mesh=mesh()
   self.mesh.texture=self.img
   self.mesh.shader=shader(Tile.Shader.vertexShader,Tile.Shader.fragmentShader)
   self.scale=s
   self.v,self.t={},{}
end

--The parameters are as follows
--p1 = vec3(x,y,z) = a corner position 
--p2 = vec3(x,y,z) = the diagonally opposite corner position 
--s = scale of image (0.5 reduces by half, 2 doubles its size, default is what was provided in the init function)
function Tile:AddSurface(p1,p2,s)
   s=s or self.scale
   local w,h=self.img.width*s,self.img.height*s
   local d=p2-p1
   local v,t
   if d.x==0 then 
       v={vec3(p1.x,p1.y,p1.z),vec3(p1.x,p1.y,p2.z),vec3(p1.x,p2.y,p2.z),vec3(p1.x,p2.y,p1.z)}
       t={vec2(0,0),vec2(d.z/w,0),vec2(d.z/w,d.y/h),vec2(0,d.y/h)}
   elseif d.y==0 then 
       v={vec3(p1.x,p1.y,p1.z),vec3(p2.x,p1.y,p1.z),vec3(p2.x,p1.y,p2.z),vec3(p1.x,p1.y,p2.z)}
       t={vec2(0,0),vec2(d.x/w,0),vec2(d.x/w,d.z/h),vec2(0,d.z/h)}
   elseif d.z==0 then 
       v={vec3(p1.x,p1.y,p1.z),vec3(p2.x,p1.y,p1.z),vec3(p2.x,p2.y,p1.z),vec3(p1.x,p2.y,p1.z)}
       t={vec2(0,0),vec2(d.x/w,0),vec2(d.x/w,d.y/h),vec2(0,d.y/h)}       
   else return nil
   end
   local seq={1,2,3,3,4,1}
   for i=1,6 do
       table.insert(self.v,v[seq[i]])
       table.insert(self.t,t[seq[i]])
   end  
   self.mesh.vertices=self.v
   self.mesh.texCoords=self.t  
end

Tile.Shader = {
vertexShader = [[

uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
   vColor = color;
   vTexCoord = texCoord;
   gl_Position = modelViewProjection * position;
}

]],
fragmentShader = [[

precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
   lowp vec4 col = texture2D( texture, vec2(mod(vTexCoord.x,1.0), mod(vTexCoord.y,1.0)));
   gl_FragColor = col;
}

]]}

So where is the problem?

@Ignatz same thing, it skips from 180 degrees of rotation to about 270.

Try this for camLook instead of what you have

camLook=vec3(math.sin(r)*1000,1,math.cos(r)*1000)

@Crumble do you have an example of applying quaternions in code? I think I sort of understand them.

@jrohanian No sorry, I had to learn about them in one of the math classes (linear algebra I believe) for my major. Have never applied them in code, and hoped I would never see them again. :smiley:

I wrote a quaternion library for Codea. Search the forum for quaternions to find it.

@jrohanian - here is a really good example

https://coolcodea.wordpress.com/2014/02/04/148-a-code-library-for-3d-rotation-and-flying/

I liked that video, took some code from the forum to visualize the quaternion rotation in Codea:

function setup()
    parameter.number("W",-2,2,1)
    parameter.number("X",-2,2,0)
    parameter.number("Y",-2,2,0)
    parameter.number("Z",-2,2,0)
    m = mesh()
    m:addRect(0,0,1,1)
    m.texture = "Space Art:Red Ship"
    m.shader = qshader()
    m.shader.centre = vec3(0,0,0)
    
    time = {value=0}
    tween(.5, time, {value=1}, {loop=tween.loop.pingpong})
end

function draw()
    background(57, 57, 57, 255)
    perspective()
    camera(0,0,5,0,0,0,0,1,0)

    local t = time.value
    pushMatrix()
    translate(-.8,1.5)
    scale(.3)
    m.shader.q = vec4(1,0,0,0):normalize()
    m:draw()
    translate(1.5,0)
    m.shader.q = vec4(1-t,t,0,0):normalize()
    m:draw()
    translate(1.5,0)
    m.shader.q = vec4(1-t,0,t,0):normalize()
    m:draw()
    translate(1.5,0)
    m.shader.q = vec4(1-t,0,0,t):normalize()
    m:draw()
    popMatrix()
    
    m.shader.q = vec4(W,X,Y,Z):normalize()
    m:draw()
end

function qshader()
    return shader([[
    //
    // A rotation vertex shader
    //
    
    //This is the current model * view * projection matrix
    // Codea sets it automatically
    uniform mat4 modelViewProjection;
    
    // Parameters set by user
    uniform vec3 centre;
    uniform vec4 q;

    //This is the current mesh vertex position, color and tex coord
    // Set automatically
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    // Basic quaternion functions
    mediump vec4 qmult (mediump vec4 p, mediump vec4 q)
    {
        mediump float a = p.x * q.x - p.y * q.y - p.z * q.z - p.w * q.w;
        mediump float b = p.x * q.y + p.y * q.x + p.z * q.w - p.w * q.z;
        mediump float c = p.x * q.z - p.y * q.w + p.z * q.x + p.w * q.y;
        mediump float d = p.x * q.w + p.y * q.z - p.z * q.y + p.w * q.x;
        return vec4(a,b,c,d);
    }
    
    mediump vec4 qconj (mediump vec4 q)
    {
        return vec4(q.x,-q.y,-q.z,-q.w);
    }
    
    mediump vec3 qvmult(mediump vec4 q, mediump vec3 v)
    {
        mediump vec4 p = vec4(0,v);
        mediump vec4 pq = qmult(q,qmult(p,qconj(q)));
        return vec3(pq.yzw);
    }
    
    
    void main()
    {
        //Pass the mesh color to the fragment shader
        vColor = color;
        vTexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
        mediump vec3 pos = position.xyz/position.w - centre;
        pos = qvmult(q,pos);
        pos += centre;
        //Multiply the vertex position by our combined transform
        gl_Position = modelViewProjection * vec4(pos,1);
    }
    
    ]], [[
    //
    // A basic fragment shader
    //
    
    //Default precision qualifier
    precision highp float;
    
    //This represents the current texture on the mesh
    uniform lowp sampler2D texture;
    
    //The interpolated vertex color for this fragment
    varying lowp vec4 vColor;
    
    //The interpolated texture coordinate for this fragment
    varying highp vec2 vTexCoord;
    
    void main()
    {
        //Sample the texture at the interpolated coordinate
        lowp vec4 col = texture2D( texture, vTexCoord );
        // colour by given colour
        col*=vColor;
        //Set the output color to the texture color
        gl_FragColor = col;
    }
    
    ]])
end

thanks