Skip to content

Commit

Permalink
enable changing crop bbox
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesPerlman committed Jun 29, 2023
1 parent 6fa55fb commit eec46f8
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 24 deletions.
123 changes: 109 additions & 14 deletions panels/nerf_object_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
import math

from turbo_nerf.blender_utility.driver_utility import force_update_drivers
from turbo_nerf.blender_utility.obj_type_utility import get_active_nerf_obj, get_all_training_cam_objs, get_closest_parent_of_type, get_nerf_obj_type, get_nerf_training_cams, is_nerf_obj_type, is_self_or_some_parent_of_type

from turbo_nerf.blender_utility.obj_type_utility import (
get_active_nerf_obj,
get_all_training_cam_objs,
get_closest_parent_of_type,
get_nerf_training_cams,
is_nerf_obj_type,
is_self_or_some_parent_of_type
)

from turbo_nerf.constants import (
CAMERA_FAR_ID,
CAMERA_INDEX_ID,
Expand All @@ -13,10 +22,13 @@
OBJ_TYPE_NERF,
OBJ_TYPE_TRAIN_CAMERA
)
from turbo_nerf.utility.math import clamp
from turbo_nerf.utility.nerf_manager import NeRFManager
from turbo_nerf.utility.render_camera_utils import bl2nerf_cam_train

# general camera prop getter
# helper methods
# kinda dirty to put these in the global scope for this file

def get_props_for_cams(nerf_obj, prop_name, default_value):
cam_objs = get_nerf_training_cams(nerf_obj, bpy.context)

Expand All @@ -25,16 +37,13 @@ def get_props_for_cams(nerf_obj, prop_name, default_value):

return [o[prop_name] for o in cam_objs]

# kindof a hack for now, need to figure out if there is a cleaner way to do this
# i also don't like that it's just a global method in this file
def update_dataset_cams(nerf_obj):
nerf = NeRFManager.get_nerf_for_obj(nerf_obj)
# updates the dataset cameras for a nerf object
def set_props_for_cams(nerf_obj, nerf):
cam_objs = get_all_training_cam_objs(nerf_obj)

# todo: only update the cameras that have changed
nerf.dataset.cameras = [bl2nerf_cam_train(cam_obj, relative_to=nerf_obj) for cam_obj in cam_objs]
nerf.is_dataset_dirty = True


# Custom property group
class NeRFObjectProperties(bpy.types.PropertyGroup):
Expand Down Expand Up @@ -78,7 +87,7 @@ def set_near(self, value):
o[CAMERA_NEAR_ID] = value
force_update_drivers(o)

update_dataset_cams(nerf_obj)
set_props_for_cams(nerf_obj, NeRFManager.get_nerf_for_obj(nerf_obj))

near: bpy.props.FloatProperty(
name="Near Plane",
Expand All @@ -104,7 +113,7 @@ def set_far(self, value):
o[CAMERA_FAR_ID] = value
force_update_drivers(o)

update_dataset_cams(nerf_obj)
set_props_for_cams(nerf_obj, NeRFManager.get_nerf_for_obj(nerf_obj))

far: bpy.props.FloatProperty(
name="Far Plane",
Expand All @@ -125,12 +134,13 @@ def get_show_image_planes(prop_id):

def set_show_image_planes(self, value):
nerf_obj = get_active_nerf_obj(bpy.context)

cams = get_nerf_training_cams(nerf_obj, bpy.context)
for o in cams:
o[CAMERA_SHOW_IMAGE_PLANES_ID] = value
force_update_drivers(o)

update_dataset_cams(nerf_obj)
set_props_for_cams(nerf_obj, NeRFManager.get_nerf_for_obj(nerf_obj))

show_image_planes: bpy.props.BoolProperty(
name="Is Visible",
Expand All @@ -140,6 +150,84 @@ def set_show_image_planes(self, value):
set=set_show_image_planes,
)

# cropping (render bbox)

def get_crop(dim: str):
if dim not in ("x", "y", "z"):
raise ValueError(f"Invalid dimension {dim} for crop")

def crop_getter(prop_id):
nerf_obj = get_active_nerf_obj(bpy.context)
nerf = NeRFManager.get_nerf_for_obj(nerf_obj)
min_dim = getattr(nerf.render_bbox, f"min_{dim}")
max_dim = getattr(nerf.render_bbox, f"max_{dim}")
return (min_dim, max_dim)

return crop_getter

def set_crop(dim):
if dim not in ("x", "y", "z"):
raise ValueError(f"Invalid dimension {dim} for crop")

def crop_setter(self, value):
nerf_obj = get_active_nerf_obj(bpy.context)
nerf = NeRFManager.get_nerf_for_obj(nerf_obj)

tbbox_min = getattr(nerf.training_bbox, f"min_{dim}")
tbbox_max = getattr(nerf.training_bbox, f"max_{dim}")

rbbox_min = getattr(nerf.render_bbox, f"min_{dim}")
rbbox_max = getattr(nerf.render_bbox, f"max_{dim}")

new_min = clamp(value[0], tbbox_min, rbbox_max)
new_max = clamp(value[1], rbbox_min, tbbox_max)

new_bbox = nerf.render_bbox
setattr(new_bbox, f"min_{dim}", new_min)
setattr(new_bbox, f"max_{dim}", new_max)
nerf.render_bbox = new_bbox

force_update_drivers(nerf_obj)

return crop_setter

crop_x: bpy.props.FloatVectorProperty(
name="Crop X",
description="Crop X",
min=-128.0,
max=128.0,
size=2,
step=0.01,
precision=5,
get=get_crop("x"),
set=set_crop("x"),
)

crop_y: bpy.props.FloatVectorProperty(
name="Crop Y",
description="Crop Y",
min=-128.0,
max=128.0,
size=2,
step=0.01,
precision=5,
get=get_crop("y"),
set=set_crop("y"),
)

crop_z: bpy.props.FloatVectorProperty(
name="Crop Z",
description="Crop Z",
min=-128.0,
max=128.0,
size=2,
step=0.01,
precision=5,
get=get_crop("z"),
set=set_crop("z"),
)


# Custom panel for the dropdown
class NeRFObjectPanel(bpy.types.Panel):
bl_label = "TurboNeRF Properties"
Expand Down Expand Up @@ -197,12 +285,19 @@ def draw_camera_section(self, context, ui_props):
row = layout.row()
row.prop(ui_props, "show_image_planes")

# row = layout.row()
# row.prop(ui_props, "use_for_training")
# crop section

row = layout.row()
row.label(text="Crop")

row = layout.row()
row.prop(ui_props, "crop_x")

# row = layout.row()
# row.prop(ui_props, "focal_length")
row = layout.row()
row.prop(ui_props, "crop_y")

row = layout.row()
row.prop(ui_props, "crop_z")

# Register the custom property group and panel
@classmethod
Expand Down
1 change: 0 additions & 1 deletion panels/nerf_panel_operators/load_nerf_images_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from turbo_nerf.blender_utility.blender_ui_utility import switch_to_turbo_nerf_renderer
from turbo_nerf.blender_utility.obj_type_utility import get_active_nerf_obj
from turbo_nerf.constants import NERF_ITEM_IDENTIFIER_ID
from turbo_nerf.utility.nerf_manager import NeRFManager

class LoadNeRFImagesOperator(bpy.types.Operator):
Expand Down
12 changes: 4 additions & 8 deletions renderer/nerf_render_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def __init__(self):
self.cancel_current_render = False
self.current_region3d: bpy.types.RegionView3D = None
self.latest_camera = None
self.has_depsgraph_updates = True

self.prev_view_dims = (0, 0)

Expand Down Expand Up @@ -263,15 +262,13 @@ def view_update(self, context, depsgraph: bpy.types.Depsgraph):
if nerf_obj_type is None:
continue

# Base NeRF object
# Update the NeRF representation's transform on the CUDA side
if nerf_obj_type == OBJ_TYPE_NERF:
nerf_id = obj[NERF_ITEM_IDENTIFIER_ID]
nerf = NeRFManager.get_nerf_by_id(nerf_id)
# why do we need to multiply by NERF_ADJUSTMENT_MATRIX? idk, but it works.
mat = np.array(obj.matrix_world @ NERF_ADJUSTMENT_MATRIX)
nerf.transform = tn.Transform4f(mat).from_nerf()

self.has_depsgraph_updates = True

# For viewport renders, this method is called whenever Blender redraws
# the 3D viewport. The renderer is expected to quickly draw the render
Expand Down Expand Up @@ -309,12 +306,11 @@ def view_draw(self, context, depsgraph):

has_new_camera = True if self.latest_camera is None else camera != self.latest_camera
has_new_dims = dimensions != self.prev_view_dims
is_any_dataset_dirty = np.any([nerf.is_dataset_dirty and nerf.can_render for nerf in all_nerfs])
is_any_nerf_dirty = np.any([nerf.is_dirty() and nerf.can_render for nerf in all_nerfs])

user_initiated = has_new_camera or has_new_dims or is_any_dataset_dirty
user_initiated = has_new_camera or has_new_dims or is_any_nerf_dirty

if user_initiated or self.has_depsgraph_updates:
self.has_depsgraph_updates = False
if user_initiated:
flags = tn.RenderFlags.Preview
if not NeRFManager.is_training(): # and not context.screen.is_animation_playing:
flags = flags | tn.RenderFlags.Final
Expand Down
8 changes: 8 additions & 0 deletions utility/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ def bl2nerf_pos(
) -> np.array:
xyz_cycled = np.array([xyz[1], xyz[2], xyz[0]])
return scale * xyz_cycled + origin

def clamp(x, min, max):
if x < min:
return min
elif x > max:
return max
else:
return x
1 change: 0 additions & 1 deletion utility/nerf_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,3 @@ def getter(self):
return cls.get_bridge_object_property(obj_name, prop_name, default)

return getter

0 comments on commit eec46f8

Please sign in to comment.