[lua] Ported addition of uniform/compressed IK and rotation fix.

This commit is contained in:
badlogic 2018-08-23 15:47:50 +02:00
parent d079555f84
commit 3e8cb852bb
6 changed files with 48 additions and 19 deletions

View File

@ -1169,19 +1169,21 @@ function Animation.DrawOrderTimeline.new (frameCount)
end end
Animation.IkConstraintTimeline = {} Animation.IkConstraintTimeline = {}
Animation.IkConstraintTimeline.ENTRIES = 4 Animation.IkConstraintTimeline.ENTRIES = 5
function Animation.IkConstraintTimeline.new (frameCount) function Animation.IkConstraintTimeline.new (frameCount)
local ENTRIES = Animation.IkConstraintTimeline.ENTRIES local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
local PREV_TIME = -4 local PREV_TIME = -5
local PREV_MIX = -3 local PREV_MIX = -4
local PREV_BEND_DIRECTION = -2 local PREV_BEND_DIRECTION = -3
local PREV_COMPRESS = -2
local PREV_STRETCH = -1 local PREV_STRETCH = -1
local MIX = 1 local MIX = 1
local BEND_DIRECTION = 2 local BEND_DIRECTION = 2
local COMPRESS = 3
local STRETCH = 1 local STRETCH = 1
local self = Animation.CurveTimeline.new(frameCount) local self = Animation.CurveTimeline.new(frameCount)
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ... self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, compress, stretch, ...
self.ikConstraintIndex = -1 self.ikConstraintIndex = -1
self.type = TimelineType.ikConstraint self.type = TimelineType.ikConstraint
@ -1189,11 +1191,16 @@ function Animation.IkConstraintTimeline.new (frameCount)
return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
end end
function self:setFrame (frameIndex, time, mix, bendDirection, stretch) function self:setFrame (frameIndex, time, mix, bendDirection, compress, stretch)
frameIndex = frameIndex * ENTRIES frameIndex = frameIndex * ENTRIES
self.frames[frameIndex] = time self.frames[frameIndex] = time
self.frames[frameIndex + MIX] = mix self.frames[frameIndex + MIX] = mix
self.frames[frameIndex + BEND_DIRECTION] = bendDirection self.frames[frameIndex + BEND_DIRECTION] = bendDirection
if (compress) then
self.frames[frameIndex + COMPRESS] = 1
else
self.frames[frameIndex + COMPRESS] = 0
end
if (stretch) then if (stretch) then
self.frames[frameIndex + STRETCH] = 1 self.frames[frameIndex + STRETCH] = 1
else else
@ -1209,10 +1216,12 @@ function Animation.IkConstraintTimeline.new (frameCount)
if blend == MixBlend.setup then if blend == MixBlend.setup then
constraint.mix = constraint.data.mix constraint.mix = constraint.data.mix
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch constraint.stretch = constraint.data.stretch
elseif blend == MixBlend.first then elseif blend == MixBlend.first then
constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch constraint.stretch = constraint.data.stretch
end end
return return
@ -1223,15 +1232,18 @@ function Animation.IkConstraintTimeline.new (frameCount)
constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
if direction == MixDirection.out then if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch constraint.stretch = constraint.data.stretch
else else
constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]); constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]);
if (math_floor(frames[zlen(frames) + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end end
else else
constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
if direction == MixDirection._in then if direction == MixDirection._in then
constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]) constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION])
if (math_floor(frames[zlen(frames) + PREV_COMPRES]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end end
end end
@ -1249,15 +1261,18 @@ function Animation.IkConstraintTimeline.new (frameCount)
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
if direction == MixDirection.out then if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch constraint.stretch = constraint.data.stretch
else else
constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end end
else else
constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
if direction == MixDirection._in then if direction == MixDirection._in then
constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION]) constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end end
end end

View File

@ -543,10 +543,10 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, bl
if blend == MixBlend.setup then r1 = bone.data.rotation end if blend == MixBlend.setup then r1 = bone.data.rotation end
local total = 0 local total = 0
local diff = r2 - r1 local diff = r2 - r1
diff = diff - (16384 - math_floor(16384.499999999996 - diff / 360)) * 360
if diff == 0 then if diff == 0 then
total = timelinesRotation[i] total = timelinesRotation[i]
else else
diff = diff - (16384 - math_floor(16384.499999999996 - diff / 360)) * 360
local lastTotal = 0 local lastTotal = 0
local lastDiff = 0 local lastDiff = 0
if firstFrame then if firstFrame then

View File

@ -52,6 +52,7 @@ function IkConstraint.new (data, skeleton)
bones = {}, bones = {},
target = nil, target = nil,
mix = data.mix, mix = data.mix,
compress = data.compress,
stretch = data.stretch, stretch = data.stretch,
bendDirection = data.bendDirection, bendDirection = data.bendDirection,
} }
@ -75,13 +76,13 @@ function IkConstraint:update ()
local bones = self.bones local bones = self.bones
local boneCount = #bones local boneCount = #bones
if boneCount == 1 then if boneCount == 1 then
self:apply1(bones[1], target.worldX, target.worldY, self.stretch, self.mix) self:apply1(bones[1], target.worldX, target.worldY, self.compress, self.stretch, self.data.uniform, self.mix)
elseif boneCount == 2 then elseif boneCount == 2 then
self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.stretch, self.mix) self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.stretch, self.mix)
end end
end end
function IkConstraint:apply1 (bone, targetX, targetY, stretch, alpha) function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform, alpha)
if not bone.appliedValid then bone:updateAppliedTransform() end if not bone.appliedValid then bone:updateAppliedTransform() end
local p = bone.parent local p = bone.parent
local id = 1 / (p.a * p.d - p.b * p.c) local id = 1 / (p.a * p.d - p.b * p.c)
@ -97,11 +98,17 @@ function IkConstraint:apply1 (bone, targetX, targetY, stretch, alpha)
rotationIK = rotationIK + 360 rotationIK = rotationIK + 360
end end
local sx = bone.ascaleX local sx = bone.ascaleX
if stretch then local sy = bone.ascaleY
if compress or stretch then
local b = bone.data.length * sx
local dd = math_sqrt(tx * tx + ty * ty) local dd = math_sqrt(tx * tx + ty * ty)
if dd > bone.data.length * sx then sx = sx * ((dd / (bone.data.length * sx) - 1) * alpha + 1) end if (compress and dd < b) or (stretch and dd > b) and b > 0.0001 then
local s = (dd / b - 1) * alpha + 1
sx = sx * s
if uniform then sy = sy * s end
end
end end
bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY) bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY)
end end
function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, alpha) function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, alpha)

View File

@ -38,7 +38,9 @@ function IkConstraintData.new (name)
bones = {}, bones = {},
target = nil, target = nil,
bendDirection = 1, bendDirection = 1,
compress = false,
stretch = false, stretch = false,
uniform = false,
mix = 1 mix = 1
} }

View File

@ -338,9 +338,10 @@ function Skeleton:setBonesToSetupPose ()
end end
for _,ikConstraint in ipairs(self.ikConstraints) do for _,ikConstraint in ipairs(self.ikConstraints) do
ikConstraint.bendDirection = ikConstraint.data.bendDirection
ikConstraint.stretch = ikConstraint.data.stretch
ikConstraint.mix = ikConstraint.data.mix ikConstraint.mix = ikConstraint.data.mix
ikConstraint.bendDirection = ikConstraint.data.bendDirection
ikConstraint.compress = ikConstraint.data.compress
ikConstraint.stretch = ikConstraint.data.stretch
end end
local transformConstraints = self.transformConstraints local transformConstraints = self.transformConstraints

View File

@ -164,9 +164,11 @@ function SkeletonJson.new (attachmentLoader)
data.target = skeletonData:findBone(targetName) data.target = skeletonData:findBone(targetName)
if not data.target then error("Target bone not found: " .. targetName) end if not data.target then error("Target bone not found: " .. targetName) end
if constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
if constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
data.mix = getValue(constraintMap, "mix", 1) data.mix = getValue(constraintMap, "mix", 1)
if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
if constraintMap["compress"] == nil or constraintMap["compress"] == false then data.compress = false else data.compress = true end
if constraintMap["stretch"] == nil or constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
if constraintMap["uniform"] == nil or constraintMap["uniform"] == false then data.uniform = false else data.uniform = true end
table_insert(skeletonData.ikConstraints, data) table_insert(skeletonData.ikConstraints, data)
end end
@ -613,9 +615,11 @@ function SkeletonJson.new (attachmentLoader)
if valueMap["mix"] ~= nil then mix = valueMap["mix"] end if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
local bendPositive = 1 local bendPositive = 1
if valueMap["bendPositive"] == false then bendPositive = -1 end if valueMap["bendPositive"] == false then bendPositive = -1 end
local stretch = true local stretch = false
if valueMap["stretch"] == false then stretch = false end if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, stretch) local compress = false
if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, compress, stretch)
readCurve(valueMap, timeline, frameIndex) readCurve(valueMap, timeline, frameIndex)
frameIndex = frameIndex + 1 frameIndex = frameIndex + 1
end end