Hello everyone, i send you now what noche gave me.
He had binded the code to Ogre with Lua but you should get the idea of what happens:
To create a procedural track you have to create first a ProceduralTrackController, the method virtual void getInterpolatedKeyFrame( ) will be called when the animation will need to be rendered. You need to fill the value of the keyframe when this is called.
Then you can create an animation Track with ProceduralAnimationTrack.
Important thing: You must create the controllers in the orders of the Parents to childs. Spine -> Arm -> lower hand -> hand because they will be called in the order they are created.
Those are a resume of the notes i took when he explained to me. I will now try this out and add more details.
Code: Select all
-------------------------------------------------------------------------------
Class "BipedController"
BipedController.XyzToYzxRotation = Quaternion.FromAngleAxis(HalfPi, Vector3(0, 0, 1)) * Quaternion.FromAngleAxis(Pi, Vector3(1, 0, 0))
-------------------------------------------------------------------------------
function BipedController:Construct(sceneManager, entity)
self.entity = entity
self.node = entity:GetParentNode()
self.skeleton = entity:GetSkeleton()
self.skeleton:SetBlendMode("AnimblendCumulative")
self.bones =
{
LeftUpperarm = self.skeleton:GetBone("BipedLeftUpperarm"),
LeftForearm = self.skeleton:GetBone("BipedLeftForearm"),
LeftHand = self.skeleton:GetBone("BipedLeftHand"),
RightUpperarm = self.skeleton:GetBone("BipedRightUpperarm"),
RightForearm = self.skeleton:GetBone("BipedRightForearm"),
RightHand = self.skeleton:GetBone("BipedRightHand"),
LeftThigh = self.skeleton:GetBone("BipedLeftThigh"),
LeftCalf = self.skeleton:GetBone("BipedLeftCalf"),
LeftFoot = self.skeleton:GetBone("BipedLeftFoot"),
RightThigh = self.skeleton:GetBone("BipedRightThigh"),
RightCalf = self.skeleton:GetBone("BipedRightCalf"),
RightFoot = self.skeleton:GetBone("BipedRightFoot"),
head = self.skeleton:GetBone("BipedHead"),
pelvis = self.skeleton:GetBone("BipedPelvis"),
spine1 = self.skeleton:GetBone("BipedSpine1"),
spine2 = self.skeleton:GetBone("BipedSpine2"),
spine3 = self.skeleton:GetBone("BipedSpine3"),
}
-- self.bones =
-- {
-- LeftUpperarm = self.skeleton:GetBone("R65_BA_L_UpperArm"),
-- LeftForearm = self.skeleton:GetBone("R65_BA_L_Forearm"),
-- LeftHand = self.skeleton:GetBone("R65_BA_L_Hand"),
-- RightUpperarm = self.skeleton:GetBone("R65_BA_R_UpperArm"),
-- RightForearm = self.skeleton:GetBone("R65_BA_R_Forearm"),
-- RightHand = self.skeleton:GetBone("R65_BA_R_Hand"),
-- LeftThigh = self.skeleton:GetBone("R65_BA_L_Thigh"),
-- LeftCalf = self.skeleton:GetBone("R65_BA_L_Calf"),
-- LeftFoot = self.skeleton:GetBone("R65_BA_L_Foot"),
-- RightThigh = self.skeleton:GetBone("R65_BA_R_Thigh"),
-- RightCalf = self.skeleton:GetBone("R65_BA_R_Calf"),
-- RightFoot = self.skeleton:GetBone("R65_BA_R_Foot"),
-- head = self.skeleton:GetBone("R65_BA_Head"),
-- pelvis = self.skeleton:GetBone("R65_BA_Pelvis"),
-- spine1 = self.skeleton:GetBone("R65_BA_Spine"),
-- spine2 = self.skeleton:GetBone("R65_BA_Spine1"),
-- spine3 = self.skeleton:GetBone("R65_BA_Spine2"),
-- }
self.manipulators = {}
self.manipulators.leftLegTarget = sceneManager:CreateSceneNode()
self.manipulators.rightLegTarget = sceneManager:CreateSceneNode()
self.manipulators.leftLegSwivel = sceneManager:CreateSceneNode()
self.manipulators.rightLegSwivel = sceneManager:CreateSceneNode()
self.manipulators.spineTarget = sceneManager:CreateSceneNode()
self.manipulators.headTarget = sceneManager:CreateSceneNode()
self.manipulators.leftArmTarget = sceneManager:CreateSceneNode()
self.manipulators.rightArmTarget = sceneManager:CreateSceneNode()
self.manipulators.leftArmSwivel = sceneManager:CreateSceneNode()
self.manipulators.rightArmSwivel = sceneManager:CreateSceneNode()
self.manipulators.leftFootTarget = sceneManager:CreateSceneNode()
self.manipulators.rightFootTarget = sceneManager:CreateSceneNode()
self.manipulators.leftHandTarget = sceneManager:CreateSceneNode()
self.manipulators.rightHandTarget = sceneManager:CreateSceneNode()
self.leftArmController = LimbController:New(self.node,
self.bones.LeftUpperarm,
self.bones.LeftForearm,
self.bones.LeftHand,
Vector3.UnitY,
self.manipulators.leftArmTarget,
self.manipulators.leftArmSwivel,
Quaternion.Identity,
Vector3(1, 0, 0))
self.rightArmController = LimbController:New(self.node,
self.bones.RightUpperarm,
self.bones.RightForearm,
self.bones.RightHand,
Vector3.UnitY,
self.manipulators.rightArmTarget,
self.manipulators.rightArmSwivel,
Quaternion.FromAngleAxis(Pi, Vector3(0, 0, 1)),
Vector3(-1, 0, 0))
self.leftLegController = LimbController:New(self.node,
self.bones.LeftThigh,
self.bones.LeftCalf,
self.bones.LeftFoot,
Vector3.UnitY,
self.manipulators.leftLegTarget,
self.manipulators.leftLegSwivel,
Quaternion.FromAngleAxis(Pi, Vector3(0, 1, 0)) * Quaternion.FromAngleAxis(-Pi / 2, Vector3(0, 0, 1)),
Vector3(0, -1, 0))
self.rightLegController = LimbController:New(self.node,
self.bones.RightThigh,
self.bones.RightCalf,
self.bones.RightFoot,
Vector3.UnitY,
self.manipulators.rightLegTarget,
self.manipulators.rightLegSwivel,
Quaternion.FromAngleAxis(Pi, Vector3(0, 1, 0)) * Quaternion.FromAngleAxis(-Pi / 2, Vector3(0, 0, 1)),
Vector3(0, -1, 0))
self.headController = LookAtController:New(self.node,
self.bones.head,
self.manipulators.headTarget,
0,
true,
"yxz")
self.spineController = SpineController:New(self.node,
self.bones.pelvis,
self.bones.spine1,
self.bones.spine2,
self.bones.spine3,
self.manipulators.spineTarget,
0,
false,
"zxy")
self.leftFootController = OrientationController:New(self.node,
self.bones.LeftFoot,
self.manipulators.leftFootTarget,
false,
"xyz")
self.rightFootController = OrientationController:New(self.node,
self.bones.RightFoot,
self.manipulators.rightFootTarget,
false,
"xyz")
self.leftHandController = OrientationController:New(self.node,
self.bones.LeftHand,
self.manipulators.leftHandTarget,
false,
"xyz")
self.rightHandController = OrientationController:New(self.node,
self.bones.RightHand,
self.manipulators.rightHandTarget,
false,
"xyz")
self.leftFootAnimation = self.skeleton:CreateAnimation("BipedControllerLeftFoot", 1)
self.rightFootAnimation = self.skeleton:CreateAnimation("BipedControllerRightFoot", 1)
self.leftHandAnimation = self.skeleton:CreateAnimation("BipedControllerLeftHand", 1)
self.rightHandAnimation = self.skeleton:CreateAnimation("BipedControllerRightHand", 1)
self.BRAND NAME = self.skeleton:CreateAnimation("BipedControllerLeftArm", 1)
self.BRAND NAME = self.skeleton:CreateAnimation("BipedControllerRightArm", 1)
self.leftLegAnimation = self.skeleton:CreateAnimation("BipedControllerLeftLeg", 1)
self.rightLegAnimation = self.skeleton:CreateAnimation("BipedControllerRightLeg", 1)
self.headAnimation = self.skeleton:CreateAnimation("BipedControllerHead", 1)
self.spineAnimation = self.skeleton:CreateAnimation("BipedControllerSpine", 1)
self.entity:RefreshAvailableAnimationState()
self.leftFootAnimationState = self.entity:GetAnimationState("BipedControllerLeftFoot")
self.rightFootAnimationState = self.entity:GetAnimationState("BipedControllerRightFoot")
self.leftHandAnimationState = self.entity:GetAnimationState("BipedControllerLeftHand")
self.rightHandAnimationState = self.entity:GetAnimationState("BipedControllerRightHand")
self.BRAND NAME = self.entity:GetAnimationState("BipedControllerLeftArm")
self.BRAND NAME = self.entity:GetAnimationState("BipedControllerRightArm")
self.leftLegAnimationState = self.entity:GetAnimationState("BipedControllerLeftLeg")
self.rightLegAnimationState = self.entity:GetAnimationState("BipedControllerRightLeg")
self.headAnimationState = self.entity:GetAnimationState("BipedControllerHead")
self.spineAnimationState = self.entity:GetAnimationState("BipedControllerSpine")
self.spineAnimationState:SetEnabled(true)
self.BRAND NAME:SetEnabled(true)
self.BRAND NAME:SetEnabled(true)
self.leftLegAnimationState:SetEnabled(true)
self.rightLegAnimationState:SetEnabled(true)
self.headAnimationState:SetEnabled(true)
self.leftFootAnimationState:SetEnabled(true)
self.rightFootAnimationState:SetEnabled(true)
self.leftHandAnimationState:SetEnabled(true)
self.rightHandAnimationState:SetEnabled(true)
self.spineAnimationState:SetWeight(1.0)
self.leftFootAnimationState:SetWeight(1.0)
self.rightFootAnimationState:SetWeight(1.0)
self.leftHandAnimationState:SetWeight(1.0)
self.rightHandAnimationState:SetWeight(1.0)
self.BRAND NAME:SetWeight(1.0)
self.BRAND NAME:SetWeight(1.0)
self.leftLegAnimationState:SetWeight(1.0)
self.rightLegAnimationState:SetWeight(1.0)
self.headAnimationState:SetWeight(1.0)
self.rightFootAnimation:CreateProceduralTrack(self.rightFootController.bone, self.rightFootController)
self.leftFootAnimation:CreateProceduralTrack(self.leftFootController.bone, self.leftFootController)
self.rightHandAnimation:CreateProceduralTrack(self.rightHandController.bone, self.rightHandController)
self.leftHandAnimation:CreateProceduralTrack(self.leftHandController.bone, self.leftHandController)
self.BRAND NAME:CreateProceduralTrack(self.leftArmController.boneStart, self.leftArmController)
self.BRAND NAME:CreateProceduralTrack(self.leftArmController.boneMid, self.leftArmController)
self.BRAND NAME:CreateProceduralTrack(self.rightArmController.boneStart, self.rightArmController)
self.BRAND NAME:CreateProceduralTrack(self.rightArmController.boneMid, self.rightArmController)
self.leftLegAnimation:CreateProceduralTrack(self.leftLegController.boneStart, self.leftLegController)
self.leftLegAnimation:CreateProceduralTrack(self.leftLegController.boneMid, self.leftLegController)
self.rightLegAnimation:CreateProceduralTrack(self.rightLegController.boneStart, self.rightLegController)
self.rightLegAnimation:CreateProceduralTrack(self.rightLegController.boneMid, self.rightLegController)
self.headAnimation:CreateProceduralTrack(self.headController.bone, self.headController)
self.spineAnimation:CreateProceduralTrack(self.spineController.bonePelvis, self.spineController)
self.spineAnimation:CreateProceduralTrack(self.spineController.boneSpine1, self.spineController)
self.spineAnimation:CreateProceduralTrack(self.spineController.boneSpine2, self.spineController)
self.spineAnimation:CreateProceduralTrack(self.spineController.boneSpine3, self.spineController)
-- manipulators for debug
self:ResetManipulators()
end
-------------------------------------------------------------------------------
function BipedController:Destroy()
self.leftFootAnimation = self.skeleton:RemoveAnimation("BipedControllerLeftFoot")
self.rightFootAnimation = self.skeleton:RemoveAnimation("BipedControllerRightFoot")
self.leftHandAnimation = self.skeleton:RemoveAnimation("BipedControllerLeftHand")
self.rightHandAnimation = self.skeleton:RemoveAnimation("BipedControllerRightHand")
self.BRAND NAME = self.skeleton:RemoveAnimation("BipedControllerLeftArm")
self.BRAND NAME = self.skeleton:RemoveAnimation("BipedControllerRightArm")
self.leftLegAnimation = self.skeleton:RemoveAnimation("BipedControllerLeftLeg")
self.rightLegAnimation = self.skeleton:RemoveAnimation("BipedControllerRightLeg")
self.headAnimation = self.skeleton:RemoveAnimation("BipedControllerHead")
self.spineAnimation = self.skeleton:RemoveAnimation("BipedControllerSpine")
self.entity:RefreshAvailableAnimationState()
self.manipulators.leftLegTarget:RemoveAndDestroy()
self.manipulators.rightLegTarget:RemoveAndDestroy()
self.manipulators.leftLegSwivel:RemoveAndDestroy()
self.manipulators.rightLegSwivel:RemoveAndDestroy()
self.manipulators.spineTarget:RemoveAndDestroy()
self.manipulators.headTarget:RemoveAndDestroy()
self.manipulators.leftArmTarget:RemoveAndDestroy()
self.manipulators.rightArmTarget:RemoveAndDestroy()
self.manipulators.leftArmSwivel:RemoveAndDestroy()
self.manipulators.rightArmSwivel:RemoveAndDestroy()
self.manipulators.leftFootTarget:RemoveAndDestroy()
self.manipulators.rightFootTarget:RemoveAndDestroy()
self.manipulators.leftHandTarget:RemoveAndDestroy()
self.manipulators.rightHandTarget:RemoveAndDestroy()
end
-------------------------------------------------------------------------------
function BipedController:Update(dt)
self.leftFootAnimationState:AddTime(dt)
self.rightFootAnimationState:AddTime(dt)
self.leftHandAnimationState:AddTime(dt)
self.rightHandAnimationState:AddTime(dt)
self.BRAND NAME:AddTime(dt)
self.BRAND NAME:AddTime(dt)
self.leftLegAnimationState:AddTime(dt)
self.rightLegAnimationState:AddTime(dt)
self.headAnimationState:AddTime(dt)
self.spineAnimationState:AddTime(dt)
self.leftFootAnimationState:SetEnabled(true)
self.rightFootAnimationState:SetEnabled(true)
self.spineAnimationState:SetEnabled(true)
self.BRAND NAME:SetEnabled(true)
self.BRAND NAME:SetEnabled(true)
self.leftHandAnimationState:SetEnabled(true)
self.rightHandAnimationState:SetEnabled(true)
self.leftLegAnimationState:SetEnabled(true)
self.rightLegAnimationState:SetEnabled(true)
self.headAnimationState:SetEnabled(true)
end
-------------------------------------------------------------------------------
function BipedController:SetWeight(weight)
-- self.leftFootAnimationState:SetWeight(weight)
-- self.rightFootAnimationState:SetWeight(weight)
self.leftHandAnimationState:SetWeight(weight)
self.rightHandAnimationState:SetWeight(weight)
self.BRAND NAME:SetWeight(weight)
self.BRAND NAME:SetWeight(weight)
self.leftLegAnimationState:SetWeight(weight)
self.rightLegAnimationState:SetWeight(weight)
self.spineAnimationState:SetWeight(weight)
self.headAnimationState:SetWeight(weight)
end
-------------------------------------------------------------------------------
function BipedController:ResetManipulators()
local offset = self.node:GetWorldPosition()
local offsetRot = self.node:GetWorldOrientation()
self.manipulators.leftFootTarget:SetWorldOrientation(Quaternion.FromAngleAxis(DegToRad(20), Vector3(0, 1, 0)) * self.bones.LeftFoot:GetWorldOrientation())
self.manipulators.rightFootTarget:SetWorldOrientation(Quaternion.FromAngleAxis(DegToRad(-20), Vector3(0, 1, 0)) * self.bones.RightFoot:GetWorldOrientation())
self.manipulators.leftHandTarget:SetWorldOrientation(Quaternion.FromAngleAxis(DegToRad(20), Vector3(0, 1, 0)) * self.bones.LeftHand:GetWorldOrientation())
self.manipulators.rightHandTarget:SetWorldOrientation(Quaternion.FromAngleAxis(DegToRad(-20), Vector3(0, 1, 0)) * self.bones.RightHand:GetWorldOrientation())
self.manipulators.leftLegTarget:SetWorldPosition(self.bones.LeftFoot:GetWorldPosition() + offset)
self.manipulators.rightLegTarget:SetWorldPosition(self.bones.RightFoot:GetWorldPosition() + offset)
self.manipulators.leftLegSwivel:SetWorldPosition(self.bones.LeftCalf:GetWorldPosition() + Vector3(1, 0, 1) + offset)
self.manipulators.rightLegSwivel:SetWorldPosition(self.bones.RightCalf:GetWorldPosition() + Vector3(-1, 0, 1) + offset)
self.manipulators.leftArmTarget:SetWorldPosition(self.bones.LeftHand:GetWorldPosition() + offset)
self.manipulators.rightArmTarget:SetWorldPosition(self.bones.RightHand:GetWorldPosition() + offset)
self.manipulators.leftArmSwivel:SetWorldPosition(self.bones.LeftForearm:GetWorldPosition() + Vector3(1, 0, -1) + offset)
self.manipulators.rightArmSwivel:SetWorldPosition(self.bones.RightForearm:GetWorldPosition() + Vector3(-1, 0, -1) + offset)
self.manipulators.spineTarget:SetWorldPosition(self.bones.head:GetWorldPosition() + offset)
self.manipulators.headTarget:SetWorldPosition(self.bones.head:GetWorldPosition() + Vector3(0, 0, 5) + offset)
end
Code: Select all
-------------------------------------------------------------------------------
Class "LimbController"
-------------------------------------------------------------------------------
function LimbController:Construct(sceneNode, boneStart, boneMid, boneEnd, axis, targetNode, swivelNode, offset, shoulderAxis)
self.sceneNode = sceneNode
self.boneStart = boneStart
self.boneMid = boneMid
self.boneEnd = boneEnd
self.axis = axis
self.targetNode = targetNode
self.swivelNode = swivelNode
self.swivelAngle = 0
self.useAngle = true
self.offset = offset
self.shoulderAxis = shoulderAxis or Vector3(0, 1, 0)
self.boneStartRotation = Quaternion.Identity
self.boneMidRotation = Quaternion.Identity
end
-------------------------------------------------------------------------------
function LimbController:OnGetInterpolatedKeyFrame(key, node)
self:CalcRotation()
if (node == self.boneStart) then
key:SetRotation(self.boneStartRotation)
elseif (node == self.boneMid) then
key:SetRotation(self.boneMidRotation)
end
end
-------------------------------------------------------------------------------
function LimbController:CalcStartRotation(origin, target, constraint)
local at = (target - origin):Normalize()
local up = (origin - constraint):CrossProduct(at):Normalize()
--local up = at:Perpendicular(Vector3.UnitX)
local right = at:CrossProduct(up):Normalize()
return Quaternion.FromAxes(at, up, right)-- * Quaternion.FromAngleAxis(0, Vector3.UnitX)
end
-------------------------------------------------------------------------------
function LimbController:CalcRotation()
local localTarget = self.targetNode:GetWorldPosition()
local localSwivel = self.swivelNode:GetWorldPosition()
-- Calc each frame the length of start and mid bones as bone may be strechable.
local startLen = self.boneMid:GetPosition():Length()
local midLen = self.boneEnd:GetPosition():Length()
-- Get the start bone current world position.
local boneStartWorldPosition = self.sceneNode:GetWorldTransforms() * self.boneStart:GetWorldPosition()
local targetDistanceToStart = localTarget:Distance(boneStartWorldPosition)
-- Calc the rotation for the mid bone
local boneMidRotationAngle = - (Pi - EuclidianAngle(targetDistanceToStart, startLen, midLen))
self.boneMidRotation = self.boneMid:GetOrientation():Inverse()
* Quaternion.FromAngleAxis(boneMidRotationAngle, self.axis)
-- Calc a first rotation for the start bone.
-- At this point the start bone lookat directly at the target, and is constraint by the swivel target
self.boneStartRotation = self:CalcStartRotation(boneStartWorldPosition, localTarget, localSwivel)
-- Calc the end bone world position after applying start and mid new rotations
local boneMidWorldPosition = boneStartWorldPosition + self.boneStartRotation * self.boneMid:GetPosition()
local boneMidWorldRotation = self.boneStartRotation * self.boneMidRotation * self.boneMid:GetOrientation()
local boneEndWorldPosition = boneMidWorldPosition + boneMidWorldRotation * self.boneEnd:GetPosition()
-- Calc the start bone rotation offset according to the end bone global position
local boneStartRotationOffset = EuclidianAngle(boneEndWorldPosition:Distance(localTarget),
boneEndWorldPosition:Distance(boneStartWorldPosition),
targetDistanceToStart)
--tracer:Axis(self.boneStart:GetWorldPosition() + self.sceneNode:GetWorldPosition(), self.boneStartRotation, 0.8)
-- Calc the final start bone rotation, by adding the offset, and by taking count of its original world orientation
self.boneStartRotation = self.boneStart:GetWorldOrientation():Inverse() * self.sceneNode:GetWorldOrientation():Inverse()
* self.boneStartRotation
* Quaternion.FromAngleAxis(boneStartRotationOffset, self.axis)
--tracer:Axis(boneMidWorldPosition, boneMidWorldOrientation, 0.1)
--tracer:Axis(boneEndWorldPosition, boneMidWorldOrientation, 0.1)
--tracer:Axis(self.boneStart:GetWorldPosition(), self.boneStart:GetWorldOrientation(), 0.5)
end
-------------------------------------------------------------------------------
function LimbController:GetInitialTargetPosition()
return self.boneEnd:GetPosition()
end