Snippet Coordinate Cameras

uberfoop

~=Admiral Stukov=~
Reaction score
177
Coordinate Cameras

Version History:
7/21/09: Basic system posted
7/22/09: Updated with Toadcop's method for bypassing default terrain mapping
9/16/09: Updated to have better documentation and format
9/17/09: Updated to be more efficient

Requires:
-vJass

Code:
JASS:

//                   Coordinate Cameras
//                       By uberfoop
//
//
//  ->What is this?
//  It is a snippet with functions designed to allow the positioning
//  of the wc3 camera based on spatial coordinates instead of target
//  positions, distance to target, and what have you.
//  Functions use absolute z value.
//  They are instant and apply to all players.
//
//  ->Functions:
//
//  function SetCameraCoord takes real x, real y, real z,...
//  ...real azimuth, real vertical, real roll returns nothing
//  
//  x, y, and z are spatial coordinates of the camera.
//  azimuth is the horizontal rotation of the camera.
//  vertical is the vertical angle of the camera. For example,
//  '30' is 30 degrees up from paralell with the ground.
//  roll is the roll angle of the camera.
//  
//
//  function SetCameraCoordB takes real x, real y, real z,...
//  ...real azimuth, real vertical, real roll returns nothing
//
//  This is the same as SetCameraCoord for everything except vertical.
//  For vertical, this uses the angle down from the zenith. For example,
//  '30' is 60 degrees up from paralell with the ground.
//
//
//  function SetCameraCoordTarget takes real x, real y, real z,...
//  ...real fx, real fy, real fz, real roll returns nothing
//
//  x, y, and z are spatial coordinates of the camera.
//  fx, fy, and fz are spatial coordinates that the camera will face.
//  roll is the roll angle of the camera.

library CoordCameras
private function SetZ takes real z returns nothing
    set z = GetCameraField(CAMERA_FIELD_ZOFFSET)+z-GetCameraTargetPositionZ()
    call SetCameraField(CAMERA_FIELD_ZOFFSET,z,-.01)
    call SetCameraField(CAMERA_FIELD_ZOFFSET,z,.01)
endfunction

globals
    private real ccdist
    private real radazim
    private real radvert
endglobals

function SetCameraCoord takes real x, real y, real z, real azimuth, real vertical, real roll returns nothing
    set radazim = bj_DEGTORAD*azimuth
    set radvert = bj_DEGTORAD*vertical
    set ccdist = 100*Cos(radvert)
    call SetZ(z + 100*Sin(radvert))
    call SetCameraPosition(x + ccdist*Cos(radazim),y + ccdist*Sin(radazim))
    call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE,100,0)
    call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK,vertical,0)
    call SetCameraField(CAMERA_FIELD_ROTATION,azimuth,0)
    call SetCameraField(CAMERA_FIELD_ROLL,roll,0)
endfunction

function SetCameraCoordB takes real x, real y, real z, real azimuth, real vertical, real roll returns nothing
    set radazim = bj_DEGTORAD*azimuth
    set radvert = bj_DEGTORAD*vertical
    set ccdist = 100*Sin(radvert)
    call SetZ(z + 100*Cos(radvert))
    call SetCameraPosition(x + ccdist*Cos(radazim),y + ccdist*Sin(radazim))
    call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE,100,0)
    call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK,90 - vertical,0)
    call SetCameraField(CAMERA_FIELD_ROTATION,azimuth,0)
    call SetCameraField(CAMERA_FIELD_ROLL,roll,0)
endfunction

globals
    private real azim
    private real vert
endglobals

function SetCameraCoordTarget takes real x, real y, real z, real fx, real fy, real fz, real roll returns nothing
    set fx = fx - x
    set fy = fy - y
    set radazim = Atan2(fy,fx)
    set radvert = Atan2(fz - z,SquareRoot(fx*fx + fy*fy))
    set ccdist = 100*Cos(radvert)
    call SetZ(z + 100*Sin(radvert))
    call SetCameraPosition(x + ccdist*Cos(radazim),y + ccdist*Sin(radazim))
    call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE,100,0)
    call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK,bj_RADTODEG*radvert,0)
    call SetCameraField(CAMERA_FIELD_ROTATION,bj_RADTODEG*radazim,0)
    call SetCameraField(CAMERA_FIELD_ROLL,roll,0)
endfunction
endlibrary


[ljass]//===================================================[/ljass]


This is a group of functions which each can be used to set the position and rotation of the Warcraft 3 camera.

In Warcraft 3, the closest distance to camera target useable is 100, and thus you're always moving a camera around some point a notable distance away. This bypasses that by using some vector math to place the camera target in a location such that, with desired camera rotation applied, the camera viewing point is at a specific desired coordinate.
Note that with this system, 'z' denotes absolute z, not z offset from terrain. Additionally, these functions are instant and affect all players.

Functions:
JASS:
function SetCameraCoord takes real x, real y, real z, real a, real v, real roll returns nothing

x, y, and z are the coordinates that the camera viewer will be at. a is the azimuth, the horizontal angle that the camera will face. v is the vertical angle; for this function, it is relative to the x/y plane (ie, a value of 30 will tilt the camera 30 degrees up from the wc3 plane). Roll is the camera roll.

JASS:
function SetCameraCoordB takes real x, real y, real z, real a, real v, real roll returns nothing

Exactly the same as the last one except that rather than having v be the angle offset from the x/y plane, it's the angle offset from the vertical (ie, a value of 30 will be 30 degrees lower than straight up and 60 degrees up from the wc3 plane).

JASS:
function SetCameraCoordTarget takes real x, real y, real z, real fx, real fy, real fz, real roll returns nothing

The x,y,z and roll inputs work exactly like the other two. However, instead of inputting two angles, for this function you input a target coordinate (fx,fy,fz) that you want the camera to face.



Example:
JASS:
call SetCameraCoord(0,0,400,0,-45,0)

This will cause the camera to be 400 above the center of the map, facing eastward and diagonally down at the ground, with a roll of 0.


Example 2:
JASS:

scope spinningthings initializer Init
globals
    private real r = 0
endglobals

private function CALLBACK takes nothing returns nothing
    set r = r + 3
    if r > 360 then
        set r = r - 360
    endif
    //call SetCameraCoord(300*Cos(bj_DEGTORAD*r),300*Sin(bj_DEGTORAD*r),456,180+r,-15,r)
    //call SetCameraCoord(300*Cos(bj_DEGTORAD*r),300*Cos(bj_DEGTORAD*r),456,180+r,-15,r)
    //call SetCameraCoord(300*Cos(bj_DEGTORAD*r),500*Sin(bj_DEGTORAD*r),456,180+r,-15,r)
    //call SetCameraCoordTarget(300*Cos(bj_DEGTORAD*r),500*Sin(bj_DEGTORAD*r),456,0,0,356,r)

    //This next one is a little long, but I'm soooo glad I made it. The calculus on the angles is a little big.
    //call SetCameraCoord(800*Cos(bj_DEGTORAD*r),1300*Sin(bj_DEGTORAD*r),700 + 300*Cos(bj_DEGTORAD*r),bj_RADTODEG*Atan2(1300*Cos(bj_DEGTORAD*r),-800*Sin(bj_DEGTORAD*r)),bj_RADTODEG*Atan2(-300*Sin(bj_DEGTORAD*r),SquareRoot((-800*Sin(bj_DEGTORAD*r))*(-800*Sin(bj_DEGTORAD*r)) + (1300*Cos(bj_DEGTORAD*r))*(1300*Cos(bj_DEGTORAD*r)))),-45+20*Cos(2*bj_DEGTORAD*r))
endfunction


private function Actions takes nothing returns nothing
    call TimerStart(CreateTimer(),.03,true,function CALLBACK)
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(t,Player(0),"-",true)
    call TriggerAddAction(t,function Actions)
endfunction
endscope
If you put this in your map and player one says "-", the callback goes off.
The commented things in the callback will cause simple looping parametric movement around the map origin if uncommented.
 

quraji

zap
Reaction score
144
Nice functions. I just last night was doing a little camera thing and I couldn't for the life of me get good results trying to move the camera around...this is exactly what I needed. Good stuff, and +rep :D
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Updated just now with Toadcop's method for bypassing terrain mapping. It now demands that the exact absolute global z values be inputted rather than z-offset, but it positions the camera at the exact absolute z values rather than acting stupid when terrain heights change.
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Seems to work fine for me. Post what you're doing?



edit: In case anyone was looking at the example 2 I posted, I added a function at the bottom. It's length is kind of a joke, but the results are spectacular, and such kinds of movement should be much shorter when using non-trig parametric equations. It was actually really easy to throw together too, even if it does look long.
 

Viikuna

No Marlo no game.
Reaction score
265
edit.

Didnt read your code properly and suggested you that toadcops z height method you are already using lols.

Anyways, looks neat.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
x, y, and z are the coordinates that the camera viewer will be at. a is the azimuth, the horizontal angle that the camera will face. v is the vertical angle; for this function, it is relative to the x/y plane (ie, a value of 30 will tilt the camera 30 degrees up from the wc3 plane). Roll is the camera roll.

Could you set the names of the variables to these to make it easier to understand (or at the very least comment above/below the function name so we can find this bit of information without having to look up this thread)?

I remember having the idea to create something similar to this awhile back (camera's that moved around like an eye, rather than around the source object (unit/location)), nice work. ;)
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Could you set the names of the variables to these to make it easier to understand (or at the very least comment above/below the function name so we can find this bit of information without having to look up this thread)?
Just added some documentation above all of the code with descriptions of each function, plus I made the angle parameter names better.

Also, I abused the new ljass tags in my post.

I remember having the idea to create something similar to this awhile back (camera's that moved around like an eye, rather than around the source object (unit/location)), nice work. ;)
:)
 

Jesus4Lyf

Good Idea™
Reaction score
397
Is Z in this system absolute Z or Z above the terrain? :)
For what player does SetCameraCoordTarget change the camera? And over any period of time?
JASS:
    local real a = bj_RADTODEG*Atan2(fy - y,fx - x)
    local real v = bj_RADTODEG*Atan2(fz - z,SquareRoot((fx - x)*(fx - x) + (fy - y)*(fy - y)))
    local real tz = GetZ(z + 100*Sin(bj_DEGTORAD*v))
    local real f = 100*Cos(bj_DEGTORAD*v)
    local real tx = x + f*Cos(bj_DEGTORAD*a)
    local real ty = y + f*Sin(bj_DEGTORAD*a)

Store radians and convert to degrees for the one time you use it as deg.

Edit:
You never use fx-x (or y or z same thing) by itself, so you should use private globals instead of locals and the first thing you do in your function should be [LJASS]set fx = fx-x[/LJASS] and so forth.

Why do you include the roll? Could let users do this on their own?

Aside from that, I think I really like this (but am yet to test it). Seems cool.
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Is Z in this system absolute Z or Z above the terrain? :)
For what player does SetCameraCoordTarget change the camera? And over any period of time?
-The functions use absolute z values.
-These are intended to be used like the natives, so they affect all players. Like those functions, unless setting a global real in a local player block causes a failcrash under all circumstances, using these within local blocks should be safe.
-The functions apply instantly.

JASS:
    local real a = bj_RADTODEG*Atan2(fy - y,fx - x)
    local real v = bj_RADTODEG*Atan2(fz - z,SquareRoot((fx - x)*(fx - x) + (fy - y)*(fy - y)))
    local real tz = GetZ(z + 100*Sin(bj_DEGTORAD*v))
    local real f = 100*Cos(bj_DEGTORAD*v)
    local real tx = x + f*Cos(bj_DEGTORAD*a)
    local real ty = y + f*Sin(bj_DEGTORAD*a)

Store radians and convert to degrees for the one time you use it as deg.
Updated, done a little differently in a way that should be slightly more efficient.

Edit:
You never use fx-x (or y or z same thing) by itself, so you should use private globals instead of locals and the first thing you do in your function should be [LJASS]set fx = fx-x[/LJASS] and so forth.
Agreed, except for the fz-z part, since it's only used once. Updated.


Why do you include the roll? Could let users do this on their own?
I could, but it is part of camera orientation and I found it handy to include in the call.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top