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.
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
@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 , 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.
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.
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.
@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?
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;
}
]]}
@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.
Comments
I made a class to help with this a long time ago.
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)
@SkyTheCoder thanks, i'll try that out and see if it helps me to make sense of this.
@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.
@Ignatz But with that, can you look up and down, and tilt the camera?
no, but he just wanted to rotate on y!
@ignatz Looks great, what is the importance of using math.rad?
@SkyTheCoder your code looks like something I might have to work up to a bit, though.
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
(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.
@Spacemonkey for sure!
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
Draw with
Where position is where in 3d space the camera is.
Finally in touch
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.
@ignatz as long as I know how to use it i'll try not to worry too much about how it works.
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
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
@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:
thanks