mirror of
https://github.com/OpenVGLab/OmniLottie.git
synced 2026-09-17 07:36:27 +00:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
from..nvector import NVector
|
||||
|
||||
|
||||
# FABRIK
|
||||
class Chain:
|
||||
def __init__(self, tail, fixed_tail=True, tolerance=0.5, max_iter=8):
|
||||
self.joints = [tail.clone()]
|
||||
self.fixed_tail = fixed_tail
|
||||
self.lengths = []
|
||||
self.total_length = 0
|
||||
self.tolerance = tolerance
|
||||
self.max_iter = max_iter
|
||||
|
||||
def add_joint(self, point):
|
||||
length = (point - self.joints[-1]).length
|
||||
self.lengths.append(length)
|
||||
self.total_length += length
|
||||
self.joints.append(point.clone())
|
||||
|
||||
def add_joints(self, head, n):
|
||||
delta = head - self.joints[-1]
|
||||
self.total_length += delta.length
|
||||
segment = delta / n
|
||||
seglen = segment.length
|
||||
for i in range(n):
|
||||
self.lengths.append(seglen)
|
||||
self.joints.append(self.joints[-1] + segment)
|
||||
|
||||
def backward(self, target):
|
||||
"""!
|
||||
target -> -> start
|
||||
"""
|
||||
self.joints[-1] = target
|
||||
for i in range(len(self.joints)-2, -1, -1):
|
||||
r = self.joints[i+1] - self.joints[i]
|
||||
l = self.lengths[i] / r.length
|
||||
self.joints[i] = self.joints[i+1].lerp(self.joints[i], l)
|
||||
|
||||
def forward(self, target):
|
||||
"""!
|
||||
start -> -> tail
|
||||
"""
|
||||
self.joints[0] = target
|
||||
for i in range(0, len(self.joints)-1):
|
||||
r = self.joints[i+1] - self.joints[i]
|
||||
l = self.lengths[i] / r.length
|
||||
self.joints[i+1] = self.joints[i].lerp(self.joints[i+1], l)
|
||||
|
||||
def reach(self, target):
|
||||
if not self.fixed_tail:
|
||||
self.backward(target)
|
||||
return
|
||||
|
||||
distance = (target - self.joints[0]).length
|
||||
if distance >= self.total_length:
|
||||
for i in range(len(self.joints)-1):
|
||||
r = target - self.joints[i]
|
||||
l = self.lengths[i] / r.length
|
||||
self.joints[i+1] = self.joints[i].lerp(target, l)
|
||||
return
|
||||
|
||||
base = self.joints[0]
|
||||
|
||||
distance = (target - self.joints[-1]).length
|
||||
n_it = 0
|
||||
while distance > self.tolerance and n_it < self.max_iter:
|
||||
self.backward(target)
|
||||
self.forward(base)
|
||||
distance = (target - self.joints[-1]).length
|
||||
n_it += 1
|
||||
|
||||
|
||||
class Octopus:
|
||||
def __init__(self, master):
|
||||
self.chains = {"master": master}
|
||||
self.master = master
|
||||
|
||||
@property
|
||||
def base(self):
|
||||
return self.master.joints[-1]
|
||||
|
||||
def add_chain(self, name):
|
||||
ch = Chain(self.base)
|
||||
self.chains[name] = ch
|
||||
return ch
|
||||
|
||||
def reach(self, target_map):
|
||||
centroid = NVector(0, 0)
|
||||
for chain, target in target_map.items():
|
||||
self.chains[chain].backward(target)
|
||||
centroid += self.chains[chain].joints[0]
|
||||
centroid /= len(target_map)
|
||||
|
||||
self.master.reach(centroid)
|
||||
|
||||
for chain in target_map.keys():
|
||||
self.chains[chain].forward(self.base)
|
||||
Reference in New Issue
Block a user