I’m trying to rotate the cameras view, so I was wondering if there is a way to rotate the camera and the cameras view on a Y axis, without having to manipulate the cameras look X and look Z? It just seems like it would be a lot simpler if there was.

I made a class to help with this a long time ago.

```
Cam3D = class()
function Cam3D:init()
self.pos = vec3(0, 5, 0)
self.rot = vec3(90, 0, 0)
self.fov = 45
self.clip = 8192
self.dist = 0
end
function Cam3D:pose()
local dy = math.cos(math.rad(self.rot.x))
local xzMult = 1 - math.abs(math.cos(math.rad(self.rot.x)))
local dx, dz = math.sin(math.rad(self.rot.y)) * xzMult, math.cos(math.rad(self.rot.y)) * xzMult
local upx = math.sin(math.rad(self.rot.z + self.rot.y))
local upy = math.cos(math.rad(self.rot.z))
local upz = math.cos(math.rad(self.rot.z + self.rot.y))
camera(self.pos.x - dx * self.dist, self.pos.y - dy * self.dist, self.pos.z - dz * self.dist, self.pos.x + dx, self.pos.y + dy, self.pos.z + dz, upx, upy, upz)
perspective(self.fov, WIDTH / HEIGHT, 0.05, self.clip)
end
function Cam3D:getRot()
local dy = math.cos(math.rad(self.rot.x))
local xzMult = 1 - math.abs(math.cos(math.rad(self.rot.x)))
local dx, dz = math.sin(math.rad(self.rot.y)) * xzMult, math.cos(math.rad(self.rot.y)) * xzMult
local upx = math.sin(math.rad(self.rot.z + self.rot.y))
local upy = math.cos(math.rad(self.rot.z))
local upz = math.cos(math.rad(self.rot.z + self.rot.y))
return 0 - dx * self.dist, 0 - dy * self.dist, 0 - dz * self.dist, dx, dy, dz, upx, upy, upz
end
```

Just create a new Cam3D object, and you can set its pos and rot vec3s to translate and rotate it. Call its pose() function to position the camera and set the perspective (before you draw your 3D stuff)

@jrohanian - you may find this a bit simpler to work with. Slide the angle parameter to look left and right. All you really need from the code below is the AdjustCamLook function. Just run it each time you change the viewing angle, to adjust the camera look values.

NB if the function stuff at the end of the parameter line is confusing, don’t worry about it, it simply runs AdjustCamLook for you whenever you change Angle, and the parameter is only there just to show you it works.

```
function setup()
parameter.number("Angle",-90,90,0,function() AdjustCamLook(Angle) end)
end
function AdjustCamLook(r)
r=math.rad(r)
camLook=vec3(math.sin(r),0,math.cos(r))*100
end
function draw()
background(50)
perspective()
camera(0,0,300,camLook.x,camLook.y,camLook.z)
sprite("Planet Cute:Character Princess Girl",0,0)
end
```

no, but he just wanted to rotate on y!

Codea’s trig functions use radians not degrees, so you need to convert them

@SkyTheCoder - wrt your code, why do you recalculate all the settings at each draw? Why not calculate them just once when the rotation changes (how does your class allow changes, btw), and store the camera vector for use in draw?

@Ignatz It didn’t occur to me to calculate them only once - easy enough to fix

```
Cam3D = class()
function Cam3D:init()
self.pos = vec3(0, 5, 0)
self.rot = vec3(90, 0, 0)
self.fov = 45
self.clip = 8192
self.dist = 0
self.lastPos = vec3(self.pos.x, self.pos.y - 1, self.pos.z)
self.lastRot = vec3(self.rot.x, self.rot.y - 1, self.rot.z)
self.dy = 0
self.xzMult = 1
self.dx, self.dz = 0, 1
self.upx = 0
self.upy = 1
self.upz = 0
end
function Cam3D:pose()
if self.pos.x ~= self.lastPos.x or self.pos.y ~= self.lastPos.y or self.pos.z ~= self.lastRot.z or self.rot.x ~= self.lastRot.x or self.rot.y ~= self.lastRot.y or self.rot.z ~= self.lastRot.z then
self.dy = math.cos(math.rad(self.rot.x))
self.xzMult = 1 - math.abs(math.cos(math.rad(self.rot.x)))
self.dx, self.dz = math.sin(math.rad(self.rot.y)) * self.xzMult, math.cos(math.rad(self.rot.y)) * self.xzMult
self.upx = math.sin(math.rad(self.rot.z + self.rot.y))
self.upy = math.cos(math.rad(self.rot.z))
self.upz = math.cos(math.rad(self.rot.z + self.rot.y))
end
camera(self.pos.x - self.dx * self.dist, self.pos.y - self.dy * self.dist, self.pos.z - self.dz * self.dist, self.pos.x + self.dx, self.pos.y + self.dy, self.pos.z + self.dz, self.upx, self.upy, self.upz)
perspective(self.fov, WIDTH / HEIGHT, 0.05, self.clip)
self.lastPos = vec3(self.pos.x, self.pos.y, self.pos.z)
self.lastRot = vec3(self.rot.x, self.rot.y, self.rot.z)
end
function Cam3D:getRot()
return 0 - self.dx * self.dist, 0 - self.dy * self.dist, 0 - self.dz * self.dist, self.dx, self.dy, self.dz, self.upx, self.upy, self.upz
end
```

(untested, not on iPad)

@ignatz , I used your code, then modified it a bit to see if it work for what I am trying to do, and it does, but I notice once I rotate to approximately 180 degrees, The cameras rotation will skip forward. It’s really kind of weird. The way I am using it is calling the function every frame with a variable, angle, then adding to and subtracting from the variable to rotate. Is this because of sine and cosine?

@jrohanian - it’s hard to say without seeing exactly how you rotated, but once you start rotating in 3 dimensions, you can’t just add new rotations to previous ones, and there can be discontinuities and problems at 90 and 180 degrees depending on circumstances.

It’s taken me about a year to partly understand it, and I am writing an ebook about it, which I hope to finish.

This post of mine describes some of the problems. It’s not totally accurate, but will give you some idea.

https://coolcodea.wordpress.com/2013/12/28/142-3d-rotations-flying-a-plane/

You are doing rotations in a classic camera on a tripod form, which is what you want for most things. I did some code yonks ago for totally free rotation in space where the camera can roll upside down/sideways etc. If anyones interested I can dig that out.

I have a quaternion rotation class which is the right way to deal with incremental rotations in any direction, but it takes a little explanation

Yeah, mines Quartenion based. Can’t explain it, I think I understood it when I did it, but not any more…

Grab Andrew Stacey’s quartenion library here and stick it in a tab http://www.math.ntnu.no/~stacey/documents/Codea/Library/Quaternion.lua

Then I have a camDir and camUp I define in setup

```
camDir = vec3(0,0,1)
camUp = vec3(0,1,0)
```

Draw with

```
camera(position.x, position.y,position.z, position.x+camDir.x, position.y+camDir.y, position.z+ camDir.z, camUp.x, camUp.y, camUp.z)
```

Where position is where in 3d space the camera is.

Finally in touch

```
--get the horizon for vertical rotation
q = Quaternion.Rotation(math.rad(90),camUp)
horizontal = camDir^q
--rotate camPos around vertical
q = Quaternion.Rotation(math.rad(touch.deltaX/3),camUp)
camDir = camDir^q
--rotate camPos and camUp around horizontal
q = Quaternion.Rotation(math.rad(touch.deltaY/3), horizontal)
camDir = camDir^q
camUp = camUp^q
```

The /3 is just a factor for how fast I wanted it to rotate…

@ignatz yeah I read the section of your eBook on quaternions, but most of it went right over my head. I think i’ll go through it again.

It still goes over my head… @-) There are several ways to derive them - 4D geometry, matrix math, and imaginary numbers - and one day I hope to understand just one of them.