Author Topic: 3D Camera Rotation Based on Angles  (Read 2822 times)

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
3D Camera Rotation Based on Angles
« on: 2011-Jul-15 »
Is the current method of pointing the camera limited to a 'look at' location point?

My problem is when the player wants to turn around 180°.
Using the 'look at' method and interpolating the old location to the new location, the look point passes directly through the player creating a weird effect.  What I would like is to have the camera rotate around the player, so the 'look at' point path is circular.

I've been working on a custom camera system that lets you specify the camera rotation by using a y-axis rotation (yaw) and an x-axis rotation (pitch).  I'm keeping track of two variables (custom TYPE), 'look_cur' and 'look_dst', and each frame I adjust the camera rotation until it reaches the destination.  The rotation speed for yaw and pitch are specified also.

So far the yaw works great and I can now rotate around a point by specifying an angle.
I'm having a b**ch of a time with the pitch!   :blink:
I'm not even (yet?) considering adding 'roll'!

Could perhaps this feature be added directly to GLBasic as an alternative camera looking option?
You could simply specify the yaw, pitch, roll and the camera will point in that direction.

How, I don't know.  Currently I'm using SIN / COS.  Quaternions or matrices would be better I'm sure, but out of my scope.
If not, no problem.  I'll keep at it until it works.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Re: 3D Camera Rotation Based on Angles
« Reply #1 on: 2011-Jul-15 »
If anybody is curious, here's my camera library so far:
It references my other library code, which is not included, but you should get the idea.

'angle' in the code usually refers to 'yaw'.
Oh, and the pitch isn't specified by an angle, but by how many world units to look up or down.
(well, that's how I INTEND it to work! ha)

Code: (glbasic) [Select]
//------------------------------------------------------------------ C a m e r a
CONSTANT CULLMODE_BOTH% = 0
CONSTANT CULLMODE_FRONT% = 1
CONSTANT CULLMODE_BACK% = -1

CONSTANT FOG_LINEAR% = FALSE
CONSTANT FOG_EXPONENTIAL% = TRUE

CONSTANT DIRECTION_LEFT% = -1
CONSTANT DIRECTION_RIGHT% = 1

//-------------------------------------------------------------- V i e w  P o r t
TYPE TViewPort
box AS TXyWh

FUNCTION Set%: x%, y%=0, w%=-1, h%=-1
VIEWPORT x, y, w, h
IF w <=0 THEN w = _screen.w - x
IF h <=0 THEN h = _screen.h - y
self.box.x = x
self.box.y = y
self.box.w = w
self.box.h = h
ENDFUNCTION

ENDTYPE

TYPE TLook
angle#
pitch#
vector AS TVector // Look's unit vector

FUNCTION Set: angle#, pitch#
self.angle = angle
self.angle = Angle_Clamp(self.angle)
self.pitch = pitch
self.Calculate()
ENDFUNCTION

FUNCTION Rotate: angle#, direction%=DIRECTION_RIGHT
SELECT direction
CASE DIRECTION_RIGHT; INC self.angle, angle
CASE DIRECTION_LEFT; DEC self.angle, angle
ENDSELECT
self.angle = Angle_Clamp(self.angle)
self.Calculate()
ENDFUNCTION

FUNCTION Calculate:
self.vector.x = COS(self.angle)
self.vector.z = SIN(self.angle)
self.vector.y = self.pitch
//self.vector.Normalize()
ENDFUNCTION

ENDTYPE

//------------------------------------------------------------------ C a m e r a
TYPE TCamera
entity AS TEntity
clip_near
clip_far
fov
cull_mode%
look_cur AS TLook
look_dst AS TLook
look_speed# = 45.0 // How many degrees per second to rotate look towards it's destination
fog_colour%
fog_near%
fog_far%

FUNCTION LookSet: angle#, pitch#
self.look_dst.Set(angle, pitch)
ENDFUNCTION

FUNCTION LookSetCurrent: angle#, pitch#
self.look_cur.Set(angle, pitch)
ENDFUNCTION

FUNCTION LookRotate: angle#, direction%=DIRECTION_RIGHT
self.look_dst.Rotate(angle, direction)
ENDFUNCTION

FUNCTION LookUpdate:
LOCAL pitch_speed# = 1.0
LOCAL b_update% = FALSE
LOCAL dir_angle%
LOCAL step_angle#
LOCAL diff_angle#
LOCAL dir_pitch%
LOCAL step_pitch#
LOCAL diff_pitch#

// Update Rotation
dir_angle = Angle_ClosestDirection(self.look_cur.angle, self.look_dst.angle) * -1
step_angle = self.look_speed * (_timer / 1000.0) * dir_angle
diff_angle = ABS(Angle_Diff(self.look_cur.angle, self.look_dst.angle))
IF diff_angle <= ABS(step_angle)
self.look_cur.angle = self.look_dst.angle
ELSE
INC self.look_cur.angle, step_angle
b_update = TRUE
ENDIF

// Update Pitch    BUGGY!
diff_pitch = ABS(self.look_dst.angle - self.look_cur.angle)
dir_pitch = SGN(diff_pitch)
step_pitch = pitch_speed * (_timer / 1000.0) * dir_pitch
IF diff_pitch <= ABS(step_pitch)
self.look_cur.pitch = self.look_dst.pitch
ELSE
INC self.look_cur.pitch, step_pitch
b_update = TRUE
ENDIF

IF b_update THEN self.look_cur.Calculate()
ENDFUNCTION

FUNCTION Initialize: clip_near, clip_far, fov, cull_mode%=BLANK
self.entity.New("Camera", ENTITY_TYPE_CAMERA)
self.clip_near = clip_near
self.clip_far = clip_far
self.fov = fov
IF (cull_mode = BLANK) AND (self.cull_mode = BLANK) THEN cull_mode = CULLMODE_BOTH
IF (cull_mode <> BLANK) THEN self.cull_mode = cull_mode
ENDFUNCTION

FUNCTION Render:
LOCAL look_pos AS TVector
self.LookUpdate()

X_MAKE3D self.clip_near, self.clip_far, self.fov
X_CULLMODE self.cull_mode
IF self.fog_far > 0 THEN X_FOG self.fog_colour, FOG_LINEAR, self.fog_near, self.fog_far

look_pos.Copy(self.entity.position)
look_pos.Add(self.look_cur.vector)
X_CAMERA self.entity.position.x, self.entity.position.y, self.entity.position.z, look_pos.x, look_pos.y, look_pos.z
ENDFUNCTION

FUNCTION Fog: colour%, near%, far%
self.fog_near = near
self.fog_far = far
self.fog_colour = colour
ENDFUNCTION

ENDTYPE

GLOBAL _viewport AS TViewPort
GLOBAL _camera AS TCamera
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline mentalthink

  • Prof. Inline
  • *****
  • Posts: 3371
  • Integrated Brain
    • View Profile
Re: 3D Camera Rotation Based on Angles
« Reply #2 on: 2011-Aug-04 »
Hi Slydog, in the samples of Glbasic, the project of the maze, have it a very good control for the camera, you can tun it 180 degrees, whitout problem.

I try to make something similar whit cos and sin, and if I rebemenber well, if you put in the target the cos,0,sin, and int the camera -cos,0,-sin it´s works, how I say I don´t rebemnber very well.

Thanks for the code Snipet, always this fact it´s a grat trouble in 3D, I desiree if Gernnot can, he´s make a one o couple commands for take more control about it, I think in the forum and I´m the first, in some cases the mathematics, are comples for us.

Thanks Slydog, again
Iván j

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Re: 3D Camera Rotation Based on Angles
« Reply #3 on: 2011-Aug-04 »
Thanks for the tips!  I never checked the example projects since I started GLB, I'll revisit the maze one tonight, appropriate too since my game is a 3D maze game!.

As it stands, my camera routines are completely messed up as I got side tracked with working on my menus again.
And updating my graphics style to a neon / glow look.  (did somebody say 'programmer art'?  =D)

I may just back out of my attempt, and figure a way to use the 'look at' vector instead. 
Really, to rotate 180°, I just need to set a half-way point perpendicular to the start and end locations (and interpolate over time).
The rotation wouldn't be circular, but triangular, but it may not be noticeable.  If it is, my interpolate code may need to use cos/sin.

Like this:
Code: (glbasic) [Select]
H = Half-way point
S = Camera Start
D = Camera Destination

      H
      ^
    / | \
   /  |  \
S <-- o --> D

But I was hoping to separate my camera control code from my game logic by creating an all around camera library.
To be universal, I'd have multiple modes I guess like: LOOK_AT, ROTATE (like I'm trying to do), FOLLOW_PATH, etc.

We'll see, but I'm getting sick of doing library code, I'd say 75% of my game now is just my common library code.
It's delaying my progress on my actual game, but I hate to hard code anything that is appropriate for a library, as I'll need it for my next games!   :P
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]