Forged Alliance Forever Forged Alliance Forever Forums 2016-12-04T20:19:54+02:00 /feed.php?f=40&t=13598 2016-12-04T20:19:54+02:00 2016-12-04T20:19:54+02:00 /viewtopic.php?t=13598&p=139993#p139993 <![CDATA[Re: Bone angles etc]]> Sorted it out, here's the code for anyone looking at creating complicated motions:
Code:
    HingeState = State{
        Main = function(self)
            WaitSeconds(2)
            #unpacking of the unit, you can ignore this, not even sure if its necessary tbh
           
            #Set up joints 1 and 2
            self.J1 = CreateRotator(self, 'joint1', 'x')
            #the two bones ill be manipulating later, see picture above
            self.J2 = CreateRotator(self, 'joint2', 'x')
            self.Trash:Add(self.J1)
            #these things that are just required for whatever reason?
            self.Trash:Add(self.J2)

            local rotateold = {}
            #I don't want to have the hinge constantly trying to move, so I create this variable to check against

            while not self:IsDead() do
            #the following gets the details on the pitch of the weapon, and if it has changed

                WaitSeconds(0.1)
                #this needs to exist and have a value that isn't 0. Changing this requires changing the starred line below

                local tune = {}
                tune.heading, tune.pitch = self:GetWeaponManipulatorByLabel('MainGun'):GetHeadingPitch()
                #This returns values in radians. Yeah. radians. What the hell. Took a while to figure that out.

                local rotate = {}
                rotate = MATH_IRound((180/3.14159)*tune.pitch) #Converting to degrees and rounding for nice numbers
                #Most of the supcom bones seem to twitch subtly, so without rounding rotate almost always changes

                if rotateold ~= rotate then #if the weapon pitch hasn't changed over the last 0.1 seconds, nothing happens

                    #Translate differences in rotate
                   
                    local R2 = {} #I used blender, and iterated through a few angles of the pitch bone to establish joint angles
                    local R3 = {} #Then I used excel to derive a polynomial. It was a 3rd order, but the first term was a tiny thing

                    local R5 = {}
                    local R6 = {}

                    R2 = (-0.0165*(rotate*rotate)) #Terms 2 and 3 from the joint1's poly
                    R3 = (1.1357*(rotate))

                    R5 = (0.0295*(rotate*rotate)) #Terms 2 and 3 from joint2's poly
                    R6 = (-1.9041*(rotate))
                    #Those paying attention may notice I dropped my C term; turns out I corrected for it with my model by
                    #accident. This is not something anyone will need to worry about, It was my own sloppiness that created its
                    #need, and the same sloppiness that accidentally fixed it.

                    rotate1 = MATH_IRound(R2+R3) #cleanliness
                    rotate2 = MATH_IRound(R5+R6)

                    self.J1:SetGoal(-rotate1):SetSpeed(50)
                    *GetHeadingPitch() produces radians, yet this takes degrees. But motion is reversed. What. The. Hell.
                    self.J2:SetGoal(-rotate2):SetSpeed(50)
                    #*******************Tune these speeds with the wait time to make a smooth motion
                end
                rotateold = rotate #set the new rotate value. This might be able to go in the if loop above, dunno.
            end
        end
    },


I annotated it heavily to help explain some of the weirdness. Major pain, but now that I've figured this general procedure out, future unit animations could be far more pleasing!

I also have a hunch that instead of using "while not self:IsDead() do" I could use something in the spirit of "if target exists then". Something I'll keep an eye out for in any case.

Statistics: Posted by Dudekahedron — 04 Dec 2016, 20:19


]]>
2016-12-04T00:24:13+02:00 2016-12-04T00:24:13+02:00 /viewtopic.php?t=13598&p=139945#p139945 <![CDATA[Re: Bone angles etc]]>
Code:
    HingeState = State{
        Main = function(self)
            WaitSeconds(2) #unpacking of the unit, you can ignore this
            self.J1 = CreateRotator(self, 'joint1', 'x') #the two bones ill be manipulating later
            self.J2 = CreateRotator(self, 'joint2', 'x')
            self.Trash:Add(self.J1) #these things that are just required for whatever reason?
            self.Trash:Add(self.J2)
            local rotateold = {}

            while not self:IsDead() do

                WaitSeconds(0.1)
                #Set up joints 1 and 2

                #Get angle position
                local angle = {}
                angle.x, angle.y, angle.z = self:GetBoneDirection('pitch') #Im hoping this is a local x angle, and not a global one

                local blah = {}               
                blah.x, blah.y, blah.z = self:GetBoneDirection('DAB201')

                local rotate = {}
                rotate = MATH_IRound(Util.GetAngleInBetween(angle, blah))
                LOG('Difference is')
                LOG(rotate)

                if rotateold ~= rotate then

                    #Translate differences in angle
                    local R1 = {}
                    local R2 = {}
                    local R3 = {}
                    local R4 = {}

                    R1 = MATH_IRound(0.0064*rotate^2)  #R1 to R4 come from the approximated hinge behavior
                    R2 = MATH_IRound(-0.9653*rotate)
                    R3 = MATH_IRound(-0.0089*rotate^2)
                    R4 = MATH_IRound(1.5412*rotate)
               
                    LOG('J1 rotating by')
                    LOG(R1+R2)

                    LOG('J2 rotating by')
                    LOG(R4+R3)

                    self.J1:SetCurrentAngle(R1+R2)
                    self.J2:SetCurrentAngle(R3+R4)
                end
                rotateold = rotate
            end
        end
    },


Now joint1 and joint2 'blink' between correct locations, not ideal, but improving.
Another new issue; GetAngleBetweenBones() always produces a positive angle, so joint1 and joint2 will bend as if the gun is pointing upwards regardless of direction it actually points.

EDIT: I can solve the new issue by adding a bone that rotates with the entire turret that is perpendicular and points forward as opposed to up. Then I just measure the angle between the pitch bone and this new bone, then change the sign of the rotate variable appropriately. Testing this later.

Statistics: Posted by Dudekahedron — 04 Dec 2016, 00:24


]]>
2016-12-03T23:42:48+02:00 2016-12-03T23:42:48+02:00 /viewtopic.php?t=13598&p=139943#p139943 <![CDATA[Bone angles etc]]> I've been trying to figure out how to measure angles, specifically changes in angles, of bones. What I'd like to do is then set the angle of other bones to a manipulation of that value. The goal is to simulate a sort of double-hinged joint like the bones in a forearm.

What I came up with:
(State is initiated after its done being built)
Code:
    HingeState = State{
        Main = function(self)
            WaitSeconds(2) #unpacking of the unit, you can ignore this

            while not self:IsDead() do
                WaitSeconds(0.5)     #necessary to stop endless update and game crash
                #Set up joints 1 and 2
                self.J1 = CreateRotator(self, 'joint1', 'x') #the two bones ill be manipulating later
                self.J2 = CreateRotator(self, 'joint2', 'x')

                self.Trash:Add(self.J1) #these things that are just required for whatever reason?
                self.Trash:Add(self.J2)

                #Get angle position
                local angle = {}
                angle.x, angle.y, angle.z = self:GetBoneDirection('pitch')
                #Im hoping this is a local x angle measured from starting orientation

                LOG('pitch angle is') #so i know what is happening
                LOG(angle.x)

                #Translate differences in angle
                #local R1 = {}
                local R2 = {}
                local R3 = {}
                local R4 = {}
                R1 = -0.0064*angle.x^2  #R1 to R4 come from the approximated hinge behavior for my specific set of bones
                R2 = 0.9653*angle.x
                R3 = 0.0089*angle.x^2
                R4 = -1.5412*angle.x
               
                LOG('J1 rotating by')
                LOG(R1+R2)

                LOG('J2 rotating by')
                LOG(R4+R3)

                self.J1:SetCurrentAngle(R1+R2) #moves joint1 and joint2 bones to their new positions
                self.J2:SetCurrentAngle(R3+R4)
            end
        end
    },

So that's what I have, but what ends up happening is J1 and J2 don't stop moving, they just keep bouncing to a new position.
Picture of set up for visualizing:
Image
Basically the code should rotate joint1 and joint2 as to keep the model representation "attached" to the small green cylinder at the top and the sphere at the bottom.
Any ideas?
Thanks

Statistics: Posted by Dudekahedron — 03 Dec 2016, 23:42


]]>