1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  4. Choose your ride to damnation in the 5th Special Effect Contest Poll.
    Dismiss Notice
  5. The winners of the 13th Techtree Contest have been announced!
    Dismiss Notice
  6. The 13th Music Contest Poll is up! Vote for the best tracks in this symphony of frost and flame.
    Dismiss Notice
  7. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

SetEffectOrientation with facing

Discussion in 'Triggers & Scripts' started by IcemanBo, Aug 18, 2018.

  1. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,236
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Hello guys,

    some time ago when trying around with Effect natives I had no luck to effecively bring to work
    BlzSetSpecialEffectOrientation(yaw, pitch, roll)
    for my needs. The other parts I needed worked pretty fast, so this is now pretty frustrating for me, as I tried too many attempts already without real success.

    My problem is the EffectOrientation works only with yaw, pitch roll, (x,y, z - axis rotation respectively), and not with facing.
    In my case, I want to convert a 3D facing between two points to those axis rotations so I can use the native.

    Here is some attempt, but I changed it too many times, so the current state is kind of pending ( so don't care is something makes no sense):

    Code (vJASS):

    function SetEffectFacingXYZ takes effect e, real x_target, real y_target, real z_target  returns nothing
        local real x_effect = BlzGetLocalSpecialEffectX(e)
        local real y_effect = BlzGetLocalSpecialEffectY(e)
        local real z_effect = BlzGetLocalSpecialEffectZ(e)
     
        local real dx = x_target - x_effect
        local real dy = y_target - y_effect
        local real dz = z_target - z_effect
     
        local real effect_abs = SquareRoot(x_effect*x_effect + y_effect*y_effect + z_effect*z_effect)
        local real target_abs = SquareRoot(x_target*x_target + y_target*y_target + z_target*z_target)
        local real distance   = SquareRoot(dx*dx + dy*dy + dz*dz)
     
        local vector v
        local vector v_plane
     
        local real yaw   = 0
        local real pitch = 0
        local real roll  = 0
     
        call ClearTextMessages()
     
        //Projektion in xy
        set v = vector.create(dx, dy, dz)
        set v_plane = vector.create(0, 0, 1)
        call v.projectPlane(v_plane)
     
        //set v_plane.x = dx
        //set v_plane.y = 0//dy
        set v_plane.z = 0//dz
        set v_plane.x = 1
        if (v.x < 0) then
            set roll = vector.getAngle(v, v_plane)
        else
            set roll = vector.getAngle(v, v_plane)
        endif
     
        // Projektion in xz
        /*
        set v.x = dx
        set v.y = dy
        set v.z = dz
        set v_plane.x = 0
        set v_plane.y = 1
        set v_plane.z = 0
        call v.projectPlane(v_plane)
        if v.x <= 0 then
            set v_plane.z = -1
            set yaw = vector.getAngle(v, v_plane)
            if (yaw != 0) then
                set yaw = yaw - bj_PI/2
            endif
       
            call BJDebugMsg("yaw 1: " + R2S(yaw))
        else
            set v_plane.z = 1
            set yaw = vector.getAngle(v, v_plane)
            if (yaw != 0) then
                set yaw = yaw - bj_PI/2
            endif
            call BJDebugMsg("yaw 2: " + R2S(yaw))
        endif
        set yaw = RAbsBJ(yaw)
        */

     
        /*
        // Projektion in yz
        set v.x = dx
        set v.y = dy
        set v.z = dz
        set v_plane.x = 1
        set v_plane.y = 0
        set v_plane.z = 0
        call v.projectPlane(v_plane)
        set v_plane.x = 0
        set v_plane.y = 0
        if v.z <= 0 then
            set v_plane.y = 1
            set pitch = vector.getAngle(v, v_plane) - bj_PI/4// + bj_PI/2
            call BJDebugMsg("pitch 1: " + R2S(pitch))
        else
            set v_plane.y = -1
            set pitch = vector.getAngle(v, v_plane) + bj_PI/2 + bj_PI*2 + bj_PI/4
            call BJDebugMsg("pitch 2: " + R2S(pitch))
        endif
        */

     
        //call BJDebugMsg("yaw: " + R2S(yaw))
        call BJDebugMsg("roll: " + R2S(roll))
        call BlzSetSpecialEffectOrientation(e, yaw, pitch, roll)
     
        //call BlzSetSpecialEffectOrientation(e, 0, 0, 0)
        //call BlzSetSpecialEffectOrientation(e, yaw, pitch, roll)
     
        call v.destroy()
        call v_plane.destroy()
    endfunction

    endlibrary


    Basically, I want a function that lets an effect face the point xyz.

    I'm using this in an orbital movement system, I tried to finish. You can ignore maybe the texts, but the demo, as the texts are about movement, and not orientation.
    In the attached demo, there's a trigger "Orbit Demo 2 Copy" (the only demo that is activated^^), which calls the function
    SetEffectFacingXYZ
    . In my opinon the given parameters are always connrect, and I tested it much. The effect movement also always works as expected, so this also would mean x/y/z are given correctly. But my problem is the called 3D facing-to-orientation is not working.

    ---

    It's pretty easy to get it working with converting only 1 axis rotation, so let's say only x-axix, so on a plane, but somehow I don't get it done properly when rotating around all three axis.
     
  2. Drake53

    Drake53

    Joined:
    Jan 1, 2018
    Messages:
    208
    Resources:
    0
    Resources:
    0
    This also took me awhile to get working (although still didn't manage to get the pitch/yaw/roll directly from the vectors).
    I had it working for a cameraobject before so I used that as basis to get a rotation matrix (camera and special effect have different order of rotation if I'm not mistaken).

    If you're not using roll, your xyz input is the tangent vector, and you can get the other two by using cross products.
    Here is my code, hope this helps.

    Code (vJASS):
        globals
            constant real EPISILON = 0.000001
        endglobals

        function GetAnglesZXY takes Vector tangent, Vector normal, Vector binormal returns Vector
            local real sqrt = SquareRoot( tangent.x * tangent.x + tangent.y * tangent.y )
            local real x = Atan2( tangent.z * -1, sqrt )
            local real y = 0
            local real z = 0
            if sqrt < EPSILON then
                if tangent.z > 0 then
                    set z = Atan2( -1 * binormal.y, normal.y   )
                else
                    set z = Atan2(      binormal.y, normal.y   )
                endif
            else
                set y = Atan2(      tangent.x,  tangent.y  )
                set z = Atan2( -1 * normal.z,   binormal.z ) + bj_PI / 2
            endif
            return Vector.Create( x, y, z )
        endfunction

        function GetCameraFromTNB takes Vector tangent, Vector normal, Vector binormal returns Vector
            local Vector result = GetAnglesZXY( tangent, normal, binormal )
            set result.x =   0 - bj_RADTODEG * result.x //Angle of Attack
            set result.y =  90 - bj_RADTODEG * result.y //Rotation
            set result.z = 360 - bj_RADTODEG * result.z //Roll
            return result
        endfunction



        struct Matrix
        // m00 m01 m02
        // m10 m11 m12
        // m20 m21 m22
            real m00
            real m01
            real m02
            real m10
            real m11
            real m12
            real m20
            real m21
            real m22

            //RzRxRy
            method GetRotationsYXZ takes nothing returns Vector
                local Vector v = Vector.create()
                if this.m21 < 1 - EPSILON then
                    if this.m21 > EPSILON - 1 then
                        //set v.x = Asin( this.m21 )
                        set v.x = Atan2( this.m21, SquareRoot( this.m20 * this.m20 + this.m22 * this.m22 ) )
                        set v.y = Atan2( -1 * this.m20, this.m22 )
                        set v.z = Atan2( -1 * this.m01, this.m11 )
                    else
                        debug call BJDebugMsg( "-Pole (YXZ)" )
                        set v.x = bj_PI / -2
                        set v.y = 0
                        set v.z = -1 * Atan2( this.m02, this.m00 )
                    endif
                else
                        debug call BJDebugMsg( "+Pole (YXZ)" )
                        set v.x = bj_PI / 2
                        set v.y = 0
                        set v.z = Atan2( this.m02, this.m00 )
                endif
                return v
            endmethod

            //RyRxRz
            static method GetMatrixZXY takes real Rx, real Ry, real Rz returns thistype
                local thistype m = thistype.create()
                local real cx = Cos( Rx )
                local real cy = Cos( Ry )
                local real cz = Cos( Rz )
                local real sx = Sin( Rx )
                local real sy = Sin( Ry )
                local real sz = Sin( Rz )

                set m.m00 = cy * cz + sx * sy * sz
                set m.m01 = sx * sy * cz - cy * sz
                set m.m02 = cx * sy
                set m.m10 = cx * sz
                set m.m11 = cx * cz
                set m.m12 = -1 * sx
                set m.m20 = sx * cy * sz - sy * cz
                set m.m21 = sx * cy * cz + sy * sz
                set m.m22 = cx * cy
                return m
            endmethod
        endstruct

        struct Effect
            Vector position

            Vector forward
            Vector up
            Vector side

            method UpdateEffect takes nothing returns nothing
                local Vector cam = GetCameraFromTNB( this.forward, this.up, this.side ).Scale( bj_DEGTORAD )
                local Matrix m = Matrix.GetMatrixZXY( cam.x * -1, cam.y, cam.z )
                call Vector.destroy( cam )

              //local Matrix m = Matrix.GetMatrixFromTNB( this.forward, this.up, this.side ) - see next post

                set cam = m.GetRotationsYXZ()
                call Matrix.destroy( m )
                call BlzSetSpecialEffectOrientation( this.e, cam.z, cam.x, cam.y ) //roll, pitch, yaw
                call Vector.destroy( cam )

                call BlzSetSpecialEffectPosition( this.e, this.pos.x, this.pos.y, this.pos.z )
            endmethod
        endstruct
     
    Last edited: Aug 20, 2018
  3. AGD

    AGD

    Joined:
    Mar 29, 2016
    Messages:
    400
    Resources:
    13
    Spells:
    7
    Tutorials:
    1
    JASS:
    5
    Resources:
    13
    Maybe I'll try to work out the yaw and the pitch tomorrow.

    Btw, I tested your demo map and I noticed that the rotation about the z-axis (roll) doesn't behave as intended. The flying sheep does not always face the center while it is at the upper semicircle of the orbit. The problem is caused by the fact that
    getAngle()
    only returns angle < PI radians. You need to add a little tweak when dy < 0.00, i.e., when angle should be > PI rads.
    Code (vJASS):

        set v_plane.x = 1
        set v_plane.y = 0
        set v_plane.z = 0

        if dy < 0.00 then
            set roll = 2.00*bj_PI - vector.getAngle(v, v_plane)
        else
            set roll = vector.getAngle(v, v_plane)
        endif
     
     
  4. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,236
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I had similar attempt before. z-axis rotation I already had working, but the problem is I get it working only on a plane, like for example only xy-plane. Always when I mix-in other axis rotations, I get wrong behaviour. (so posted formulas above currently don't necessarily make sense)
     
  5. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    681
    Resources:
    3
    Maps:
    3
    Resources:
    3
    I have worked with them when they were released. I haven't completed or touched that library since then so it's not perfect and might not even work.

    Code (vJASS):

        // movement is a Vector 3D
        // new is the target position (Vector 3D)
        // fx.position is the fx position (Vector 3D)
        set movement =  new - fx.position
        call fx.setOrientation(movement.angleX,movement.angleY,movement.angleZ)
     
        // those are the 'angle' method operators from the Vector 3D struct
        method operator angleZ takes nothing returns real
            return Atan2(this.y,this.x)
        endmethod
           
        method operator angleY takes nothing returns real
            local real ix = Math.abs(this.x)
            local real iy = Math.abs(this.y)
            local real px = (1-(iy/(ix+iy)))
            if not (this.x == 0) then
                return -Atan(this.z/this.x)*px
            else
                return 0.
            endif
        endmethod
           
        method operator angleX takes nothing returns real
            local real ix = Math.abs(this.x)
            local real iy = Math.abs(this.y)
            local real py = (1-(ix/(ix+iy)))
             
            if not (this.y == 0) then
                return Atan(this.z/this.y)*py
            else
                return 0.
            endif
        endmethod
     
     
  6. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,236
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    @Drake53 , thank you. I'm already getting correct vector through the rotation matrix. The yaw pitch roll was the thing. What is the vector exactly meaning you are creating?

    @Wareditor , it is working, thanks much! I made only a little change in x-, y- axis if something is negative but it seems good. [need to test]

    I'll make some more tests and then just post the orbit movement system tomorrow, if all works good.

    Thanks to everyone.
     
    Last edited: Aug 19, 2018
  7. Drake53

    Drake53

    Joined:
    Jan 1, 2018
    Messages:
    208
    Resources:
    0
    Resources:
    0
    @IcemanBo , the camera vector doesn't really have a meaning, it just combines the three rotations, roll, pitch, and yaw (in that order).

    In case anyone needs it, I also have some additional code to create the input vectors in case you use a roll value as well:

    Code (vJASS):
        struct Vector
            real x
            real y
            real z

            static method Normal takes real pitch, real yaw, real roll returns Vector //rotation order = Rz-Rx-Ry
                local Vector v = Vector.create()
                set v.x = Sin( pitch ) * Sin( yaw ) * Cos( roll ) -                Cos( yaw ) * Sin( roll )
                set v.y =                Sin( yaw ) * Sin( roll ) + Sin( pitch ) * Cos( yaw ) * Cos( roll )
                set v.z = Cos( pitch )              * Cos( roll )
                return v
            endmethod
            static method NormalTan takes Vector tangent, real roll returns Vector
                local real pitch = Atan2( tangent.z * -1, SquareRoot( tangent.x * tangent.x + tangent.y * tangent.y ) )
                local real yaw   = Atan2( tangent.x, tangent.y )
                return Normal( pitch, yaw, roll )
            endmethod

            static method Difference takes Vector a, Vector b returns Vector
                local Vector v = Vector.create()
                set v.x = b.x - a.x
                set v.y = b.y - a.y
                set v.z = b.z - a.z
                return v
            endmethod

            static method Cross takes Vector a, Vector b returns Vector
                local Vector v = Vector.create()
                set v.x = a.y * b.z - a.z * b.y
                set v.y = a.z * b.x - a.x * b.z
                set v.z = a.x * b.y - a.y * b.x
                return v
            endmethod
        endstruct

        //Roll in radians
        function SetEffectFacingXYZWithRoll takes effect e, real x_target, real y_target, real z_target, real roll returns nothing
            local real x_effect = BlzGetLocalSpecialEffectX(e)
            local real y_effect = BlzGetLocalSpecialEffectY(e)
            local real z_effect = BlzGetLocalSpecialEffectZ(e)

            local Vector origin = Vector.Create( x_effect, y_effect, z_effect )
            local Vector target = Vector.Create( x_target, y_target, z_target )

            local Vector tangent  = Vector.Difference( origin, target  ).Normalize() //Forward vector
            local Vector normal   = Vector.NormalTan(  tangent, roll   ).Normalize() //Up vector
            local Vector binormal = Vector.Cross(      tangent, normal ).Normalize() //Side vector

            //call UpdateEffect( e, tangent, normal, binormal ) - see code in previous post
        endfunction



    Edit: Did some more testing, and figured out how to create the rotation matrix directly from the TNB vectors, which is a lot faster:

    Code (vJASS):
        struct Matrix
            real m00
            real m01
            real m02
            real m10
            real m11
            real m12
            real m20
            real m21
            real m22

            static method GetMatrixFromTNB takes Vector tangent, Vector normal, Vector binormal returns thistype
                local thistype m = thistype.create()
                set m.m00 = -1 * binormal.y
                set m.m01 =        normal.y
                set m.m02 =       tangent.y
                set m.m10 = -1 * binormal.z
                set m.m11 =        normal.z
                set m.m12 =       tangent.z
                set m.m20 = -1 * binormal.x
                set m.m21 =        normal.x
                set m.m22 =       tangent.x
                return m
            endmethod
        endstruct

        struct Effect
            effect e
            Vector forward
            Vector up
            Vector side

            method UpdateEffect takes nothing returns nothing
                local Matrix m = Matrix.GetMatrixFromTNB( this.forward, this.up, this.side )
                local Vector cam = m.GetRotationsYXZ()
                call Matrix.destroy( m )
                call BlzSetSpecialEffectOrientation( this.e, cam.z, cam.x, cam.y ) //roll, pitch, yaw
                call Vector.destroy( cam )
            endmethod
        endstruct
     
    Last edited: Aug 20, 2018