[JASS] Effect orientation

Level 6
Joined
Jul 3, 2006
Messages
102
I have a beam effect that starts from the hero and goes outwards.
1769597735495.png


I am trying to get this to face upwards/downwards on slopes. I have a function that calculates slopes in both directions, but I can't seem to get the orientation to work correctly
Setting the roll angle rotates the effect around the Z axis to match the hero's facing - this works.
Setting the pitch, yaw angles does not work consistently and seems to be dependent on the roll angle!?

For example, here I have a hardcoded 45 degree pitch angle (roll matches facing angle always) that changes direction depending on the roll angle:
Pitch 45, Yaw 0, Roll 90 (facing north), it beams upwards (that's telling me pitch rotates around X):
1769597996556.png


Pitch 45, Yaw 0, Roll 270 (facing south), it beams downwards:
1769598029451.png


The same effect happens if I hardcode the yaw value.
I don't get why Z rotation would affect the result for X and Y rotation.
Anyone care to explain this situation?
 
Last edited:
If the beam effect is a special effect created via triggers, then you can only change orientation for effects created at point. If the effect is attached to a unit, orientation change won't work.
Effects by default face 0.00 degrees, which is eastward.
  • Roll is along X-axis (positive values rotate in north-to-south direction)
  • Pitch is along Y-axis (positive values rotate in west-to-east direction)
  • Yaw is along Z-axis (value 0 faces east, 90 faces north, 180 faces west and 270 faces south, it works the same way like facing angle for units)
  • Angles must be converted from degrees to radians.

It might be easier to explain on a model with more discerning features than your fiery beam, so let's take footman as example:
  • Special Effect - Create a special effect at <some_loc> using units\human\Footman\Footman.mdl
That footman will face eastward (0.00 degrees).
  • Rotating 90.00 degrees along Roll axis (x-axis) will make the footman lie on his right side
  • Rotating -90.00 degrees along Pitch axis (y-axis) will make the footman lie on his back
  • Rotating 225.00 degrees along Yaw axis (z-axis) will make the footman face south-west

What you should determine is the initial orientation of the beam model itself. For example, if you created a special effect using your fiery beam model and the created effect was facing southward, then the model itself would have a 270.00 degree offset on its yaw axis: You would need to take that offset into account when reorienting the model to face some specific direction.

Try this simple script which will allow you to change effect's orientation via chat messages:
JASS:
function GetAngle takes string s, integer start returns real
    return S2R(SubString(s, start, 0))
endfunction

function SetEffectOrientation takes effect efx returns nothing
    local string text = GetEventPlayerChatString()
    local integer len = StringLength(text)
    local real angle
    local real radians

    if len > 5 and SubString(text, 0, 5) == "-yaw " then
        set angle = GetAngle(text, 5)
        set radians = Deg2Rad(angle)
        call BlzSetSpecialEffectYaw(efx, radians)
        call BJDebugMsg("Yaw: " + R2S(angle))
    elseif len > 6 and SubString(text, 0, 6) == "-roll " then
        set angle = GetAngle(text, 6)
        set radians = Deg2Rad(angle)
        call BlzSetSpecialEffectRoll(efx, radians)
        call BJDebugMsg("Roll: " + R2S(angle))
    elseif len > 7 and SubString(text, 0, 7) == "-pitch " then
        set angle = GetAngle(text, 7)
        set radians = Deg2Rad(angle)
        call BlzSetSpecialEffectPitch(efx, radians)
        call BJDebugMsg("Pitch: " + R2S(angle))
    endif

    set text = null
endfunction

Using the footman model as effect from earlier example, you can use the script in following way:
  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Special Effect - Create a special effect at (Center of (Playable map area)) using units\human\Footman\Footman.mdl
      • Set VariableSet efx = (Last created special effect)
  • Set Orientation
    • Events
      • Player - Player 1 (Red) types a chat message containing -pitch as A substring
      • Player - Player 1 (Red) types a chat message containing -roll as A substring
      • Player - Player 1 (Red) types a chat message containing -yaw as A substring
    • Conditions
    • Actions
      • Custom script: call SetEffectOrientation( udg_efx )
In game use it by writing -pitch, -roll or -yaw, followed by empty space and then by value, e.g. -yaw 225
 
If the beam effect is a special effect created via triggers, then you can only change orientation for effects created at point. If the effect is attached to a unit, orientation change won't work.
Effects by default face 0.00 degrees, which is eastward.
  • Roll is along X-axis (positive values rotate in north-to-south direction)
  • Pitch is along Y-axis (positive values rotate in west-to-east direction)
  • Yaw is along Z-axis (value 0 faces east, 90 faces north, 180 faces west and 270 faces south, it works the same way like facing angle for units)
  • Angles must be converted from degrees to radians.

It was easier to test with a footman indeed and I see the core problem is that the yaw refers to the local model's z axis and this axis gets twisted by the terrain slope. What I would want in effect is to have pitch, roll match the terrain's slope and then calculate pitch,yaw,roll due to the unit's facing by rotating in the global Z axis.

Edit: Ok, I spent some more time on it. It turns out the pitch, yaw, roll angles in warcraft refer to global axes which is not really what they are about normally. So the calculations turn out to be fairly simple:

JASS:
function GetLocZ 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

function GetTerrainSlopeX takes real x, real y returns real
    local real d = 32 // sampling size
    local real h1 = GetLocZ(x + d, y)
    local real h2 = GetLocZ(x - d, y)
    return (h1 - h2) / (2.0 * d)
endfunction

function GetTerrainSlopeY takes real x, real y returns real
    local real d = 32   // sampling size
    local real h1 = GetLocZ(x, y + d)
    local real h2 = GetLocZ(x, y - d)
    return (h1 - h2) / (2.0 * d)
endfunction

// Aligns an effect with respect to the ground slope for the specified facing direction (angle in degrees).
function TerrainAlignEffectDirectional takes effect e, real forwardAngle returns nothing
    local real facingRad
    local real slopeX
    local real slopeY
    local real pitchY
    local real yawX

    set facingRad = forwardAngle * bj_DEGTORAD

    // Terrain slope in world axes
    set slopeX = GetTerrainSlopeX(BlzGetLocalSpecialEffectX(e), BlzGetLocalSpecialEffectY(e))
    set slopeY = GetTerrainSlopeY(BlzGetLocalSpecialEffectX(e), BlzGetLocalSpecialEffectY(e))
    
    // Convert slopes to world-axis rotations
    // Pitch = rotation around GLOBAL Y
    set pitchY = -Atan(slopeX)

    // Yaw = rotation around GLOBAL X
    set yawX = Atan(slopeY)

    call BlzSetSpecialEffectRoll(e, facingRad) // facing (Z)
    call BlzSetSpecialEffectPitch(e, pitchY)   // tilt X slope
    call BlzSetSpecialEffectYaw(e, yawX)       // tilt Y slope
endfunction
 
Last edited:
Back
Top