Author Topic: 3D Camera Rotation Based on Angles  (Read 2564 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: 3366
  • 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]