# Rotating camera in 3D?

This is a pretty good explanation of quaternions

@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)
a = Tile(("Platformer Art:Block Brick"), 3)
h = Tile(("Platformer Art:Block Brick"),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

end

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)
self.img=img
self.iw,self.ih=img.width,img.height
self.mesh=mesh()
self.mesh.texture=self.img
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)
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

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;
}

]],

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.

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.texture = "Space Art:Red Ship"

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:draw()
translate(1.5,0)
m:draw()
translate(1.5,0)
m:draw()
translate(1.5,0)
m:draw()
popMatrix()

m:draw()
end

//
//

//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);
}

]], [[
//
//

//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