main
John Lauer Rev 2 hero 3D: an adult hand for scale beside the case (CC0, MakeHuman base mesh) 9852f34 1d ago
import json, numpy as np, trimesh
m=trimesh.load('hand_raw.ply')
V=[];
for l in open('base.obj'):
    if l.startswith('v '): V.append([float(x) for x in l.split()[1:4]])
V=np.array(V)
w=json.load(open('default_weights.mhw'))['weights']
def pts(prefixes,th=0.5):
    s=np.zeros(len(V))
    for b in w:
        if b.endswith('.R') and b.startswith(prefixes):
            for i,x in w[b]: s[i]+=x
    return V[s>th]
wrist=pts(('wrist',)).mean(0)
tip=pts(('finger3-3',),0.8)            # middle fingertip segment
tipf=tip[np.argmax(np.linalg.norm(tip-wrist,axis=1))]
thumb=pts(('finger1-3',),0.8).mean(0)
pinky=pts(('finger5-3',),0.8).mean(0)
L=tipf-wrist; Lu=L/np.linalg.norm(L)
side=thumb-pinky; side-=side.dot(Lu)*Lu; Su=side/np.linalg.norm(side)
N=np.cross(Lu,Su)                      # normal; sign checked below
# palm faces the body (+x in MakeHuman A-pose); make Nd point to the palm side
if N[0]<0: N=-N
print('wrist',wrist.round(3),'len dm',np.linalg.norm(L).round(3))
# right hand palm down: fingers +Y, palm normal -Z, then thumb lands on -X (left side seen from above)
R=np.stack([np.cross(Lu,-N),Lu,-N])    # rows: new X,Y,Z axes expressed in old coords -> want Lu->Y, N->-Z
# new coords = R @ (p - wrist): X = (Lu x -N)·p, Y = Lu·p, Z = -N·p  => palm (N side) goes to -Z
P=(m.vertices-wrist)@R.T
scale=0.180/(np.linalg.norm(L))        # 180 mm wrist-to-middle-tip, in metres
P*=scale
P[:,2]-=P[:,2].min()                   # rest on the counter
h=trimesh.Trimesh(P,m.faces,process=False)
if h.volume<0: h.invert()
h=h.subdivide_loop(1) if hasattr(h,'subdivide_loop') else h
h.visual=trimesh.visual.TextureVisuals(material=trimesh.visual.material.PBRMaterial(name='skin',baseColorFactor=[224,172,140,255],metallicFactor=0.0,roughnessFactor=0.65))
print('extents mm',(h.extents*1000).round(1),'faces',len(h.faces),'thumb x',((thumb-wrist)@R.T*scale*1000).round(1))
h.export('hand_ref.glb'); import os; print(os.path.getsize('hand_ref.glb')//1024,'KB')