'/Users/davidbelgrod/Repos/libigl-python-bindings/igl/__init__.py'
#https://github.com/libigl/libigl-tutorial-data
import numpy as np
import igl
import meshplot as mp
from scipy.spatial.transform import Rotation
import ipywidgets as iw
import time
from math import exp
import quaternion
import pickle
from joblib import Parallel, delayed
import contextlib
import joblib
from tqdm import tqdm
@contextlib.contextmanager
def tqdm_joblib(tqdm_object):
"""Context manager to patch joblib to report into tqdm progress bar given as argument"""
class TqdmBatchCompletionCallback(joblib.parallel.BatchCompletionCallBack):
def __call__(self, *args, **kwargs):
tqdm_object.update(n=self.batch_size)
return super().__call__(*args, **kwargs)
old_batch_callback = joblib.parallel.BatchCompletionCallBack
joblib.parallel.BatchCompletionCallBack = TqdmBatchCompletionCallback
try:
yield tqdm_object
finally:
joblib.parallel.BatchCompletionCallBack = old_batch_callback
tqdm_object.close()
V, F = igl.read_triangle_mesh('data/arm.obj')
C,BE,_,_,_,_ = igl.read_tgf('data/arm.tgf')
W = igl.read_dmat('data/arm-weights.dmat')
# labels = np.load('data/hand.label.npy').astype(int)
# v -= v.min(axis=0)
# v /= v.max()
# mp.plot(V,F)
# V, F = igl.read_triangle_mesh('data/untitled.obj')
# mp.plot(V,F)
F
array([[ 352, 350, 349],
[ 352, 349, 0],
[ 349, 351, 0],
...,
[7961, 8258, 7785],
[8004, 8071, 7751],
[7648, 8175, 8137]], dtype=int64)
# TV = np.concatenate((V, C))
# TE = BE + V.shape[0]
# labels = np.concatenate((np.zeros(V.shape[0]), np.array(range(1,C.shape[0]+1)))).astype(int)
labels = np.array(range(BE.shape[0])).astype(int)
def circle_sum(q1, q2):
return q1 + q2 if np.dot(quaternion.as_float_array(q1), quaternion.as_float_array(q2)) >= 0 else q1 - q2
def apply_weighted_rotation(vertices, wgts, quat, CoR, translation): #vertices, weights, rot (as quat), CoR, translation array
vnew = vertices.copy()
for i in range(vertices.shape[0]):
vi = vertices[i]
wi = wgts[i]
q = quaternion.as_quat_array([0,0,0,0])
for j in range(BE.shape[0]): # #BE
qj = quat[j]
wij = wi[j]
q = circle_sum(q, wij*qj)
# wqi = np.sum(qi, axis=0)
q /= np.linalg.norm(quaternion.as_float_array(q))
R = quaternion.as_rotation_matrix(q)
Rtilda = np.zeros((3,3))
ttilda = np.zeros((3,1))
for j in range(BE.shape[0]):
Rj = quaternion.as_rotation_matrix(quat[j]) #3 x 3
tj = translation[j] # 1 x 3
wij = wi[j]
Rtilda += wij*Rj
ttilda += wij*tj.reshape((3,1))
t = Rtilda @ CoR[i].reshape((3,1)) + ttilda - R @ CoR[i].reshape((3,1))
vnew[i] = (R @ vi.reshape((3,1)) + t).reshape(3)
return vnew
def similarity(Wp, Wv, sigma=0.1):
#BE shape
Wp = Wp if len(Wp.shape) == 1 else Wp.reshape(-1)
Wv = Wv if len(Wv.shape) == 1 else Wv.reshape(-1)
tot = 0
for j in range(Wp.shape[0]):
for k in range(j+1, Wv.shape[0]):
tot += Wp[j]*Wp[k]*Wv[j]*Wv[k]*exp( -(Wp[j]*Wv[k] - Wp[k]*Wv[j])**2 / sigma**2)
return tot
def CoR(i, weights, vertices, faces, omega=0.1, pb = None):
num = np.zeros([1, 3])
denom = np.zeros([1,3])
for t in range(faces.shape[0]):
# cmp = [i for i in range(3) if np.linalg.norm(weights[i] - weights[faces[t,i]]) < omega]
cmp = [0, 1,2]
if not cmp:
continue
s = similarity(weights[i], np.mean([weights[faces[t,c]] for c in cmp], axis = 0))
v = np.mean([vertices[faces[t,c]] for c in cmp], axis = 0)
a = igl.doublearea(vertices, faces[[t]]) / 2
num += s * v * a
denom += s * a
pi = num / denom
if pb:
pb.value = i
return pi
# P = np.zeros(V.shape)
# with tqdm_joblib(tqdm(desc="My calculation", total=P.shape[0])) as progress_bar:
# P = np.array(Parallel(n_jobs=10)(delayed(CoR)(i, W, V, F) for i in range(P.shape[0])))
# pickle.dump(P, open("data/CoR.p", "wb"))
P = pickle.load(open('data/CoR.p', 'rb'))
mp.plot(P)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0007487…
<meshplot.Viewer.Viewer at 0x7fa1990936a0>
OCoR = V.copy()
pos_f_saver = np.zeros((labels.max()+1, 7))
def pos_f(s,x,y,z, w, α, β, γ, plt):
global OCoR
clicked_edges = BE[np.isin(labels, s)]
slices = []
for e in clicked_edges:
for v in e:
if v not in slices:
slices.append(v)
# r = Rotation.from_euler('xyz', [α, β, γ], degrees=True)
r = Rotation.from_quat([α, β, γ, w])
v_slice = C[slices] + np.array([[x,y,z]])
C1 = C.copy()
C1[slices] = r.apply(v_slice)
for si in s:
pos_f_saver[si] = [x,y,z,w,α,β,γ]
q = np.zeros((BE.shape[0], 4))
t = np.zeros((BE.shape[0], 3))
for i in range(BE.shape[0]):
# res = Qt0[i].inverse() * Qt1[i]
# diff[i,:] = [res.w, res.x, res.y, res.z]
xi,yi,zi,wi,αi,βi,γi = pos_f_saver[i]
q[i,:] = [wi,αi,βi,γi]
t[i,:] = [xi, yi, zi]
# q /= np.linalg.norm(q, axis=1)
Q = quaternion.as_quat_array(q)
OCoR = V.copy()
OCoR = apply_weighted_rotation(V, W, Q, P, t)
v_deformed = pos_f.deformer(OCoR)
plt.update_object(vertices = v_deformed)
# p.remove_object(max(p._Viewer__objects.keys()))
# p.add_edges(C1+np.repeat([[0,.25,0]], C1.shape[0], axis=0), BE, shading={"line_color": "green"})
pos_f.deformer = lambda x:x
def widgets_wrapper():
# segment_widget = iw.Dropdown(options=np.arange(labels.max()) + 1)
segment_widget = iw.SelectMultiple(options=np.arange(labels.max()+1))
translate_widget = {i:iw.FloatSlider(min=-1, max=1, value=0)
for i in 'xyz'}
# rotate_widget = {a:iw.FloatSlider(min=-90, max=90, value=0, step=1)
# for a in 'αβγ'}
real_widget = {a:iw.FloatSlider(min=-2, max=2, value=1, step=.25)
for a in 'w'}
imag_widget = {a:iw.FloatSlider(min=-1, max=1, value=0, step=.1)
for a in 'αβγ'}
def update_seg(*args):
(translate_widget['x'].value,translate_widget['y'].value,
translate_widget['z'].value, real_widget['w'].value,
imag_widget['α'].value,imag_widget['β'].value,
imag_widget['γ'].value) = pos_f_saver[segment_widget.value]
segment_widget.observe(update_seg, 'value')
widgets_dict = dict(s=segment_widget)
widgets_dict.update(translate_widget)
widgets_dict.update(real_widget)
widgets_dict.update(imag_widget)
return widgets_dict
def position_deformer(target_pos):
'''Fill in this function to change positions'''
return target_pos
''' (Optional) Register this function to perform interactive deformation
pos_f.deformer = position_deformer
'''
' (Optional) Register this function to perform interactive deformation\npos_f.deformer = position_deformer\n'
## Widget UI
p = mp.plot(V, F)
# p.add_edges(C,BE, shading={"line_color": "green"});
iw.interact(pos_f,
**widgets_wrapper(), plt=iw.fixed(p))
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
interactive(children=(SelectMultiple(description='s', options=(0, 1, 2, 3), value=()), FloatSlider(value=0.0, …
<function __main__.pos_f(s, x, y, z, w, α, β, γ, plt)>
# deform(hand_full_rotation | {'x': .2}, p1)
def reset(plot):
hand_full_rotation = {'s' : [0,1,2,3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : 1, 'α' : 0, 'β' : 0, 'γ' : 0}
pos_f(**hand_full_rotation, plt=plot)
p1 = mp.plot(V,F)
hand_full_rotation = {'s' : [0,1,2,3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : 1, 'α' : 0, 'β' : 0, 'γ' : 0, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
p1.add_mesh(v_deformed + shft, F)
p1.add_mesh(U+2*shft, F)
reset(p1)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
Cool illustrations
p1 = mp.plot(V,F)
reset(p1)
hand_full_rotation = {'s' : [0,1,2,3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : 1, 'α' : 0, 'β' : 0, 'γ' : 0, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
p1.add_mesh(v_deformed + shft, F)
p1.add_mesh(U+2*shft, F)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
2
p1 = mp.plot(V,F)
reset(p1)
hand_full_rotation = {'s' : [0,1,2,3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : 0, 'α' : 0, 'β' : 0, 'γ' : -1, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
# p1.add_mesh(v_deformed + shft, F)
p1.add_mesh(U+2*shft, F)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
1
p1._Viewer__s["scale"] *= 2
# p1._Viewer__objects[0]["mesh"].add
import pythreejs as p3s
def add_text(viewer, text):
sh = viewer._Viewer__get_shading({})
tt = p3s.TextTexture(string=text, color="white", size=100, fontFace="cambria")
sm = p3s.SpriteMaterial(map=tt, fog=False, transparent=False)
obj = viewer._Viewer__objects[viewer._Viewer__cnt - 1]
mesh = obj["mesh"]
loc = (obj.get("min")[0], obj.get("max")[1], obj.get("max")[2])
# loc[2] += .1
print(text, viewer._Viewer__cnt, loc)
s = p3s.Sprite(material=sm, scale = (.2,.2,.2), position=loc, center = (.5,.5))
viewer.text = s
viewer._scene.add(viewer.text)
# sobj = {"mesh" : s}
# viewer._Viewer__add_object(sobj, mesh)
# p1._Viewer__update_view()
vtmp = np.zeros((1,3))
ftmp = np.zeros((1,3))
3
p1 = mp.plot(vtmp, ftmp)
reset(p1)
hand_full_rotation = {'s' : [2,3], 'x': -.1, 'y' : 0.2, 'z' : 0.0, 'w' : .5, 'α' : -1, 'β' : -.5, 'γ' : 0, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
p1.add_mesh(v_deformed, F)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
add_text(p1, "CoR")
# p1.add_mesh(v_deformed + shft, F)
p1.add_mesh(U+2*shft, F)
#adding in
add_text(p1, "DQS")
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0, 0.0,…
CoR 2 (-0.9104905, 0.9316595, 0.48011917)
DQS 3 (-0.9106639, -0.06529052, 0.48666853)
p1 = mp.plot(vtmp, ftmp, return_plot = True)
p1._Viewer__s["scale"] *= 1.2
reset(p1)
hand_full_rotation = {'s' : [3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : -2, 'α' : 1, 'β' : 0, 'γ' : 0, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
p1.add_mesh(v_deformed, F)
add_text(p1, "CoR")
# p1.add_mesh(v_deformed + shft, F)
p1.add_mesh(U+2*shft, F)
add_text(p1, "DQS")
p1._Viewer__update_view()
p1.save("blending.html")
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0, 0.0,…
CoR 2 (-0.910616, 0.37081754, 0.3392871)
DQS 3 (-0.910616, -0.629097, 0.34136364)
Plot saved to file blending.html.
p1._Viewer__update_view()
play = iw.Play(
value=0,
min=0,
max=40,
step=1,
interval=1000,
description="Press play",
disabled=False
)
slider = iw.IntSlider()
iw.jslink((play, 'value'), (slider, 'value'))
iw.HBox([play, slider])
HBox(children=(Play(value=0, description='Press play', interval=1000, max=40), IntSlider(value=0)))
hand_full_rotation = {'s' : [3], 'x': 0, 'y' : 0, 'z' : 0, 'w' : 1, 'α' : 0, 'β' : 0, 'γ' : 0}
p = mp.plot(V,F, return_plot=True)
def deform(x, hand_rot, plot):
# reset(plot=plot)
res = hand_rot | {'w': 1-x/10, 'α' : x/10}
pos_f(**res, plt = plot)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
# plot = mp.plot(V,F)
# while len(plot._Viewer__objects.keys()) > 1:
# plot.remove_object(max(plot._Viewer__objects.keys()))
# plot.add_mesh(v_deformed + shft, F)
# plot.add_mesh(U+2*shft, F)
# display(plot._renderer)
plot._Viewer__update_view()
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
play = iw.Play(
value=0,
min=0,
max=40,
step=1,
interval=1000,
description="Press play",
disabled=False
)
slider = iw.IntSlider()
p = mp.plot(V,F)
iw.interact(deform, x = slider, hand_rot=iw.fixed(hand_full_rotation), plot = iw.fixed(p))
iw.jslink((play, 'value'), (slider, 'value'))
iw.HBox([play, slider])
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(0.0001610…
interactive(children=(IntSlider(value=0, description='x'), Output()), _dom_classes=('widget-interact',))
HBox(children=(Play(value=0, description='Press play', interval=1000, max=40), IntSlider(value=0, description=…
Animation part
from pythreejs import *
from IPython.display import display
from math import pi
<bound method Geometry.from_geometry of <class 'pythreejs.core.Geometry.Geometry'>>
# https://github.com/jupyter-widgets/pythreejs/blob/master/examples/Examples.ipynb
vertices = [
[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]
]
faces = [
[0, 1, 3],
[0, 3, 2],
[0, 2, 4],
[2, 6, 4],
[0, 4, 1],
[1, 4, 5],
[2, 3, 6],
[3, 7, 6],
[1, 5, 3],
[3, 5, 7],
[4, 6, 5],
[5, 6, 7]
]
vertexcolors = ['#000000', '#0000ff', '#00ff00', '#ff0000',
'#00ffff', '#ff00ff', '#ffff00', '#ffffff']
# Map the vertex colors into the 'color' slot of the faces
faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces]
# Create the geometry:
cubeGeometry = Geometry(vertices=vertices,
faces=faces,
colors=vertexcolors)
# Calculate normals per face, for nice crisp edges:
cubeGeometry.exec_three_obj_method('computeFaceNormals')
# Create a mesh. Note that the material need to be told to use the vertex colors.
myobjectCube = Mesh(
geometry=cubeGeometry,
material=MeshLambertMaterial(vertexColors='VertexColors'),
position=[-0.5, -0.5, -0.5], # Center the cube
)
# Set up a scene and render it:
cCube = PerspectiveCamera(position=[3, 3, 3], fov=20,
children=[DirectionalLight(color='#ffffff', position=[-3, 5, 1], intensity=0.5)])
sceneCube = Scene(children=[myobjectCube, cCube, AmbientLight(color='#dddddd')])
rendererCube = Renderer(camera=cCube, background='black', background_opacity=1,
scene=sceneCube, controls=[OrbitControls(controlling=cCube)])
display(rendererCube)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(intensity=0.5, position=(-3.0, 5.0, 1.0), quatern…
Animating the CoR
# p1 = mp.plot(V,F)
# reset(p1)
hand_full_rotation = {'s' : [2,3], 'x': -.1, 'y' : 0.2, 'z' : 0.0, 'w' : .5, 'α' : -1, 'β' : -.5, 'γ' : 0, 'plt' : p1}
pos_f(**hand_full_rotation)
v_deformed = pos_f.deformer(OCoR)
vT = np.array(pos_f_saver[:, :3])
vQ = np.array(pos_f_saver[:, [4,5,6,3]], order='C')
U = igl.dqs(V,W, vQ, vT)
shft = np.zeros(V.shape)
shft[:,1] = -.5
# # p1.add_mesh(v_deformed + shft, F)
# p1.add_mesh(U+2*shft, F)
hV = V.astype('float32')
hF = F.astype('uint16').ravel()
handGeometry = BufferGeometry(attributes=dict(
position=BufferAttribute(hV, normalized=False),
index=BufferAttribute(hF, normalized=False)))
Preview(child=BufferGeometry(attributes={'position': <BufferAttribute shape=(8311, 3), dtype=float32>, 'index'…
V, F = igl.read_triangle_mesh('data/arm.obj')
C,BE,_,_,_,_ = igl.read_tgf('data/arm.tgf')
W = igl.read_dmat('data/arm-weights.dmat')
labels = np.array(range(BE.shape[0])).astype(int)
def apply_ocor(s,x,y,z, w, α, β, γ):
clicked_edges = BE[np.isin(labels, s)]
slices = []
for e in clicked_edges:
for v in e:
if v not in slices:
slices.append(v)
r = Rotation.from_quat([α, β, γ, w])
v_slice = C[slices] + np.array([[x,y,z]])
C1 = C.copy()
C1[slices] = r.apply(v_slice)
q = np.repeat([[w,α, β, γ]], BE.shape[0], axis=0)
t = np.repeat([[x,y,z]], BE.shape[0], axis=0)
# t = np.zeros((BE.shape[0], 3))
# for i in range(BE.shape[0]):
# xi,yi,zi,wi,αi,βi,γi = pos_f_saver[i]
# q[i,:] = [wi,αi,βi,γi]
# t[i,:] = [xi, yi, zi]
Q = quaternion.as_quat_array(q)
OCoR = apply_weighted_rotation(V, W, Q, P, t)
return OCoR
rotation = {'s' : [2,3], 'x': -.1, 'y' : 0.2, 'z' : 0.0, 'w' : .5, 'α' : -1, 'β' : -.5, 'γ' : 0}
nV = apply_ocor(**rotation)
hnV = nV.astype('float32')
handGeometry = BufferGeometry(attributes=dict(
position=BufferAttribute(hV, normalized=False),
index=BufferAttribute(hF, normalized=False)),
morphAttributes=dict(
position=[BufferAttribute(hnV, normalized=False)]))
Preview(child=BufferGeometry(attributes={'position': <BufferAttribute shape=(8311, 3), dtype=float32>, 'index'…
handGeometry.exec_three_obj_method('computeFaceNormals')
morphMesh = Mesh(handGeometry, MeshPhongMaterial(
color='#ff3333', shininess=150, morphTargets=True))
pill_track = NumberKeyframeTrack(
name='.morphTargetInfluences[0]', times=[0, 1.5, 3], values=[0, 2.5, 0])
pill_clip = AnimationClip(tracks=[pill_track])
pill_action = AnimationAction(AnimationMixer(morphMesh), pill_clip, morphMesh)
view_width = 600
view_height = 400
camera3 = PerspectiveCamera( position=[5, 3, 5], aspect=view_width/view_height)
scene3 = Scene(children=[morphMesh, camera3,
DirectionalLight(position=[3, 5, 1], intensity=0.6),
AmbientLight(intensity=0.5)])
renderer3 = Renderer(camera=camera3, scene=scene3,
controls=[OrbitControls(controlling=camera3)],
width=view_width, height=view_height)
display(renderer3, pill_action)
Renderer(camera=PerspectiveCamera(aspect=1.5, position=(5.0, 3.0, 5.0), projectionMatrix=(1.0, 0.0, 0.0, 0.0, …
AnimationAction(clip=AnimationClip(tracks=(NumberKeyframeTrack(name='.morphTargetInfluences[0]', times=array([…
# push multiple iterations of the rotation and render through all of them and back
ball = Mesh(geometry=SphereGeometry(radius=1, widthSegments=32, heightSegments=24),
material=MeshLambertMaterial(color='red'),
position=[2, 1, 0])
c = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0],
children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)])
scene = Scene(children=[ball, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)])
display(renderer)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.5, position=(3.0, 5.0,…
# import time, math
# ball.material.color = '#4400dd'
# for i in range(1, 150, 2):
# ball.scale = (i / 100.,) * 3
# ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]
# time.sleep(.05)