• 🏆 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!

Using Terrain Z detection

Status
Not open for further replies.
Level 12
Joined
Aug 20, 2007
Messages
866
I have been working on a system thats supposed to reproduce the QuadraticMissile() with more features

My problem has to do with rapid changes in terrain, like the projectile flys over a valley of heights 5-4-1-2-6-2, at each relative/respective location

I can't seem to get the system to accurately predict the new height at each location, even with an appropriate GetZ() detection function

Could anybody who has / had experience with such things help me out?
 
Level 4
Joined
May 17, 2008
Messages
75
If you're using a flying unit for the projectile dummy, the height could be thrown off because of the way flying units change their heights based on the surrounding terrain.

Otherwise, It's hard to tell what the problem is without more information.
 
Level 12
Joined
Aug 20, 2007
Messages
866
I don't mean to be demeaning, but this question was directed at some of the more experienced coders who know how to retrieve terrain Z ( GetZ() function ), and have made spells for it

For the most part, it's not a flying unit, it is a ground unit given flying using the ravencrow ability
 
Level 4
Joined
May 17, 2008
Messages
75
Actually I have experimented with projectile systems.

What are you using to detect the terrain height? (I used GetLocationZ, which is very accurate but not always synced)
 
Level 8
Joined
Jun 20, 2004
Messages
229
um well, assuming you already know how to call the locz function, you can set the units flying height to say 50 assuming it is about the right height for a projectile to begin its travel. Then you simply just have the height change by 50 - z height. If the z height is greater than the 50, then it hits the ground and u remove it. I think it should work both ways, if the origin of the missile is on a flat surface of 0 height and the missle hight is 50, then it will stay at 50 until say a bump of approximately 20 height arrives, then it will set the new missle height to 50 - 20 = 30 new height is 30. Say it shoots over a canyon, and the button of the canyon is -500. Then it will make the height 50 -(-500) = 550 so it stays the same height. This is just out of my head so it should work but might need some tweaking. Test it out and let me know how it works, that is if this is what you are wanting.

EDIT- You may have to make an initial Z height of the origin of the missiles start location. Meaning you will need to save the variable and subtract it from the next LocZ's location. So if a missle starts at a Z height of say 250, and it passes over a canyon of -500, you will have to set the height to 50, but then do Next LocZ - 250. So when the missile starts, a few feet in front say the hill slopes down slightly before the canyon, it will set the height to 50 height - (new locZ(225) - 250) = 50 -(-25) = 75, so it will retain its height. The lower the elevation from the missiles origin, the higher the flying units height will be set. So when the canyon arrives, it will be 50 - (-500 - 250) = 50 - -750 = 800, so the height will now be 800, yet again retaining its flat trajectory. Again, I havent tested it ingame, but this concept should work.
 
Last edited:
Level 12
Joined
Aug 20, 2007
Messages
866
um well, assuming you already know how to call the locz function, you can set the units flying height to say 50 assuming it is about the right height for a projectile to begin its travel. Then you simply just have the height change by 50 - z height. If the z height is greater than the 50, then it hits the ground and u remove it. I think it should work both ways, if the origin of the missile is on a flat surface of 0 height and the missle hight is 50, then it will stay at 50 until say a bump of approximately 20 height arrives, then it will set the new missle height to 50 - 20 = 30 new height is 30. Say it shoots over a canyon, and the button of the canyon is -500. Then it will make the height 50 -(-500) = 550 so it stays the same height. This is just out of my head so it should work but might need some tweaking. Test it out and let me know how it works, that is if this is what you are wanting.

EDIT- You may have to make an initial Z height of the origin of the missiles start location. Meaning you will need to save the variable and subtract it from the next LocZ's location. So if a missle starts at a Z height of say 250, and it passes over a canyon of -500, you will have to set the height to 50, but then do Next LocZ - 250. So when the missile starts, a few feet in front say the hill slopes down slightly before the canyon, it will set the height to 50 height - (new locZ(225) - 250) = 50 -(-25) = 75, so it will retain its height. The lower the elevation from the missiles origin, the higher the flying units height will be set. So when the canyon arrives, it will be 50 - (-500 - 250) = 50 - -750 = 800, so the height will now be 800, yet again retaining its flat trajectory. Again, I havent tested it ingame, but this concept should work.

Hmmm, yeah the first way was how I originally went about it, but like how menace described, there is some kind of lag between height changes (games internal systems)

Uhh, I don't really understand your second method...

So if a missle starts at a Z height of say 250, and it passes over a canyon of -500, you will have to set the height to 50, but then do Next LocZ - 250

I'm not sure what thats supposed to mean exactly (Next LocZ is a function, then you subtract 250 from it, or you get 250 as the next locZ?)

I don't mean to sound stupid, but that description has too much variable representation that I am un-familiar with. [new locZ(225) ???]

EDIT

Actually I have experimented with projectile systems.

What are you using to detect the terrain height? (I used GetLocationZ, which is very accurate but not always synced)

I don't believe there is another method of getting a locations height, how is not always synced??
 
Level 8
Joined
Jun 20, 2004
Messages
229
sorry, what I meant was, when the missile is created, get the Z of that height and set it to a variable and save it. We need to keep that variable alive until the missile is done traveling. Assuming you are moving the missile using a periodic event, just set the missiles height to: 50 - (initial height - current Z height of area) = new height.

I overconfused this for you and said new instead of initial for some reason.

So when missile is created,
Set Initial_MissileZ = LocZ of position of missile. (not exactly correct Im not in editor right now)
Set Missiles Height to 50.

then every .01 or however you are moving the missile,
Set Current_MissileZ = locZ of position of missile. (this is where it was just moved)
Set Missiles Height to 50 - (Initial_MissileZ - Current_MissileZ)

that should be it, i dont know how you would work the saved variable in though. I dont know if simply setting the origin height to the custom value of the unit would work either as it is interger based not real based.
 
Level 4
Joined
May 17, 2008
Messages
75
There should not be any delay in height changes if you change the unit's height at a rate of 0 (which makes it instant). It sounds like the problem is caused by some unit property (like pitch/roll not being zero etc.) or something in the code, but it's nearly impossible to tell without seeing the code or what the flight path looks like.

And several things will desync GetLocationZ:

-walkable doodads (includes stuff like bridges and volcanoes): It's understandable how animated walkable doodads height would not be synced because animation isn't synced. Yet according to my testing, non-animated doodads cause slight GetLocationZ discrepancies too.

-terrain deformation (includes spells like thunderclap as well as triggered terrain deformation) in combination with fog of war: terrain def won't desync it by itself, but fog of war hides the deformation from some players giving them a different GetLocationZ result.

However, if you use GetLocationZ ONLY to set the unit's flying height, it won't desync the game because it affects nothing else (unless it's possible for the GetLocationZ value to selectively cause a divide by zero thread crash in the code).

However, in order to use it for substantial things (such as destroying the projectile if it hits the ground) you'll need to avoid things that will desync it.
 
Level 12
Joined
Aug 20, 2007
Messages
866
@ Tricky - That doesn't make sense to me, but I will try it

@ Menace - Uhh, I suppose, you did not provide the other way of getting terrain Z without using GetLocationZ()
 
Level 4
Joined
May 17, 2008
Messages
75
The only other way I could think of to get the terrain height is with camera targets, which is apparently much less accurate and probably not synced either.

I only asked what you used to get the Z value because you said you used "an appropriate GetZ() detection function" without saying it was GetLocationZ, and I wasn't sure if you were using another viable method I hadn't heard of.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ohhh, sorry

Yeah, instead of GetLocationZ(), I use this

JASS:
function GetZ takes real x, real y returns real
    local location loc = Location(x,y)
    local real z = GetLocationZ(loc)
    call RemoveLocation(loc)
    set loc = null
    return z
endfunction

I ment GetZ() function, because there are crappy-er ways of going about it, appropriate meaning most efficient

I took a look at my code and re-edited it a little using vJASS, I haven't tried every possibility for the Z detection system, but for some reason the best cooperation between the terrain and the projectile comes from when I don't mess with it at all

If I find anything out when I go back to my computer, I will post it here
 
Level 4
Joined
May 17, 2008
Messages
75
Funny, I wrote a function called GetXYZ that does exactly the same thing.

Anyways, the problem does not appear to be caused by this function. What does your code look like in regard to setting the flying height?

Generally it should be something to the effect of:

new fly height = old fly height + (height difference due to arc) + GetZ(old position) - GetZ(new position)
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
Show us what code you have, or we cannot help you...

Ohhh, sorry

Yeah, instead of GetLocationZ(), I use this

JASS:
function GetZ takes real x, real y returns real
    local location loc = Location(x,y)
    local real z = GetLocationZ(loc)
    call RemoveLocation(loc)
    set loc = null
    return z
endfunction

I ment GetZ() function, because there are crappy-er ways of going about it, appropriate meaning most efficient

I took a look at my code and re-edited it a little using vJASS, I haven't tried every possibility for the Z detection system, but for some reason the best cooperation between the terrain and the projectile comes from when I don't mess with it at all

If I find anything out when I go back to my computer, I will post it here

That function isn't at all efficient...

JASS:
library XYZ initializer Init

globals
    private location loc
endglobals

function GetZ takes real x, real y returns real
    call MoveLocation(loc, x, y)
    return GetLocationZ(loc)
endfunction

private function Init takes nothing returns nothing
    set loc = Location(0., 0.)
endfunction

endlibrary

HOWEVER, with rapid changes, the inaccuracies of GetLocationZ can result in it being inaccurate. This may or may not be your problem. This code is, fairly obviously, a lot more complex, but it actually gives accurate results (whether or not the fly height uses same as the graphics of the triangles is another matter).

JASS:
library Z initializer Init

globals
    private location tempL
endglobals

function GetCoordinateZ takes real x, real y returns real
    call MoveLocation(tempL, x, y)
    return GetLocationZ(tempL)
endfunction

function GetZ takes real x, real y returns real
    local real x1 = x - ModuloReal(x, 128.) // top left corner
    local real y1 = y - ModuloReal(x, 128.) + 128.
    local real z1 = GetCoordinateZ(x1, y1)
    local real x3 = x1 + 128. // bottom right
    local real y3 = y1 - 128.
    local real z3 = GetCoordinateZ(x3, y3)
    local real x2
    local real y2
    local real z2
    
    local real A
    local real B
    local real C
    local real D
    
    if (x-x1) < (y1-y) then // in bottom left section
        set x2 = x1
        set y2 = y3
    else
        set x2 = x3 // top right corner
        set y2 = y1
    endif
    set z2 = GetCoordinateZ(x2, y2)
    
    set A = y1*(z2 - z3) + y2*(z3 - z1) + y3*(z1 - z2) // [url=http://local.wasp.uwa.edu.au/~pbourke/geometry/planeeq/]Equation of a plane[/url] ftw
    set B = z1*(x2 - x3) + z2*(x3 - x1) + z3*(x1 - x2) 
    set C = x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)
    set D = -( x1*(y2*z3 - y3*z2) + x2*(y3*z1 - y1*z3) + x3*(y1*z2 - y2*z1) )
    
    return -(A*x + B*y + D) / C
endfunction

private function Init takes nothing returns nothing
    set tempL = Location(0.,0.)
endfunction

endlibrary
 
Level 4
Joined
May 17, 2008
Messages
75
It would seem to be very accurate (picture shows a string of lightnings created across several walkable doodads using AddLightningLoc, which uses GetLocationZ)

However as I said before, walkable doodads can cause the returned value not to be synced.
 

Attachments

  • z.jpg
    z.jpg
    162.8 KB · Views: 142
Level 12
Joined
Aug 20, 2007
Messages
866
Whoops, sorry not efficient at all ><

Yeah I s'pose using a global location would be no comparison

Uhhh.... I do not understand your second getZ function, I really didn't put enough thought into it, but what exactly is it supposed to do??? (or rather, how?)

EDIT - I apologize again for not putting the code here

I don't have internet home, and need to go to the public library to post anything

I did buy a flashdrive, and I can post it soon

@Menace - Ohh, thats nice
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ok, heres my problem that I really couldn't describe so well about the GetLocationZ() in a few simple pictures

The dark blue line is made of dummy units with 0.0 height, they represent the normal height/path of any units moving over the terrain, if they had a height of 0.0

The lighter blue is a line made by lightnings, that are positioned using the same coordinates as the units, except the bottom of the lightning is the GetLocationZ(), and the top is GetLocationZ() + 30

It should be pretty clear what my dilemma is, and why I have such problems with projectile systems that use terrain detection

I noticed a few other systems don't account for such changes, this including the beloved CasterSystem (Vexorian)



If you still don't see the problem, it is that the normal path of a (flying) unit projectile would be influenced by uniformally curving terrain, causing the projectile to move slightly higher or lower than the original shape of its projection(?)

To avoid this, jassers used the GetLocationZ() and simply subtracted/added the the little bit of terrain difference, to keep a nice uniform projection(again,?) from point A to point B

My problem, is that with differences shown using abrupt terrain changes, the GetLocationZ() does not detect how much the projectile's height is actually being changed, but only the terrain height

So instead of getting a nice curve...

.....*..*
...*......*
.*.........*
*...........*

It looks more like this...
........__
......_|..|_
...._|......|_
.._|..........|_
*................*

Which is a pretty crappy curve

I will continues my witchhunt for a decent projectile system that accounts for such things, but for now I will create two functions

One that does not even consider the terrain
A second that does, and is only to be used with curved terrain changes

(Btw, I do thank all who have posted, because you guys were 100% right when it came to uniformly curved terrain)
 

Attachments

  • GetZDeformations2.jpg
    GetZDeformations2.jpg
    634 KB · Views: 110
  • GetZDeformations3.jpg
    GetZDeformations3.jpg
    351.1 KB · Views: 83
Level 4
Joined
May 17, 2008
Messages
75
Ok, so this appears to be caused by the dummy unit, not the code. It interpolates the height of the surrounding terrain like a flying unit does.

If it has the "foot" movement type it generally should not interpolate the surrounding terrain type, but you might want to try changing the unit's "interpolation" fields (though admittedly I don't know quite how those work).

What unit is your dummy unit based off of? Vexorian's is based off the Wisp and so is mine. It does not seem to interpolate height like this.
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
You always use a ground unit not a flying unit to avoid that, then use the add-remove crow form method to be able to set its fly height. My 'more accurate' GetZ only works right on terrain, not cliffs, and not walkable doodads (I very rarely use cliffs due to how utterly bad they normally look). GetLocationZ is inaccurate, but it only shows when you have rapid changes.
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
Did some testing, and unit fly height on ground units uses the same height as GetLocationZ (which disagrees slightly with the ground's graphical display of triangles, but there you go).

So just use GetLocationZ, it works fine for this purpose. If it's not working right, you're doing something wrong, because it's working fine on mine.

You just check cliff heights every time you move.
If your next movement position's cliff level is higher then the current position, decrease 128, if it's lower increase 128, not so hard.

GetLocationZ() already takes it into account.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ok, so this appears to be caused by the dummy unit, not the code. It interpolates the height of the surrounding terrain like a flying unit does.

If it has the "foot" movement type it generally should not interpolate the surrounding terrain type, but you might want to try changing the unit's "interpolation" fields (though admittedly I don't know quite how those work).

What unit is your dummy unit based off of? Vexorian's is based off the Wisp and so is mine. It does not seem to interpolate height like this.

Ohhhhhhhhh, ok

I just used a random projectile from war3's big model selection (random file, I believed I based it off either a peasant or a footman)

Yes, it was in fact a flying unit that used a 0.0, and not a ground unit + crowform

Ok, I will add that the projectiles must be ground units

I'm also gonna do a little looking into of the 'interpolation', because I had always wondered what half the things in the object editor did, and that was on my list

Did some testing, and unit fly height on ground units uses the same height as GetLocationZ (which disagrees slightly with the ground's graphical display of triangles, but there you go).

So just use GetLocationZ, it works fine for this purpose. If it's not working right, you're doing something wrong, because it's working fine on mine.


GetLocationZ() already takes it into account.

Woot, ok, for now the problem is solved (Danke alles!), although when I find out more about the interpolation fields, I don't know where to post the notes/pics (probably a new thread) :thumbs_up:

I'm gonna plus rep you guys both, because it seems appropriate
 
Status
Not open for further replies.
Top