File size: 3,363 Bytes
7e120dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | from pathlib import Path
import bpy
import numpy as np
import math
from mathutils import Matrix, Vector
# Hardcode your NPZ path here. Use raw string or forward slashes to avoid backslash escapes.
NPZ_PATH = Path(r"D:\Users\Adam\Downloads\VRM_JG6Z7WA_clip_0_global_smplx.npz")
CAMERA_NAME = "GenmoCamera"
SPHERE_NAME = "TestSphere"
FPS = 30
ROTATE_LOCAL_Z_DEG = 180.0
ROTATE_LOCAL_Y_DEG = 180.0
def _ensure_camera(name: str) -> bpy.types.Object:
cam_obj = bpy.data.objects.get(name)
if cam_obj is None:
cam_data = bpy.data.cameras.new(name)
cam_obj = bpy.data.objects.new(name, cam_data)
bpy.context.collection.objects.link(cam_obj)
return cam_obj
def _apply_fov(cam_obj: bpy.types.Object, npz_data: np.lib.npyio.NpzFile) -> None:
cam_data = cam_obj.data
fov_y_deg = float(npz_data["fov_y_deg"]) if "fov_y_deg" in npz_data else None
fov_x_deg = float(npz_data["fov_x_deg"]) if "fov_x_deg" in npz_data else None
if (fov_x_deg is None or fov_y_deg is None) and "K_fullimg" in npz_data:
K_fullimg = npz_data["K_fullimg"]
if K_fullimg.ndim == 3:
K0 = K_fullimg[0]
else:
K0 = K_fullimg
fx = float(K0[0, 0])
fy = float(K0[1, 1])
cx = float(K0[0, 2])
cy = float(K0[1, 2])
width = 2.0 * cx
height = 2.0 * cy
if fov_x_deg is None and fx > 0 and width > 0:
fov_x_deg = math.degrees(2.0 * math.atan(width / (2.0 * fx)))
if fov_y_deg is None and fy > 0 and height > 0:
fov_y_deg = math.degrees(2.0 * math.atan(height / (2.0 * fy)))
if fov_y_deg is not None:
cam_data.angle_y = math.radians(float(fov_y_deg))
elif fov_x_deg is not None:
cam_data.angle = math.radians(float(fov_x_deg))
def _ensure_sphere(name: str) -> bpy.types.Object:
obj = bpy.data.objects.get(name)
if obj is None:
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.2, location=(0.0, 0.0, 0.0))
obj = bpy.context.active_object
obj.name = name
return obj
def main():
npz_path = NPZ_PATH
if not npz_path.is_absolute():
npz_path = Path(bpy.path.abspath("//")) / npz_path
data = np.load(str(npz_path))
if "camera_transform" not in data:
raise ValueError("NPZ is missing 'camera_transform'")
camera_transform = data["camera_transform"] # (F, 4, 4)
scene = bpy.context.scene
scene.render.fps = FPS
scene.frame_start = 1
scene.frame_end = int(camera_transform.shape[0])
cam_obj = _ensure_camera(CAMERA_NAME)
scene.camera = cam_obj
_ensure_sphere(SPHERE_NAME)
_apply_fov(cam_obj, data)
for i, T in enumerate(camera_transform):
frame = i + 1
mat = Matrix(T.tolist())
rot_z = Matrix.Rotation(math.radians(ROTATE_LOCAL_Z_DEG), 3, Vector((0.0, 0.0, 1.0)))
rot_y = Matrix.Rotation(math.radians(ROTATE_LOCAL_Y_DEG), 3, Vector((0.0, 1.0, 0.0)))
rot_local = rot_y @ rot_z # first local Z, then local Y
new_rot = mat.to_3x3() @ rot_local
new_mat = new_rot.to_4x4()
new_mat.translation = mat.to_translation()
cam_obj.matrix_world = new_mat
cam_obj.keyframe_insert(data_path="location", frame=frame)
cam_obj.keyframe_insert(data_path="rotation_euler", frame=frame)
if __name__ == "__main__":
main()
|