I'm a bit late to the party. But I was wondering if Blizzard meant to do yaw/pitch/roll for special effects the way they implemented it or if they misassigned the axes.
In normal wc3 axes, we would consider (in this specific order):
yaw - rotation around the Z axis (i.e., the facing of a unit)
pitch - subsequent rotation around the NEW y axis (i.e., looking up or looking down)
roll - subsequent rotation around the NEW x axis (i.e., like a plane rolling)
However, blizzard implemented yaw/pitch/roll differently for special effects (in this specific order):
roll - rotation around the Z axis
pitch - rotation around the OLD Y axis
yaw - rotation around the OLD X axis
Now, this may not seem like a big deal, but it complicates pointing models towards somewhere a lot. The current situation makes sense for objects that are facing UP (for example, a torch). However, most models are facing to the RIGHT (i.e., positive X axis, all missiles). Right now, I think the quickest solution to orient right-facing models is by using quaternions. I've written the following method to rotate X facing models upwards before applying whatever the user actually wanted to do, but this requires a lot of computing power. If a model is supposed to change direction a lot (for instance with missiles), it would still be faster to use units with the dummy model, which I can't imagine was the point of introducing the Orientation natives for special effects.
JASS:
method setOrientation takes real yaw, real pitch, real roll returns nothing
// preset reals for a -pi/2 rotation around y
local real w2 = 0.707107
local real x2 = 0.0
local real y2 = 0.707107
local real z2 = 0.0
// get a quaternion from the user input
local real cy = Cos(yaw/2)
local real sy = Sin(yaw/2)
local real cp = Cos(pitch/2)
local real sp = Sin(pitch/2)
local real cr = Cos(roll/2)
local real sr = Sin(roll/2)
local real w1 = cy * cr * cp + sy * sr * sp
local real x1 = cy * sr * cp - sy * cr * sp
local real y1 = cy * cr * sp + sy * sr * cp
local real z1 = sy * cr * cp - cy * sr * sp
// multiply the quaternions to get a new rotation
local real w3 = -x1*x2 - y1*y2 - z1*z2 + w1*w2
local real x3 = x1*w2 + y1*z2 - z1*y2 + w1*x2
local real y3 = -x1*z2 + y1*w2 + z1*x2 + w1*y2
local real z3 = x1*y2 - y1*x2 + z1*w2 + w1*z2
// calculate the new yaw/pitch/roll
local real sinr = 2*(w3*x3+y3*z3)
local real cosr = 1 - 2 * (x3*x3+y3*y3)
local real sinp = 2 * (w3*y3 - z3*x3)
local real siny = 2 * (w3*z3 + x3*y3)
local real cosy = 1 - 2*(y3*y3 + z3*z3)
set roll = Atan2(sinr,cosr)
set yaw = Atan2(siny,cosy)
if sinp > 1 then
set pitch = 1.57079632
elseif sinp < -1 then
set pitch = -1.57079632
else
set pitch = Asin(sinp)
endif
call BlzSetSpecialEffectOrientation(this.fx, yaw, pitch, roll)
endmethod
So I guess this is a bug report. Please fix the axes assignments for the special effects and the order to be consistent with the rest of the wc3 world
Thanks for everything blizzies!
If I'm overlooking something painfully obvious, please let me know!
EDIT:
It seems that there is a simpler method for lookat. assuming a LookAt vector v:
JASS:
set yaw = Atan2(v.y, v.x)
set pitch = Atan2(v.z, SquareRoot(v.x*v.x + v.y*v.y))
call BlzSetSpecialEffectOrientation(fx, Sin(yaw)*pitch,-Cos(yaw)*pitch,yaw)
Still, having the rotating frame makes more sense imo.