| from pathlib import Path |
|
|
| import bpy |
| import numpy as np |
| import math |
| from mathutils import Matrix, Vector |
|
|
| |
| 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"] |
|
|
| 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 |
| 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() |
|
|