Spaces:
Sleeping
Sleeping
Fix ZYX order for BVH format
Browse files- app_new.py +14 -14
app_new.py
CHANGED
|
@@ -233,21 +233,21 @@ def _quat_from_two_vectors(v1, v2):
|
|
| 233 |
q = np.array([w, cross[0], cross[1], cross[2]])
|
| 234 |
return q / (np.linalg.norm(q) + 1e-10)
|
| 235 |
|
| 236 |
-
def
|
| 237 |
-
"""Quaternion to Euler
|
| 238 |
w, x, y, z = q
|
| 239 |
-
#
|
| 240 |
-
sinr = 2 * (w * x + y * z)
|
| 241 |
-
cosr = 1 - 2 * (x * x + y * y)
|
| 242 |
-
rx = np.arctan2(sinr, cosr)
|
| 243 |
-
# Pitch (Y)
|
| 244 |
-
sinp = 2 * (w * y - z * x)
|
| 245 |
-
ry = np.arcsin(np.clip(sinp, -1, 1))
|
| 246 |
-
# Yaw (Z)
|
| 247 |
siny = 2 * (w * z + x * y)
|
| 248 |
cosy = 1 - 2 * (y * y + z * z)
|
| 249 |
rz = np.arctan2(siny, cosy)
|
| 250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
|
| 252 |
def joints_to_bvh(joints, output_path, fps=20):
|
| 253 |
"""Convert joint positions to BVH with proper local rotations."""
|
|
@@ -298,9 +298,9 @@ def joints_to_bvh(joints, output_path, fps=20):
|
|
| 298 |
local_rot = global_rot
|
| 299 |
|
| 300 |
global_quats[j] = global_rot
|
| 301 |
-
all_rotations[frame, j] =
|
| 302 |
|
| 303 |
-
# Write BVH
|
| 304 |
with open(output_path, "w") as f:
|
| 305 |
f.write("HIERARCHY\n")
|
| 306 |
def write_joint(idx, indent):
|
|
@@ -308,7 +308,7 @@ def joints_to_bvh(joints, output_path, fps=20):
|
|
| 308 |
pre = " " * indent
|
| 309 |
f.write(f"{'ROOT' if idx==0 else pre+'JOINT'} {name}\n{pre}{{\n")
|
| 310 |
f.write(f"{pre} OFFSET {off[0]:.6f} {off[1]:.6f} {off[2]:.6f}\n")
|
| 311 |
-
f.write(f"{pre} CHANNELS {'6 Xposition Yposition Zposition ' if idx==0 else '3 '}
|
| 312 |
if children[idx]:
|
| 313 |
for c in children[idx]: write_joint(c, indent + 1)
|
| 314 |
else:
|
|
|
|
| 233 |
q = np.array([w, cross[0], cross[1], cross[2]])
|
| 234 |
return q / (np.linalg.norm(q) + 1e-10)
|
| 235 |
|
| 236 |
+
def _quat_to_euler_zyx(q):
|
| 237 |
+
"""Quaternion to Euler ZYX order (degrees) - standard BVH format."""
|
| 238 |
w, x, y, z = q
|
| 239 |
+
# Z rotation (yaw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
siny = 2 * (w * z + x * y)
|
| 241 |
cosy = 1 - 2 * (y * y + z * z)
|
| 242 |
rz = np.arctan2(siny, cosy)
|
| 243 |
+
# Y rotation (pitch)
|
| 244 |
+
sinp = 2 * (w * y - z * x)
|
| 245 |
+
ry = np.arcsin(np.clip(sinp, -1, 1))
|
| 246 |
+
# X rotation (roll)
|
| 247 |
+
sinr = 2 * (w * x + y * z)
|
| 248 |
+
cosr = 1 - 2 * (x * x + y * y)
|
| 249 |
+
rx = np.arctan2(sinr, cosr)
|
| 250 |
+
return np.degrees([rz, ry, rx]) # ZYX order for BVH
|
| 251 |
|
| 252 |
def joints_to_bvh(joints, output_path, fps=20):
|
| 253 |
"""Convert joint positions to BVH with proper local rotations."""
|
|
|
|
| 298 |
local_rot = global_rot
|
| 299 |
|
| 300 |
global_quats[j] = global_rot
|
| 301 |
+
all_rotations[frame, j] = _quat_to_euler_zyx(local_rot)
|
| 302 |
|
| 303 |
+
# Write BVH (ZYX rotation order - standard for BVH)
|
| 304 |
with open(output_path, "w") as f:
|
| 305 |
f.write("HIERARCHY\n")
|
| 306 |
def write_joint(idx, indent):
|
|
|
|
| 308 |
pre = " " * indent
|
| 309 |
f.write(f"{'ROOT' if idx==0 else pre+'JOINT'} {name}\n{pre}{{\n")
|
| 310 |
f.write(f"{pre} OFFSET {off[0]:.6f} {off[1]:.6f} {off[2]:.6f}\n")
|
| 311 |
+
f.write(f"{pre} CHANNELS {'6 Xposition Yposition Zposition ' if idx==0 else '3 '}Zrotation Yrotation Xrotation\n")
|
| 312 |
if children[idx]:
|
| 313 |
for c in children[idx]: write_joint(c, indent + 1)
|
| 314 |
else:
|