• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

GetCameraTarget/Eye

Status
Not open for further replies.
JASS:
library CameraPosition initializer init

/*
    Getting the target and eye position of a local player's camera is crucial
    for many systems that provide additional UI elements on screen
    (like trackables, lightnings, texttags or special effects).

    These natives, however, update at a much lower frequency in multiplayer games (every ~0.05-0.1 seconds)
    despite not being synced anyway.
    The aim of this system is to provide an alternative to:
       GetCameraTargetPositionX
       GetCameraTargetPositionY
       GetCameraEyePositionX
       GetCameraEyePositionY
    by interpolating returned values between two consecutive value updates.

    It also provides a sanity check in that the following functions will not interpolate if the camera was moved faster than a certain
    configurable MOVEMENT_THRESHOLD per INTERVAL.
    This is to make sure that instant camera movement (f.ex. by left-clicking the minimap) will not trigger the interpolation.
    If you want to disable this feature, simply set MOVEMENT_TRESHOLD to a very large value (like 100.000).

    The configurable MAX_TIMEOUT defines the number of iterations done until a guaranteed return value from GetCameraPosition natives is received. Usually this happens around 0.1 seconds. This is required to find out when the camera has stopped moving.

    API:
    function GetCameraTargetX takes nothing returns real
    function GetCameraTargetY takes nothing returns real
    function GetCameraEyeX takes nothing returns real
    function GetCameraEyeY takes nothing returns real

*/

globals
    //Configurable
    private constant real INTERVAL = 0.03125 //determines the timer speed for update intervals; recommended value: 0.3125
    private constant real MOVEMENT_THRESHOLD = 100 //determines the distance a camera can move within INTERVAL before the camera movement is assumed to be instant
    private constant real MAX_TIMEOUT = 0.09 //determines the maximum time span over which the camera data will be interpolated if no new value is received (when the camera stopped moving)

    private real TargX = 0.
    private real TargY = 0.
    private real EyeX = 0.
    private real EyeY = 0.
    private real lastTargX = 0.
    private real lastTargY = 0.
    private real lastEyeX = 0.
    private real lastEyeY = 0.
    private real vXTarg = 0.
    private real vYTarg = 0.
    private real vXEye = 0.
    private real vYEye = 0.
    private real timeout = 1.
endglobals

function GetCameraTargetX takes nothing returns real
    return TargX
endfunction
function GetCameraTargetY takes nothing returns real
    return TargY
endfunction
function GetCameraEyeX takes nothing returns real
    return EyeX
endfunction
function GetCameraEyeY takes nothing returns real
    return EyeY
endfunction

private function update takes nothing returns nothing
    local real tx = GetCameraTargetPositionX()
    local real ty = GetCameraTargetPositionY()
    local real ex = GetCameraEyePositionX()
    local real ey = GetCameraEyePositionY()
    if tx != lastTargX or ty != lastTargY or ex != lastEyeX or ey != lastEyeY then
        set vXTarg = (tx - lastTargX) / timeout
        set vYTarg = (ty - lastTargY) / timeout
        set vXEye = (ex - lastEyeX) / timeout
        set vYEye = (ey - lastEyeY) / timeout

        if vXTarg > MOVEMENT_THRESHOLD or vYTarg > MOVEMENT_THRESHOLD or vXEye > MOVEMENT_THRESHOLD or vYEye > MOVEMENT_THRESHOLD then
            set vXTarg = 0
            set vYTarg = 0
            set vXEye = 0
            set vYEye = 0
        endif

        set TargX = tx
        set TargY = ty
        set EyeX = ex
        set EyeY = ey
        set lastTargX = tx
        set lastTargY = ty
        set lastEyeX = ex
        set lastEyeY = ey
        set timeout = 1
    else
        if (timeout*INTERVAL) >= MAX_TIMEOUT then
            set vXTarg = 0
            set vYTarg = 0
            set vXEye = 0
            set vYEye = 0
            set TargX = tx
            set TargY = ty
            set EyeX = ex
            set EyeY = ey
            set timeout = 1
        else
            set TargX = TargX + vXTarg
            set TargY = TargY + vYTarg
            set EyeX = EyeX + vXEye
            set EyeY = EyeY + vYEye
            set timeout = timeout + 1
        endif
    endif
endfunction

private function init takes nothing returns nothing
    call TimerStart(CreateTimer(), INTERVAL, true, function update)
endfunction

endlibrary
 
Last edited:
I had no idea that the accuracy changed in multiplayer! Good to know.

Could you explain your script a little? (anything dealing with a bunch of reals can get pretty confusing to read) Specifically:
JASS:
if vXTarg > MOVEMENT_TRESHOLD or vYTarg > MOVEMENT_TRESHOLD or vXEye > MOVEMENT_TRESHOLD or vYEye > MOVEMENT_TRESHOLD then
    set vXTarg = 0
    set vYTarg = 0
    set vXEye = 0
    set vYEye = 0
endif

This part.
 
I tried applying that here but still, it gets left behind by the player camera. Maybe because the camera's update rate is just too high.
Uhh, thanks for this report!
I actually made a mistake in my code and forgot to update the lastTargX/Y and lastEyeX/Y values.

I updated the TO and it should work properly now!

And also very very minor mistake, it should be MOVEMENT_THRESHOLD.
Fixed. Thanks!


I had no idea that the accuracy changed in multiplayer! Good to know.

Could you explain your script a little? (anything dealing with a bunch of reals can get pretty confusing to read) Specifically:
JASS:
if vXTarg > MOVEMENT_TRESHOLD or vYTarg > MOVEMENT_TRESHOLD or vXEye > MOVEMENT_TRESHOLD or vYEye > MOVEMENT_TRESHOLD then
    set vXTarg = 0
    set vYTarg = 0
    set vXEye = 0
    set vYEye = 0
endif

This part.
Basicly, it checks if the current return value of GetCameraTargetPosition and GetCameraEyePosition is different from the last return value (= the camera has moved).
If it is, it compares how many iteration intervals have passed since the last position change to calculate the X and Y velocity of the camera movement.
The part you quoted is just there to prevent the system from interpolating when the camera was moved instantly (either via trigger or by pressing spacebar or clicking on the minimap).
Then it simply uses that speed to interpolate the camera coordinates.

EDIT:
I just noticed that there is still a flaw in the system in that it continues to interpolate if the camera stops moving. I'll think of a fix for this.

EDIT2:
Now fixed this by incorporating a reset timer for the X and Y velocity values.
 
Last edited:
I was about to tell you that.
Maybe put a MIN_THRESHOLD wherein it will not interpolate when the movement per 1/32 sec is less than that threshold?
This would fail in some cases.
I fixed it by simply capping the number of maximum intervals it will interpolate between two data sets.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I doubt increasing the threshold will do anything since camera movement I measured has an average of 93 (only horizontal movement). But what's actually intruiging is, sometimes the change in x is 48, sometimes 140 but mostly 93 (not exactly 93, it is not a whole number). You could try and conduct your own test to see if it's really that weird.

Btw, here's the explanation to my vague answer
http://idioms.thefreedictionary.com/more+or+less
 
I doubt increasing the threshold will do anything since camera movement I measured has an average of 93 (only horizontal movement). But what's actually intruiging is, sometimes the change in x is 48, sometimes 140 but mostly 93 (not exactly 93, it is not a whole number). You could try and conduct your own test to see if it's really that weird.

Btw, here's the explanation to my vague answer
http://idioms.thefreedictionary.com/more+or+less
This is expected because as I said, the Camera natives don't update on a regular predictable interval... it seems to fluctuate based on hardware load.

I'll run some tests on this system at home.
 
Tested this now (used Threshold = 300 and 0.09 for the reset timer) and ... yeah ... i see what you mean.
The problem is that there is no way to know if the player stopped moving the camera.
I'll see if I can come up with a better solution... maybe one that actually smooths out the movement to prevent the "jitter" by using acceleration and velocity instead of just velocity.

This will cause the movement of UI elements to be always a tad behind the camera movement... but at least they will look nice and smooth that way.
 
Status
Not open for further replies.
Top