mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[lua] Fix IkConstraintTimeline.ENTRIES. See #1383.
This commit is contained in:
parent
ffd40fed68
commit
3411cfaf35
@ -1181,21 +1181,23 @@ function Animation.DrawOrderTimeline.new (frameCount)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Animation.IkConstraintTimeline = {}
|
Animation.IkConstraintTimeline = {}
|
||||||
Animation.IkConstraintTimeline.ENTRIES = 5
|
Animation.IkConstraintTimeline.ENTRIES = 6
|
||||||
function Animation.IkConstraintTimeline.new (frameCount)
|
function Animation.IkConstraintTimeline.new (frameCount)
|
||||||
local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
|
local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
|
||||||
local PREV_TIME = -5
|
local PREV_TIME = -6
|
||||||
local PREV_MIX = -4
|
local PREV_MIX = -5
|
||||||
|
local PREV_SOFTNESS = -4
|
||||||
local PREV_BEND_DIRECTION = -3
|
local PREV_BEND_DIRECTION = -3
|
||||||
local PREV_COMPRESS = -2
|
local PREV_COMPRESS = -2
|
||||||
local PREV_STRETCH = -1
|
local PREV_STRETCH = -1
|
||||||
local MIX = 1
|
local MIX = 1
|
||||||
local BEND_DIRECTION = 2
|
local SOFTNESS = 2
|
||||||
local COMPRESS = 3
|
local BEND_DIRECTION = 3
|
||||||
local STRETCH = 4
|
local COMPRESS = 4
|
||||||
|
local STRETCH = 5
|
||||||
|
|
||||||
local self = Animation.CurveTimeline.new(frameCount)
|
local self = Animation.CurveTimeline.new(frameCount)
|
||||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, compress, stretch, ...
|
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, softness, bendDirection, compress, stretch, ...
|
||||||
self.ikConstraintIndex = -1
|
self.ikConstraintIndex = -1
|
||||||
self.type = TimelineType.ikConstraint
|
self.type = TimelineType.ikConstraint
|
||||||
|
|
||||||
@ -1203,10 +1205,11 @@ 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, compress, stretch)
|
function self:setFrame (frameIndex, time, mix, softness, 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 + SOFTNESS] = softness
|
||||||
self.frames[frameIndex + BEND_DIRECTION] = bendDirection
|
self.frames[frameIndex + BEND_DIRECTION] = bendDirection
|
||||||
if (compress) then
|
if (compress) then
|
||||||
self.frames[frameIndex + COMPRESS] = 1
|
self.frames[frameIndex + COMPRESS] = 1
|
||||||
@ -1228,11 +1231,13 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
|||||||
if time < frames[0] then
|
if time < frames[0] then
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
constraint.mix = constraint.data.mix
|
constraint.mix = constraint.data.mix
|
||||||
|
constraint.softness = constraint.data.softness
|
||||||
constraint.bendDirection = constraint.data.bendDirection
|
constraint.bendDirection = constraint.data.bendDirection
|
||||||
constraint.compress = constraint.data.compress
|
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.softness = constraint.softness + (constraint.data.softness - constraint.softness) * alpha
|
||||||
constraint.bendDirection = constraint.data.bendDirection
|
constraint.bendDirection = constraint.data.bendDirection
|
||||||
constraint.compress = constraint.data.compress
|
constraint.compress = constraint.data.compress
|
||||||
constraint.stretch = constraint.data.stretch
|
constraint.stretch = constraint.data.stretch
|
||||||
@ -1243,6 +1248,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
|||||||
if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
|
if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame.
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
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
|
||||||
|
constraint.softness = constraint.data.softness
|
||||||
|
+ (frames[zlen(frames) + PREV_SOFTNESS] - constraint.data.softness) * 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.compress = constraint.data.compress
|
||||||
@ -1253,7 +1260,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
|||||||
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[zlen(frames) + PREV_MIX] - constraint.mix) * alpha;
|
constraint.mix = constraint.mix + (frames[zlen(frames) + PREV_MIX] - constraint.mix) * alpha
|
||||||
|
constraint.softness = constraint.softness + (frames[zlen(frames) + PREV_SOFTNESS] - constraint.softness) * 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_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
|
if (math_floor(frames[zlen(frames) + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
|
||||||
@ -1266,12 +1274,15 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
|||||||
-- Interpolate between the previous frame and the current frame.
|
-- Interpolate between the previous frame and the current frame.
|
||||||
local frame = binarySearch(frames, time, ENTRIES)
|
local frame = binarySearch(frames, time, ENTRIES)
|
||||||
local mix = frames[frame + PREV_MIX]
|
local mix = frames[frame + PREV_MIX]
|
||||||
|
local softness = frames[frame + PREV_SOFTNESS]
|
||||||
local frameTime = frames[frame]
|
local frameTime = frames[frame]
|
||||||
local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
|
local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1,
|
||||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
|
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime))
|
||||||
|
|
||||||
if blend == MixBlend.setup then
|
if blend == MixBlend.setup then
|
||||||
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
|
||||||
|
constraint.softness = constraint.data.softness
|
||||||
|
+ (softness + (frames[frame + SOFTNESS] - softness) * percent - constraint.data.softness) * 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.compress = constraint.data.compress
|
||||||
@ -1282,7 +1293,8 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
|||||||
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
|
||||||
|
constraint.softness = constraint.softness + (softness + (frames[frame + SOFTNESS] - softness) * percent - constraint.softness) * 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_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
|
||||||
|
|||||||
@ -34,6 +34,7 @@ local math_sqrt = math.sqrt
|
|||||||
local math_acos = math.acos
|
local math_acos = math.acos
|
||||||
local math_sin = math.sin
|
local math_sin = math.sin
|
||||||
local math_cos = math.cos
|
local math_cos = math.cos
|
||||||
|
local math_min = math.min
|
||||||
local table_insert = table.insert
|
local table_insert = table.insert
|
||||||
local math_deg = math.deg
|
local math_deg = math.deg
|
||||||
local math_rad = math.rad
|
local math_rad = math.rad
|
||||||
@ -51,6 +52,7 @@ function IkConstraint.new (data, skeleton)
|
|||||||
bones = {},
|
bones = {},
|
||||||
target = nil,
|
target = nil,
|
||||||
mix = data.mix,
|
mix = data.mix,
|
||||||
|
softness = data.softness,
|
||||||
compress = data.compress,
|
compress = data.compress,
|
||||||
stretch = data.stretch,
|
stretch = data.stretch,
|
||||||
bendDirection = data.bendDirection,
|
bendDirection = data.bendDirection,
|
||||||
@ -78,7 +80,7 @@ function IkConstraint:update ()
|
|||||||
if boneCount == 1 then
|
if boneCount == 1 then
|
||||||
self:apply1(bones[1], target.worldX, target.worldY, self.compress, self.stretch, self.data.uniform, 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.softness, self.mix)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform
|
|||||||
bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, 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, softness, alpha)
|
||||||
if alpha == 0 then
|
if alpha == 0 then
|
||||||
child:updateWorldTransform()
|
child:updateWorldTransform()
|
||||||
return
|
return
|
||||||
@ -169,19 +171,36 @@ function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch,
|
|||||||
c = pp.c
|
c = pp.c
|
||||||
d = pp.d
|
d = pp.d
|
||||||
local id = 1 / (a * d - b * c)
|
local id = 1 / (a * d - b * c)
|
||||||
local x = targetX - pp.worldX
|
local x = cwx - pp.worldX
|
||||||
local y = targetY - pp.worldY
|
local y = cwy - pp.worldY
|
||||||
local tx = (x * d - y * b) * id - px
|
|
||||||
local ty = (y * a - x * c) * id - py
|
|
||||||
local dd = tx * tx + ty * ty
|
|
||||||
x = cwx - pp.worldX
|
|
||||||
y = cwy - pp.worldY
|
|
||||||
local dx = (x * d - y * b) * id - px
|
local dx = (x * d - y * b) * id - px
|
||||||
local dy = (y * a - x * c) * id - py
|
local dy = (y * a - x * c) * id - py
|
||||||
local l1 = math_sqrt(dx * dx + dy * dy)
|
local l1 = math_sqrt(dx * dx + dy * dy)
|
||||||
local l2 = child.data.length * csx
|
local l2 = child.data.length * csx
|
||||||
local a1 = 0
|
local a1 = 0
|
||||||
local a2 = 0
|
local a2 = 0
|
||||||
|
if l1 < 0.0001 then
|
||||||
|
self:apply1(parent, targetX, targetY, false, stretch, false, alpha)
|
||||||
|
child:updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
x = targetX - pp.worldX
|
||||||
|
y = targetY - pp.worldY
|
||||||
|
local tx = (x * d - y * b) * id - px
|
||||||
|
local ty = (y * a - x * c) * id - py
|
||||||
|
local dd = tx * tx + ty * ty
|
||||||
|
if softness ~= 0 then
|
||||||
|
softness = softness * (psx * (csx + 1) / 2)
|
||||||
|
local td = math_sqrt(dd)
|
||||||
|
local sd = td - l1 - l2 * psx + softness
|
||||||
|
if sd > 0 then
|
||||||
|
local p = math_min(1, sd / (softness * 2)) - 1
|
||||||
|
p = (sd - softness * (1 - p * p)) / td
|
||||||
|
tx = tx - p * tx
|
||||||
|
ty = ty - p * ty
|
||||||
|
dd = tx * tx + ty * ty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if u then
|
if u then
|
||||||
l2 = l2 * psx
|
l2 = l2 * psx
|
||||||
|
|||||||
@ -41,7 +41,8 @@ function IkConstraintData.new (name)
|
|||||||
compress = false,
|
compress = false,
|
||||||
stretch = false,
|
stretch = false,
|
||||||
uniform = false,
|
uniform = false,
|
||||||
mix = 1
|
mix = 1,
|
||||||
|
softness = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@ -363,6 +363,7 @@ function Skeleton:setBonesToSetupPose ()
|
|||||||
|
|
||||||
for _,ikConstraint in ipairs(self.ikConstraints) do
|
for _,ikConstraint in ipairs(self.ikConstraints) do
|
||||||
ikConstraint.mix = ikConstraint.data.mix
|
ikConstraint.mix = ikConstraint.data.mix
|
||||||
|
ikConstraint.softness = ikConstraint.data.softness
|
||||||
ikConstraint.bendDirection = ikConstraint.data.bendDirection
|
ikConstraint.bendDirection = ikConstraint.data.bendDirection
|
||||||
ikConstraint.compress = ikConstraint.data.compress
|
ikConstraint.compress = ikConstraint.data.compress
|
||||||
ikConstraint.stretch = ikConstraint.data.stretch
|
ikConstraint.stretch = ikConstraint.data.stretch
|
||||||
|
|||||||
@ -168,6 +168,7 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
if not data.target then error("Target bone not found: " .. targetName) end
|
if not data.target then error("Target bone not found: " .. targetName) end
|
||||||
|
|
||||||
data.mix = getValue(constraintMap, "mix", 1)
|
data.mix = getValue(constraintMap, "mix", 1)
|
||||||
|
data.softness = getValue(constraintMap, "softness", 0)
|
||||||
if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == true then
|
if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == true then
|
||||||
data.bendDirection = 1
|
data.bendDirection = 1
|
||||||
else
|
else
|
||||||
@ -637,14 +638,16 @@ function SkeletonJson.new (attachmentLoader)
|
|||||||
local frameIndex = 0
|
local frameIndex = 0
|
||||||
for _,valueMap in ipairs(values) do
|
for _,valueMap in ipairs(values) do
|
||||||
local mix = 1
|
local mix = 1
|
||||||
|
local softness = 0
|
||||||
if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
|
if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
|
||||||
|
if valueMap["softness"] ~= nil then softness = valueMap["softness"] 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 = false
|
local stretch = false
|
||||||
if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
|
if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
|
||||||
local compress = false
|
local compress = false
|
||||||
if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
|
if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
|
||||||
timeline:setFrame(frameIndex, getValue(valueMap, "time", 0), mix, bendPositive, compress, stretch)
|
timeline:setFrame(frameIndex, getValue(valueMap, "time", 0), mix, softness, bendPositive, compress, stretch)
|
||||||
readCurve(valueMap, timeline, frameIndex)
|
readCurve(valueMap, timeline, frameIndex)
|
||||||
frameIndex = frameIndex + 1
|
frameIndex = frameIndex + 1
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user