Download scripts/blender_load_camera.py from zirobtc/vr-hmr: direct link, hf CLI and curl.
- Browser
- Download file 3.36 kB
-
https://huggingface.co/zirobtc/vr-hmr/resolve/main/scripts/blender_load_camera.py
- Command line
-
hf download hf://zirobtc/vr-hmr/scripts/blender_load_camera.py
-
curl -L -o blender_load_camera.py https://huggingface.co/zirobtc/vr-hmr/resolve/main/scripts/blender_load_camera.py
3.36 kB
| 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() | |