Skip to content

Commit

Permalink
Make split_inview accept query multiple cameras, refactor camera hand…
Browse files Browse the repository at this point in the history
…ling
  • Loading branch information
araistrick authored and pvl-bot committed Oct 28, 2024
1 parent 4b68e9c commit f4710c4
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 265 deletions.
8 changes: 4 additions & 4 deletions infinigen/assets/objects/rocks/boulder.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class BoulderFactory(AssetFactory):
def __init__(
self,
factory_seed,
meshing_camera=None,
meshing_cameras=None,
adapt_mesh_method="remesh",
cam_meshing_max_dist=1e7,
coarse=False,
do_voronoi=True,
):
super(BoulderFactory, self).__init__(factory_seed, coarse)

self.camera = meshing_camera
self.cameras = meshing_cameras
self.cam_meshing_max_dist = cam_meshing_max_dist
self.adapt_mesh_method = adapt_mesh_method

Expand Down Expand Up @@ -166,10 +166,10 @@ def geo_extrusion(nw: NodeWrangler, extrude_scale=1):
nw.new_node(Nodes.GroupOutput, input_kwargs={"Geometry": geometry})

def create_asset(self, i, placeholder, face_size=0.01, distance=0, **params):
if self.camera is not None and distance < self.cam_meshing_max_dist:
if self.cameras is not None and distance < self.cam_meshing_max_dist:
assert self.adapt_mesh_method != "remesh"
skin_obj, outofview, vert_dists, _ = split_inview(
placeholder, cam=self.camera, vis_margin=0.15
placeholder, cameras=self.cameras, vis_margin=0.15
)
butil.parent_to(outofview, skin_obj, no_inverse=True, no_transform=True)
face_size = detail.target_face_size(vert_dists.min())
Expand Down
8 changes: 4 additions & 4 deletions infinigen/assets/objects/trees/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(
child_col,
trunk_surface,
realize=False,
meshing_camera=None,
meshing_cameras=None,
cam_meshing_max_dist=1e7,
coarse_mesh_placeholder=False,
adapt_mesh_method="remesh",
Expand All @@ -73,7 +73,7 @@ def __init__(
self.trunk_surface = trunk_surface
self.realize = realize

self.camera = meshing_camera
self.cameras = meshing_cameras
self.cam_meshing_max_dist = cam_meshing_max_dist
self.adapt_mesh_method = adapt_mesh_method
self.decimate_placeholder_levels = decimate_placeholder_levels
Expand Down Expand Up @@ -168,12 +168,12 @@ def create_asset(
),
)

if self.camera is not None and distance < self.cam_meshing_max_dist:
if self.cameras is not None and distance < self.cam_meshing_max_dist:
assert self.adapt_mesh_method != "remesh"

skin_obj_cleanup = skin_obj
skin_obj, outofview, vert_dists, _ = split_inview(
skin_obj, cam=self.camera, vis_margin=0.15
skin_obj, cameras=self.cameras, vis_margin=0.15
)
butil.parent_to(outofview, skin_obj, no_inverse=True, no_transform=True)

Expand Down
30 changes: 17 additions & 13 deletions infinigen/core/execute_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def get_scene_tag(name):
def render(
scene_seed,
output_folder,
camera_id,
camera,
render_image_func=render_image,
resample_idx=None,
hide_water=False,
Expand All @@ -59,7 +59,7 @@ def render(
if resample_idx is not None and resample_idx != 0:
resample_scene(int_hash((scene_seed, resample_idx)))
with Timer("Render Frames"):
render_image_func(frames_folder=Path(output_folder), camera_id=camera_id)
render_image_func(frames_folder=Path(output_folder), camera=camera)


def is_static(obj):
Expand Down Expand Up @@ -87,8 +87,9 @@ def is_static(obj):

@gin.configurable
def save_meshes(
scene_seed,
output_folder,
scene_seed: int,
output_folder: Path,
cameras: list[bpy.types.Object],
frame_range,
resample_idx=False,
point_trajectory_src_frame=1,
Expand All @@ -108,8 +109,9 @@ def save_meshes(
for obj in bpy.data.objects:
obj.hide_viewport = not (not obj.hide_render and is_static(obj))
frame_idx = point_trajectory_src_frame
frame_info_folder = Path(output_folder) / f"frame_{frame_idx:04d}"
frame_info_folder = output_folder / f"frame_{frame_idx:04d}"
frame_info_folder.mkdir(parents=True, exist_ok=True)

logger.info("Working on static objects")
exporting.save_obj_and_instances(
frame_info_folder / "static_mesh",
Expand All @@ -128,17 +130,17 @@ def save_meshes(
):
bpy.context.scene.frame_set(frame_idx)
bpy.context.view_layer.update()
frame_info_folder = Path(output_folder) / f"frame_{frame_idx:04d}"
frame_info_folder = output_folder / f"frame_{frame_idx:04d}"
frame_info_folder.mkdir(parents=True, exist_ok=True)
logger.info(f"Working on frame {frame_idx}")
logger.info(f"save_meshes processing {frame_idx=}")

exporting.save_obj_and_instances(
frame_info_folder / "mesh",
previous_frame_mesh_id_mapping,
current_frame_mesh_id_mapping,
)
cam_util.save_camera_parameters(
camera_ids=cam_util.get_cameras_ids(),
camera_ids=cameras,
output_folder=frame_info_folder / "cameras",
frame=frame_idx,
)
Expand Down Expand Up @@ -246,12 +248,15 @@ def execute_tasks(
with open(outpath / "info.pickle", "wb") as f:
pickle.dump(info, f, protocol=pickle.HIGHEST_PROTOCOL)

cam_util.set_active_camera(*camera_id)
camera_rigs = cam_util.get_camera_rigs()
camrig_id, subcam_id = camera_id
active_camera = camera_rigs[camrig_id].children[subcam_id]
cam_util.set_active_camera(active_camera)

group_collections()

if Task.Populate in task and populate_scene_func is not None:
populate_scene_func(output_folder, scene_seed)
populate_scene_func(output_folder, scene_seed, camera_rigs)

need_terrain_processing = "atmosphere" in bpy.data.objects

Expand All @@ -267,10 +272,9 @@ def execute_tasks(
whole_bbox=info["whole_bbox"],
)

cameras = [cam_util.get_camera(i, j) for i, j in cam_util.get_cameras_ids()]
terrain.fine_terrain(
output_folder,
cameras=cameras,
cameras=[c for rig in camera_rigs for c in rig.children],
optimize_terrain_diskusage=optimize_terrain_diskusage,
)

Expand Down Expand Up @@ -326,7 +330,7 @@ def execute_tasks(
render(
scene_seed,
output_folder=output_folder,
camera_id=camera_id,
camera=active_camera,
resample_idx=resample_idx,
)

Expand Down
137 changes: 55 additions & 82 deletions infinigen/core/placement/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@

logger = logging.getLogger(__name__)

CAMERA_RIGS_DIRNAME = "CameraRigs"


@gin.configurable
def get_sensor_coords(cam, H, W, sparse=False):
Expand Down Expand Up @@ -119,55 +117,54 @@ def spawn_camera():
return cam


def camera_name(rig_id, cam_id):
return f"{CAMERA_RIGS_DIRNAME}/{rig_id}/{cam_id}"
def cam_name(cam_rig, subcam):
return f"camera_{cam_rig}_{subcam}"


def get_id(camera: bpy.types.Object):
_, rig, subcam = camera.name.split("_")
return int(rig), int(subcam)


@gin.configurable
def spawn_camera_rigs(
camera_rig_config,
n_camera_rigs,
):
) -> list[bpy.types.Object]:
rigs_col = butil.get_collection("camera_rigs")
cams_col = butil.get_collection("cameras")

def spawn_rig(i):
rig_parent = butil.spawn_empty(f"{CAMERA_RIGS_DIRNAME}/{i}")
rig_parent = butil.spawn_empty(f"camrig.{i}")
butil.put_in_collection(rig_parent, rigs_col)

for j, config in enumerate(camera_rig_config):
cam = spawn_camera()
cam.name = camera_name(i, j)
cam.name = cam_name(i, j)
cam.parent = rig_parent

cam.location = config["loc"]
cam.rotation_euler = config["rot_euler"]

return rig_parent
butil.put_in_collection(cam, cams_col)

camera_rigs = [spawn_rig(i) for i in range(n_camera_rigs)]
butil.group_in_collection(camera_rigs, CAMERA_RIGS_DIRNAME)
return rig_parent

return camera_rigs
return [spawn_rig(i) for i in range(n_camera_rigs)]


def get_cameras_ids() -> list[tuple]:
res = []
col = bpy.data.collections[CAMERA_RIGS_DIRNAME]
rigs = [o for o in col.objects if o.name.count("/") == 1]
for i, root in enumerate(rigs):
for j, subcam in enumerate(root.children):
assert subcam.name == camera_name(i, j)
res.append((i, j))
def get_camera_rigs() -> list[bpy.types.Object]:
if "camera_rigs" not in bpy.data.collections:
raise ValueError("No camera rigs found")

return res
result = list(bpy.data.collections["camera_rigs"].objects)

for i, rig in enumerate(result):
for j, child in enumerate(rig.children):
expected = cam_name(i, j)
if child.name != expected:
raise ValueError(f"child {i=} {j} was {child.name=}, {expected=}")

def get_camera(rig_id, subcam_id, checkonly=False):
col = bpy.data.collections[CAMERA_RIGS_DIRNAME]
name = camera_name(rig_id, subcam_id)
if name in col.objects.keys():
return col.objects[name]
if checkonly:
return None
raise ValueError(
f"Could not get_camera({rig_id=}, {subcam_id=}). {list(col.objects.keys())=}"
)
return result


@node_utils.to_nodegroup(
Expand All @@ -181,8 +178,7 @@ def nodegroup_active_cam_info(nw: NodeWrangler):
)


def set_active_camera(rig_id, subcam_id):
camera = get_camera(rig_id, subcam_id)
def set_active_camera(camera: bpy.types.Object):
bpy.context.scene.camera = camera

ng = (
Expand All @@ -193,34 +189,6 @@ def set_active_camera(rig_id, subcam_id):
return bpy.context.scene.camera


def positive_gaussian(mean, std):
while True:
val = np.random.normal(mean, std)
if val > 0:
return val


def set_camera(
camera,
location,
rotation,
focus_dist,
frame,
):
camera.location = location
camera.rotation_euler = rotation
if focus_dist is not None:
camera.data.dof.focus_distance = (
focus_dist # this should come before view_layer.update()
)
bpy.context.view_layer.update()

camera.keyframe_insert(data_path="location", frame=frame)
camera.keyframe_insert(data_path="rotation_euler", frame=frame)
if focus_dist is not None:
camera.data.dof.keyframe_insert(data_path="focus_distance", frame=frame)


def terrain_camera_query(
cam, scene_bvh, terrain_tags_queries, vertexwise_min_dist, min_dist=0
):
Expand Down Expand Up @@ -465,7 +433,7 @@ def compute_base_views(
):
potential_views = []
n_min_candidates = int(min_candidates_ratio * n_views)
logger.debug("Center Coordinate", center_coordinate)

with tqdm(total=n_min_candidates, desc="Searching for camera viewpoints") as pbar:
for it in range(1, max_tries):
if center_coordinate:
Expand Down Expand Up @@ -798,32 +766,37 @@ def animate_cameras(


@gin.configurable
def save_camera_parameters(camera_ids, output_folder, frame, use_dof=False):
def save_camera_parameters(
camera_obj: bpy.types.Object, output_folder, frame, use_dof=False
):
output_folder = Path(output_folder)
output_folder.mkdir(exist_ok=True, parents=True)

if frame is not None:
bpy.context.scene.frame_set(frame)
for camera_pair_id, camera_id in camera_ids:
camera_obj = get_camera(camera_pair_id, camera_id)
if use_dof is not None:
camera_obj.data.dof.use_dof = use_dof
# Saving camera parameters
K = camera.get_calibration_matrix_K_from_blender(camera_obj.data)
suffix = get_suffix(
dict(cam_rig=camera_pair_id, resample=0, frame=frame, subcam=camera_id)
)
output_file = output_folder / f"camview{suffix}.npz"

height_width = np.array(
(
bpy.context.scene.render.resolution_y,
bpy.context.scene.render.resolution_x,
)
camrig_id, subcam_id = get_id(camera_obj)

if use_dof is not None:
camera_obj.data.dof.use_dof = use_dof

# Saving camera parameters
K = camera.get_calibration_matrix_K_from_blender(camera_obj.data)
suffix = get_suffix(
dict(cam_rig=camrig_id, resample=0, frame=frame, subcam=subcam_id)
)
output_file = output_folder / f"camview{suffix}.npz"

height_width = np.array(
(
bpy.context.scene.render.resolution_y,
bpy.context.scene.render.resolution_x,
)
T = np.asarray(camera_obj.matrix_world, dtype=np.float64) @ np.diag(
(1.0, -1.0, -1.0, 1.0)
) # Y down Z forward (aka opencv)
np.savez(output_file, K=np.asarray(K, dtype=np.float64), T=T, HW=height_width)
)
T = np.asarray(camera_obj.matrix_world, dtype=np.float64) @ np.diag(
(1.0, -1.0, -1.0, 1.0)
) # Y down Z forward (aka opencv)
np.savez(output_file, K=np.asarray(K, dtype=np.float64), T=T, HW=height_width)


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit f4710c4

Please sign in to comment.