Compare commits

..

2 Commits

Author SHA1 Message Date
hofee
7132ff83ce add normal material 2024-10-15 11:17:26 -05:00
hofee
5905669dbd format 2024-10-15 11:07:17 -05:00
2 changed files with 358 additions and 147 deletions

View File

@ -1,4 +1,3 @@
import os import os
import json import json
import bpy import bpy
@ -7,6 +6,7 @@ import gc
import numpy as np import numpy as np
import mathutils import mathutils
class BlenderUtils: class BlenderUtils:
TABLE_NAME: str = "table" TABLE_NAME: str = "table"
@ -19,7 +19,7 @@ class BlenderUtils:
@staticmethod @staticmethod
def get_obj_path(obj_dir, name): def get_obj_path(obj_dir, name):
return os.path.join(obj_dir, name, BlenderUtils.MESH_FILE_NAME) return os.path.join(obj_dir, name, BlenderUtils.MESH_FILE_NAME)
@staticmethod @staticmethod
def load_obj(name, mesh_path, scale=1): def load_obj(name, mesh_path, scale=1):
print(mesh_path) print(mesh_path)
@ -34,32 +34,31 @@ class BlenderUtils:
@staticmethod @staticmethod
def get_obj(name): def get_obj(name):
return bpy.data.objects.get(name) return bpy.data.objects.get(name)
@staticmethod @staticmethod
def get_obj_pose(name): def get_obj_pose(name):
obj = BlenderUtils.get_obj(name) obj = BlenderUtils.get_obj(name)
return np.asarray(obj.matrix_world) return np.asarray(obj.matrix_world)
@staticmethod @staticmethod
def add_plane(name, location, orientation, size=10): def add_plane(name, location, orientation, size=10):
bpy.ops.mesh.primitive_plane_add(size=size,location=location) bpy.ops.mesh.primitive_plane_add(size=size, location=location)
plane = bpy.context.selected_objects[-1] plane = bpy.context.selected_objects[-1]
plane.name = name plane.name = name
plane.rotation_euler = orientation plane.rotation_euler = orientation
bpy.ops.rigidbody.object_add() bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE' bpy.context.object.rigid_body.type = "PASSIVE"
@staticmethod @staticmethod
def add_table(table_model_path): def add_table(table_model_path):
table = BlenderUtils.load_obj(BlenderUtils.TABLE_NAME, table_model_path, scale=0.01) table = BlenderUtils.load_obj(
BlenderUtils.TABLE_NAME, table_model_path, scale=0.01
)
bpy.ops.rigidbody.object_add() bpy.ops.rigidbody.object_add()
bpy.context.object.rigid_body.type = 'PASSIVE' bpy.context.object.rigid_body.type = "PASSIVE"
mat = bpy.data.materials.new(name="TableYellowMaterial") mat = bpy.data.materials.new(name="TableYellowMaterial")
mat.diffuse_color = (1.0, 1.0, 0.0, 1.0) mat.diffuse_color = (1.0, 1.0, 0.0, 1.0)
if len(table.data.materials) > 0: if len(table.data.materials) > 0:
table.data.materials[0] = mat table.data.materials[0] = mat
else: else:
@ -67,107 +66,124 @@ class BlenderUtils:
@staticmethod @staticmethod
def setup_scene(init_light_and_camera_config, table_model_path, binocular_vision): def setup_scene(init_light_and_camera_config, table_model_path, binocular_vision):
bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT' bpy.context.scene.render.engine = "BLENDER_EEVEE_NEXT"
bpy.context.scene.display.shading.show_xray = False bpy.context.scene.display.shading.show_xray = False
bpy.context.scene.display.shading.use_dof = False bpy.context.scene.display.shading.use_dof = False
bpy.context.scene.display.render_aa = 'OFF' bpy.context.scene.display.render_aa = "OFF"
bpy.context.scene.view_settings.view_transform = 'Standard' bpy.context.scene.view_settings.view_transform = "Standard"
bpy.context.scene.eevee.use_ssr = False # 关闭屏幕空间反射 bpy.context.scene.eevee.use_ssr = False # 关闭屏幕空间反射
bpy.context.scene.eevee.use_bloom = False # 关闭辉光 bpy.context.scene.eevee.use_bloom = False # 关闭辉光
bpy.context.scene.eevee.use_gtao = False # 关闭环境光遮蔽 bpy.context.scene.eevee.use_gtao = False # 关闭环境光遮蔽
bpy.context.scene.eevee.use_soft_shadows = False # 关闭软阴影 bpy.context.scene.eevee.use_soft_shadows = False # 关闭软阴影
bpy.context.scene.eevee.use_shadows = False # 关闭所有阴影 bpy.context.scene.eevee.use_shadows = False # 关闭所有阴影
bpy.context.scene.world.use_nodes = False # 如果你不需要环境光,关闭环境节点 bpy.context.scene.world.use_nodes = False # 如果你不需要环境光,关闭环境节点
# bpy.context.scene.eevee.use_sss = False # 关闭次表面散射
#bpy.context.scene.eevee.use_sss = False # 关闭次表面散射
# 2. 设置最低的采样数 # 2. 设置最低的采样数
bpy.context.scene.eevee.taa_render_samples = 1 bpy.context.scene.eevee.taa_render_samples = 1
bpy.context.scene.eevee.taa_samples = 1 bpy.context.scene.eevee.taa_samples = 1
BlenderUtils.init_light_and_camera(init_light_and_camera_config, binocular_vision) BlenderUtils.init_light_and_camera(
init_light_and_camera_config, binocular_vision
BlenderUtils.add_plane("plane_floor", location=(0,0,0), orientation=(0,0,0)) )
BlenderUtils.add_plane("plane_ceil", location=(0,0,10), orientation=(0,0,0))
BlenderUtils.add_plane("plane_wall_1", location=(5,0,5), orientation=(0,np.pi/2,0)) BlenderUtils.add_plane("plane_floor", location=(0, 0, 0), orientation=(0, 0, 0))
BlenderUtils.add_plane("plane_wall_2", location=(-5,0,5), orientation=(0,np.pi/2,0)) BlenderUtils.add_plane("plane_ceil", location=(0, 0, 10), orientation=(0, 0, 0))
BlenderUtils.add_plane("plane_wall_3", location=(0,5,5), orientation=(np.pi/2,0,0)) BlenderUtils.add_plane(
BlenderUtils.add_plane("plane_wall_4", location=(0,-5,5), orientation=(np.pi/2,0,0)) "plane_wall_1", location=(5, 0, 5), orientation=(0, np.pi / 2, 0)
)
BlenderUtils.add_plane(
"plane_wall_2", location=(-5, 0, 5), orientation=(0, np.pi / 2, 0)
)
BlenderUtils.add_plane(
"plane_wall_3", location=(0, 5, 5), orientation=(np.pi / 2, 0, 0)
)
BlenderUtils.add_plane(
"plane_wall_4", location=(0, -5, 5), orientation=(np.pi / 2, 0, 0)
)
BlenderUtils.add_table(table_model_path) BlenderUtils.add_table(table_model_path)
@staticmethod @staticmethod
def set_light_params(light, config): def set_light_params(light, config):
light.location = config["location"] light.location = config["location"]
light.rotation_euler = config["orientation"] light.rotation_euler = config["orientation"]
if light.type == 'SUN': if light.type == "SUN":
light.data.energy = config["power"] light.data.energy = config["power"]
elif light.type == 'POINT': elif light.type == "POINT":
light.data.energy = config["power"] light.data.energy = config["power"]
@staticmethod @staticmethod
def set_camera_params(camera, config, binocular_vision): def set_camera_params(camera, config, binocular_vision):
camera_object = bpy.data.objects.new(BlenderUtils.CAMERA_OBJECT_NAME, None) camera_object = bpy.data.objects.new(BlenderUtils.CAMERA_OBJECT_NAME, None)
bpy.context.collection.objects.link(camera_object) bpy.context.collection.objects.link(camera_object)
cameras = [bpy.data.objects.get("Camera")] cameras = [bpy.data.objects.get("Camera")]
camera.location = [0,0,0] camera.location = [0, 0, 0]
camera.rotation_euler = [0,0,0] camera.rotation_euler = [0, 0, 0]
camera.parent = camera_object camera.parent = camera_object
if binocular_vision: if binocular_vision:
left_camera = cameras[0] left_camera = cameras[0]
right_camera = left_camera.copy() right_camera = left_camera.copy()
right_camera.name = BlenderUtils.CAMERA_RIGHT_NAME right_camera.name = BlenderUtils.CAMERA_RIGHT_NAME
right_camera.data = left_camera.data.copy() right_camera.data = left_camera.data.copy()
right_camera.data.name = BlenderUtils.CAMERA_RIGHT_NAME right_camera.data.name = BlenderUtils.CAMERA_RIGHT_NAME
bpy.context.collection.objects.link(right_camera) bpy.context.collection.objects.link(right_camera)
right_camera.parent = camera_object right_camera.parent = camera_object
right_camera.location = [config["eye_distance"]/2, 0, 0] right_camera.location = [config["eye_distance"] / 2, 0, 0]
left_camera.location = [-config["eye_distance"]/2, 0, 0] left_camera.location = [-config["eye_distance"] / 2, 0, 0]
binocular_angle = config["eye_angle"] binocular_angle = config["eye_angle"]
half_angle = np.radians(binocular_angle / 2) half_angle = np.radians(binocular_angle / 2)
left_camera.rotation_euler[1] = -half_angle left_camera.rotation_euler[1] = -half_angle
right_camera.rotation_euler[1] = half_angle right_camera.rotation_euler[1] = half_angle
cameras.append(right_camera) cameras.append(right_camera)
for camera in cameras: for camera in cameras:
camera.data.clip_start = config["near_plane"] camera.data.clip_start = config["near_plane"]
camera.data.clip_end = config["far_plane"] camera.data.clip_end = config["far_plane"]
bpy.context.scene.render.resolution_x = config["resolution"][0] bpy.context.scene.render.resolution_x = config["resolution"][0]
bpy.context.scene.render.resolution_y = config["resolution"][1] bpy.context.scene.render.resolution_y = config["resolution"][1]
sensor_height = 24.0 sensor_height = 24.0
focal_length = sensor_height / (2 * np.tan(np.radians(config["fov_vertical"]) / 2)) focal_length = sensor_height / (
2 * np.tan(np.radians(config["fov_vertical"]) / 2)
)
camera.data.lens = focal_length camera.data.lens = focal_length
camera.data.sensor_width = sensor_height * config["resolution"][0] / config["resolution"][1] camera.data.sensor_width = (
sensor_height * config["resolution"][0] / config["resolution"][1]
)
camera.data.sensor_height = sensor_height camera.data.sensor_height = sensor_height
@staticmethod @staticmethod
def init_light_and_camera(init_light_and_camera_config, binocular_vision): def init_light_and_camera(init_light_and_camera_config, binocular_vision):
camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_NAME) camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_NAME)
BlenderUtils.set_camera_params(camera, init_light_and_camera_config[BlenderUtils.CAMERA_NAME], binocular_vision) BlenderUtils.set_camera_params(
camera,
init_light_and_camera_config[BlenderUtils.CAMERA_NAME],
binocular_vision,
)
@staticmethod @staticmethod
def get_obj_diag(name): def get_obj_diag(name):
obj = BlenderUtils.get_obj(name) obj = BlenderUtils.get_obj(name)
return np.linalg.norm(obj.dimensions) return np.linalg.norm(obj.dimensions)
@staticmethod @staticmethod
def matrix_to_blender_pose(matrix): def matrix_to_blender_pose(matrix):
location = matrix[:3, 3] location = matrix[:3, 3]
rotation_matrix = matrix[:3, :3] rotation_matrix = matrix[:3, :3]
rotation_matrix_blender = mathutils.Matrix(rotation_matrix.tolist()) rotation_matrix_blender = mathutils.Matrix(rotation_matrix.tolist())
rotation_euler = rotation_matrix_blender.to_euler() rotation_euler = rotation_matrix_blender.to_euler()
return location, rotation_euler return location, rotation_euler
@staticmethod @staticmethod
def set_camera_at(pose): def set_camera_at(pose):
camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_OBJECT_NAME) camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_OBJECT_NAME)
location, rotation_euler = BlenderUtils.matrix_to_blender_pose(pose) location, rotation_euler = BlenderUtils.matrix_to_blender_pose(pose)
camera.location = location camera.location = location
camera.rotation_euler = rotation_euler camera.rotation_euler = rotation_euler
@ -177,27 +193,59 @@ class BlenderUtils:
vertices_world = [obj.matrix_world @ v for v in vertices] vertices_world = [obj.matrix_world @ v for v in vertices]
min_z = min([v.z for v in vertices_world]) min_z = min([v.z for v in vertices_world])
return min_z return min_z
@staticmethod
def render_normal(
output_dir, file_name, binocular_vision=False, target_object=None
):
target_cameras = [BlenderUtils.CAMERA_NAME]
if binocular_vision:
target_cameras.append(BlenderUtils.CAMERA_RIGHT_NAME)
for cam_name in target_cameras:
bpy.context.scene.camera = BlenderUtils.get_obj(cam_name)
cam_suffix = "L" if cam_name == BlenderUtils.CAMERA_NAME else "R"
scene = bpy.context.scene
scene.render.filepath = ""
mask_dir = os.path.join(output_dir, "normal")
if not os.path.exists(mask_dir):
os.makedirs(mask_dir)
scene.render.filepath = os.path.join(
output_dir, mask_dir, f"{file_name}_{cam_suffix}.png"
)
scene.render.image_settings.color_depth = "8"
scene.render.resolution_percentage = 100
scene.render.use_overwrite = False
scene.render.use_file_extension = False
scene.render.use_placeholder = False
bpy.ops.render.render(write_still=True)
msg = "success"
return msg
@staticmethod @staticmethod
def render_and_save(output_dir, file_name, binocular_vision=False, target_object=None): def render_mask_and_depth(
output_dir, file_name, binocular_vision=False, target_object=None
):
target_cameras = [BlenderUtils.CAMERA_NAME] target_cameras = [BlenderUtils.CAMERA_NAME]
if binocular_vision: if binocular_vision:
target_cameras.append(BlenderUtils.CAMERA_RIGHT_NAME) target_cameras.append(BlenderUtils.CAMERA_RIGHT_NAME)
for cam_name in target_cameras: for cam_name in target_cameras:
bpy.context.scene.camera = BlenderUtils.get_obj(cam_name) bpy.context.scene.camera = BlenderUtils.get_obj(cam_name)
bpy.context.scene.view_layers["ViewLayer"].use_pass_z = True
bpy.context.scene.view_layers["ViewLayer"].use_pass_normal = True
cam_suffix = "L" if cam_name == BlenderUtils.CAMERA_NAME else "R" cam_suffix = "L" if cam_name == BlenderUtils.CAMERA_NAME else "R"
scene = bpy.context.scene scene = bpy.context.scene
scene.render.filepath = "" scene.render.filepath = ""
mask_dir = os.path.join(output_dir, "mask") mask_dir = os.path.join(output_dir, "mask")
if not os.path.exists(mask_dir): if not os.path.exists(mask_dir):
os.makedirs(mask_dir) os.makedirs(mask_dir)
scene.render.filepath = os.path.join(output_dir, mask_dir, f"{file_name}_{cam_suffix}.png") scene.render.filepath = os.path.join(
scene.render.image_settings.color_depth = '8' output_dir, mask_dir, f"{file_name}_{cam_suffix}.png"
)
scene.render.image_settings.color_depth = "8"
scene.render.resolution_percentage = 100 scene.render.resolution_percentage = 100
scene.render.use_overwrite = False scene.render.use_overwrite = False
scene.render.use_file_extension = False scene.render.use_file_extension = False
@ -209,91 +257,47 @@ class BlenderUtils:
for node in tree.nodes: for node in tree.nodes:
tree.nodes.remove(node) tree.nodes.remove(node)
rl = tree.nodes.new('CompositorNodeRLayers') rl = tree.nodes.new("CompositorNodeRLayers")
map_range = tree.nodes.new('CompositorNodeMapRange') map_range = tree.nodes.new("CompositorNodeMapRange")
map_range.inputs['From Min'].default_value = 0.01 map_range.inputs["From Min"].default_value = 0.01
map_range.inputs['From Max'].default_value = 5 map_range.inputs["From Max"].default_value = 5
map_range.inputs['To Min'].default_value = 0 map_range.inputs["To Min"].default_value = 0
map_range.inputs['To Max'].default_value = 1 map_range.inputs["To Max"].default_value = 1
tree.links.new(rl.outputs['Depth'], map_range.inputs[0]) tree.links.new(rl.outputs["Depth"], map_range.inputs[0])
output_depth = tree.nodes.new('CompositorNodeOutputFile') output_depth = tree.nodes.new("CompositorNodeOutputFile")
depth_dir = os.path.join(output_dir, "depth") depth_dir = os.path.join(output_dir, "depth")
if not os.path.exists(depth_dir): if not os.path.exists(depth_dir):
os.makedirs(depth_dir) os.makedirs(depth_dir)
output_depth.base_path = depth_dir output_depth.base_path = depth_dir
output_depth.file_slots[0].path = f"{file_name}_{cam_suffix}.####" output_depth.file_slots[0].path = f"{file_name}_{cam_suffix}.####"
output_depth.format.file_format = 'PNG' output_depth.format.file_format = "PNG"
output_depth.format.color_mode = 'BW' output_depth.format.color_mode = "BW"
output_depth.format.color_depth = '16' output_depth.format.color_depth = "16"
# 创建 Separate XYZ 节点来分离法线的 X, Y, Z 分量
separate_xyz = tree.nodes.new('CompositorNodeSeparateXYZ')
# 将法线向量连接到 Separate XYZ 节点
tree.links.new(rl.outputs['Normal'], separate_xyz.inputs[0])
# 创建 Map Range 节点来分别映射 X, Y, Z 分量
map_range_x = tree.nodes.new('CompositorNodeMapRange')
map_range_y = tree.nodes.new('CompositorNodeMapRange')
map_range_z = tree.nodes.new('CompositorNodeMapRange')
# 设置映射范围
for map_range in [map_range_x, map_range_y, map_range_z]:
map_range.inputs['From Min'].default_value = -1
map_range.inputs['From Max'].default_value = 1
map_range.inputs['To Min'].default_value = 0
map_range.inputs['To Max'].default_value = 1
# 分别连接到法线的 X, Y, Z 输出
tree.links.new(separate_xyz.outputs['X'], map_range_x.inputs[0])
tree.links.new(separate_xyz.outputs['Y'], map_range_y.inputs[0])
tree.links.new(separate_xyz.outputs['Z'], map_range_z.inputs[0])
# 合并 X, Y, Z 分量到一个 RGB 输出
combine_rgb = tree.nodes.new('CompositorNodeCombineXYZ')
tree.links.new(map_range_x.outputs[0], combine_rgb.inputs['X'])
tree.links.new(map_range_y.outputs[0], combine_rgb.inputs['Y'])
tree.links.new(map_range_z.outputs[0], combine_rgb.inputs['Z'])
# 输出到文件
output_normal = tree.nodes.new('CompositorNodeOutputFile')
normal_dir = os.path.join(output_dir, "normal")
if not os.path.exists(normal_dir):
os.makedirs(normal_dir)
output_normal.base_path = normal_dir
output_normal.file_slots[0].path = f"{file_name}_{cam_suffix}.####"
output_normal.format.file_format = 'PNG'
output_normal.format.color_mode = 'RGB'
output_normal.format.color_depth = '8'
tree.links.new(combine_rgb.outputs[0], output_normal.inputs[0])
bpy.ops.render.render(write_still=True) bpy.ops.render.render(write_still=True)
msg = "success" msg = "success"
return msg return msg
@staticmethod @staticmethod
def save_cam_params(scene_dir, idx, binocular_vision=False): def save_cam_params(scene_dir, idx, binocular_vision=False):
camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_NAME) camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_NAME)
extrinsic = np.array(camera.matrix_world) extrinsic = np.array(camera.matrix_world)
cam_data = camera.data cam_data = camera.data
focal_length = cam_data.lens focal_length = cam_data.lens
sensor_width = cam_data.sensor_width sensor_width = cam_data.sensor_width
sensor_height = cam_data.sensor_height sensor_height = cam_data.sensor_height
resolution_x = bpy.context.scene.render.resolution_x resolution_x = bpy.context.scene.render.resolution_x
resolution_y = bpy.context.scene.render.resolution_y resolution_y = bpy.context.scene.render.resolution_y
intrinsic = np.zeros((3, 3)) intrinsic = np.zeros((3, 3))
intrinsic[0, 0] = focal_length * resolution_x / sensor_width # fx intrinsic[0, 0] = focal_length * resolution_x / sensor_width # fx
intrinsic[1, 1] = focal_length * resolution_y / sensor_height # fy intrinsic[1, 1] = focal_length * resolution_y / sensor_height # fy
intrinsic[0, 2] = resolution_x / 2.0 # cx intrinsic[0, 2] = resolution_x / 2.0 # cx
intrinsic[1, 2] = resolution_y / 2.0 # cy intrinsic[1, 2] = resolution_y / 2.0 # cy
intrinsic[2, 2] = 1.0 intrinsic[2, 2] = 1.0
cam_object = BlenderUtils.get_obj(BlenderUtils.CAMERA_OBJECT_NAME) cam_object = BlenderUtils.get_obj(BlenderUtils.CAMERA_OBJECT_NAME)
extrinsic_cam_object = np.array(cam_object.matrix_world) extrinsic_cam_object = np.array(cam_object.matrix_world)
data = { data = {
"extrinsic": extrinsic.tolist(), "extrinsic": extrinsic.tolist(),
@ -305,21 +309,28 @@ class BlenderUtils:
if binocular_vision: if binocular_vision:
right_camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_RIGHT_NAME) right_camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_RIGHT_NAME)
extrinsic_right = np.array(right_camera.matrix_world) extrinsic_right = np.array(right_camera.matrix_world)
print("result:",extrinsic_right) print("result:", extrinsic_right)
data["extrinsic_R"] = extrinsic_right.tolist() data["extrinsic_R"] = extrinsic_right.tolist()
cam_params_dir = os.path.join(scene_dir, "camera_params") cam_params_dir = os.path.join(scene_dir, "camera_params")
if not os.path.exists(cam_params_dir): if not os.path.exists(cam_params_dir):
os.makedirs(cam_params_dir) os.makedirs(cam_params_dir)
cam_params_path = os.path.join(cam_params_dir, f"{idx}.json") cam_params_path = os.path.join(cam_params_dir, f"{idx}.json")
with open(cam_params_path, "w") as f: with open(cam_params_path, "w") as f:
json.dump(data, f, indent=4) json.dump(data, f, indent=4)
@staticmethod @staticmethod
def reset_objects_and_platform(): def reset_objects_and_platform():
all_objects = bpy.data.objects all_objects = bpy.data.objects
keep_objects = {"plane_floor", "plane_ceil", "plane_wall_1", "plane_wall_2", "plane_wall_3", "plane_wall_4"} keep_objects = {
"plane_floor",
"plane_ceil",
"plane_wall_1",
"plane_wall_2",
"plane_wall_3",
"plane_wall_4",
}
keep_objects.add(BlenderUtils.CAMERA_OBJECT_NAME) keep_objects.add(BlenderUtils.CAMERA_OBJECT_NAME)
keep_objects.add(BlenderUtils.CAMERA_NAME) keep_objects.add(BlenderUtils.CAMERA_NAME)
keep_objects.add(BlenderUtils.CAMERA_RIGHT_NAME) keep_objects.add(BlenderUtils.CAMERA_RIGHT_NAME)
@ -345,18 +356,28 @@ class BlenderUtils:
@staticmethod @staticmethod
def save_scene_info(scene_root_dir, display_table_config, target_name): def save_scene_info(scene_root_dir, display_table_config, target_name):
all_objects = bpy.data.objects all_objects = bpy.data.objects
no_save_objects = {"plane_floor", "plane_ceil", "plane_wall_1", "plane_wall_2", "plane_wall_3", "plane_wall_4"} no_save_objects = {
"plane_floor",
"plane_ceil",
"plane_wall_1",
"plane_wall_2",
"plane_wall_3",
"plane_wall_4",
}
no_save_objects.add(BlenderUtils.CAMERA_OBJECT_NAME) no_save_objects.add(BlenderUtils.CAMERA_OBJECT_NAME)
no_save_objects.add(BlenderUtils.CAMERA_NAME) no_save_objects.add(BlenderUtils.CAMERA_NAME)
no_save_objects.add(BlenderUtils.CAMERA_RIGHT_NAME) no_save_objects.add(BlenderUtils.CAMERA_RIGHT_NAME)
no_save_objects.add(BlenderUtils.TABLE_NAME) no_save_objects.add(BlenderUtils.TABLE_NAME)
scene_info = {} scene_info = {}
for obj in all_objects: for obj in all_objects:
if obj.name not in no_save_objects and obj.name != BlenderUtils.DISPLAY_TABLE_NAME: if (
obj.name not in no_save_objects
and obj.name != BlenderUtils.DISPLAY_TABLE_NAME
):
obj_info = { obj_info = {
"location": list(obj.location), "location": list(obj.location),
"rotation_euler": list(obj.rotation_euler), "rotation_euler": list(obj.rotation_euler),
"scale": list(obj.scale) "scale": list(obj.scale),
} }
scene_info[obj.name] = obj_info scene_info[obj.name] = obj_info
scene_info[BlenderUtils.DISPLAY_TABLE_NAME] = display_table_config scene_info[BlenderUtils.DISPLAY_TABLE_NAME] = display_table_config
@ -364,6 +385,3 @@ class BlenderUtils:
scene_info_path = os.path.join(scene_root_dir, "scene_info.json") scene_info_path = os.path.join(scene_root_dir, "scene_info.json")
with open(scene_info_path, "w") as outfile: with open(scene_info_path, "w") as outfile:
json.dump(scene_info, outfile) json.dump(scene_info, outfile)

View File

@ -243,7 +243,7 @@ class DataGenerator:
np.savetxt(os.path.join(scene_dir, "points_and_normals.txt"), points_normals) np.savetxt(os.path.join(scene_dir, "points_and_normals.txt"), points_normals)
for i, cam_pose in enumerate(view_data["cam_poses"]): for i, cam_pose in enumerate(view_data["cam_poses"]):
BlenderUtils.set_camera_at(cam_pose) BlenderUtils.set_camera_at(cam_pose)
BlenderUtils.render_and_save(scene_dir, f"{i}", binocular_vision=self.binocular_vision, target_object = self.target_obj) BlenderUtils.render_mask_and_depth(scene_dir, f"{i}", binocular_vision=self.binocular_vision, target_object = self.target_obj)
BlenderUtils.save_cam_params(scene_dir, i, binocular_vision=self.binocular_vision) BlenderUtils.save_cam_params(scene_dir, i, binocular_vision=self.binocular_vision)
self.set_progress("render frame", i, len(view_data["cam_poses"])) self.set_progress("render frame", i, len(view_data["cam_poses"]))
self.set_progress("render frame", len(view_data["cam_poses"]), len(view_data["cam_poses"])) self.set_progress("render frame", len(view_data["cam_poses"]), len(view_data["cam_poses"]))
@ -255,15 +255,208 @@ class DataGenerator:
file_path = os.path.join(depth_dir, depth_file) file_path = os.path.join(depth_dir, depth_file)
new_file_path = os.path.join(depth_dir, f"{name}.png") new_file_path = os.path.join(depth_dir, f"{name}.png")
os.rename(file_path,new_file_path) os.rename(file_path,new_file_path)
normal_dir = os.path.join(scene_dir, "normal")
for normal_file in os.listdir(normal_dir): self.change_target_obj_material_to_normal()
if not normal_file.endswith(".png"): for i, cam_pose in enumerate(view_data["cam_poses"]):
name, _ = os.path.splitext(normal_file) BlenderUtils.set_camera_at(cam_pose)
file_path = os.path.join(normal_dir, normal_file) BlenderUtils.render_normal(scene_dir, f"{i}", binocular_vision=self.binocular_vision, target_object = self.target_obj)
new_file_path = os.path.join(normal_dir, f"{name}.png") BlenderUtils.save_cam_params(scene_dir, i, binocular_vision=self.binocular_vision)
os.rename(file_path,new_file_path) self.set_progress("render normal frame", i, len(view_data["cam_poses"]))
self.set_progress("render normal frame", len(view_data["cam_poses"]), len(view_data["cam_poses"]))
return True return True
def change_target_obj_material_to_normal(self):
material_name = "normal"
mat = bpy.data.materials.get(material_name) or bpy.data.materials.new(
material_name
)
mat.use_nodes = True
node_tree = mat.node_tree
nodes = node_tree.nodes
nodes.clear()
links = node_tree.links
links.clear()
# Nodes:
new_node = nodes.new(type="ShaderNodeMath")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (151.59744262695312, 854.5482177734375)
new_node.name = "Math"
new_node.operation = "MULTIPLY"
new_node.select = False
new_node.use_clamp = False
new_node.width = 140.0
new_node.inputs[0].default_value = 0.5
new_node.inputs[1].default_value = 1.0
new_node.inputs[2].default_value = 0.0
new_node.outputs[0].default_value = 0.0
new_node = nodes.new(type="ShaderNodeLightPath")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (602.9912719726562, 1046.660888671875)
new_node.name = "Light Path"
new_node.select = False
new_node.width = 140.0
new_node.outputs[0].default_value = 0.0
new_node.outputs[1].default_value = 0.0
new_node.outputs[2].default_value = 0.0
new_node.outputs[3].default_value = 0.0
new_node.outputs[4].default_value = 0.0
new_node.outputs[5].default_value = 0.0
new_node.outputs[6].default_value = 0.0
new_node.outputs[7].default_value = 0.0
new_node.outputs[8].default_value = 0.0
new_node.outputs[9].default_value = 0.0
new_node.outputs[10].default_value = 0.0
new_node.outputs[11].default_value = 0.0
new_node.outputs[12].default_value = 0.0
new_node = nodes.new(type="ShaderNodeOutputMaterial")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.is_active_output = True
new_node.location = (1168.93017578125, 701.84033203125)
new_node.name = "Material Output"
new_node.select = False
new_node.target = "ALL"
new_node.width = 140.0
new_node.inputs[2].default_value = [0.0, 0.0, 0.0]
new_node = nodes.new(type="ShaderNodeBsdfTransparent")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (731.72900390625, 721.4832763671875)
new_node.name = "Transparent BSDF"
new_node.select = False
new_node.width = 140.0
new_node.inputs[0].default_value = [1.0, 1.0, 1.0, 1.0]
new_node = nodes.new(type="ShaderNodeCombineXYZ")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (594.4229736328125, 602.9271240234375)
new_node.name = "Combine XYZ"
new_node.select = False
new_node.width = 140.0
new_node.inputs[0].default_value = 0.0
new_node.inputs[1].default_value = 0.0
new_node.inputs[2].default_value = 0.0
new_node.outputs[0].default_value = [0.0, 0.0, 0.0]
new_node = nodes.new(type="ShaderNodeMixShader")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (992.7239990234375, 707.2142333984375)
new_node.name = "Mix Shader"
new_node.select = False
new_node.width = 140.0
new_node.inputs[0].default_value = 0.5
new_node = nodes.new(type="ShaderNodeEmission")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (774.0802612304688, 608.2547607421875)
new_node.name = "Emission"
new_node.select = False
new_node.width = 140.0
new_node.inputs[0].default_value = [1.0, 1.0, 1.0, 1.0]
new_node.inputs[1].default_value = 1.0
new_node = nodes.new(type="ShaderNodeSeparateXYZ")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (-130.12167358398438, 558.1497802734375)
new_node.name = "Separate XYZ"
new_node.select = False
new_node.width = 140.0
new_node.inputs[0].default_value = [0.0, 0.0, 0.0]
new_node.outputs[0].default_value = 0.0
new_node.outputs[1].default_value = 0.0
new_node.outputs[2].default_value = 0.0
new_node = nodes.new(type="ShaderNodeMath")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (162.43240356445312, 618.8094482421875)
new_node.name = "Math.002"
new_node.operation = "MULTIPLY"
new_node.select = False
new_node.use_clamp = False
new_node.width = 140.0
new_node.inputs[0].default_value = 0.5
new_node.inputs[1].default_value = 1.0
new_node.inputs[2].default_value = 0.0
new_node.outputs[0].default_value = 0.0
new_node = nodes.new(type="ShaderNodeMath")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (126.8158187866211, 364.5539855957031)
new_node.name = "Math.001"
new_node.operation = "MULTIPLY"
new_node.select = False
new_node.use_clamp = False
new_node.width = 140.0
new_node.inputs[0].default_value = 0.5
new_node.inputs[1].default_value = -1.0
new_node.inputs[2].default_value = 0.0
new_node.outputs[0].default_value = 0.0
new_node = nodes.new(type="ShaderNodeVectorTransform")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.convert_from = "WORLD"
new_node.convert_to = "CAMERA"
new_node.location = (-397.0209045410156, 594.7037353515625)
new_node.name = "Vector Transform"
new_node.select = False
new_node.vector_type = "VECTOR"
new_node.width = 140.0
new_node.inputs[0].default_value = [0.5, 0.5, 0.5]
new_node.outputs[0].default_value = [0.0, 0.0, 0.0]
new_node = nodes.new(type="ShaderNodeNewGeometry")
# new_node.active_preview = False
new_node.color = (0.6079999804496765, 0.6079999804496765, 0.6079999804496765)
new_node.location = (-651.8067016601562, 593.0455932617188)
new_node.name = "Geometry"
new_node.width = 140.0
new_node.outputs[0].default_value = [0.0, 0.0, 0.0]
new_node.outputs[1].default_value = [0.0, 0.0, 0.0]
new_node.outputs[2].default_value = [0.0, 0.0, 0.0]
new_node.outputs[3].default_value = [0.0, 0.0, 0.0]
new_node.outputs[4].default_value = [0.0, 0.0, 0.0]
new_node.outputs[5].default_value = [0.0, 0.0, 0.0]
new_node.outputs[6].default_value = 0.0
new_node.outputs[7].default_value = 0.0
new_node.outputs[8].default_value = 0.0
# Links :
links.new(nodes["Light Path"].outputs[0], nodes["Mix Shader"].inputs[0])
links.new(nodes["Separate XYZ"].outputs[0], nodes["Math"].inputs[0])
links.new(nodes["Separate XYZ"].outputs[1], nodes["Math.002"].inputs[0])
links.new(nodes["Separate XYZ"].outputs[2], nodes["Math.001"].inputs[0])
links.new(nodes["Vector Transform"].outputs[0], nodes["Separate XYZ"].inputs[0])
links.new(nodes["Combine XYZ"].outputs[0], nodes["Emission"].inputs[0])
links.new(nodes["Math"].outputs[0], nodes["Combine XYZ"].inputs[0])
links.new(nodes["Math.002"].outputs[0], nodes["Combine XYZ"].inputs[1])
links.new(nodes["Math.001"].outputs[0], nodes["Combine XYZ"].inputs[2])
links.new(nodes["Transparent BSDF"].outputs[0], nodes["Mix Shader"].inputs[1])
links.new(nodes["Emission"].outputs[0], nodes["Mix Shader"].inputs[2])
links.new(nodes["Mix Shader"].outputs[0], nodes["Material Output"].inputs[0])
links.new(nodes["Geometry"].outputs[1], nodes["Vector Transform"].inputs[0])
self.target_obj.data.materials.clear()
self.target_obj.data.materials.append(mat)
def simulate_scene(self, frame_limit=120, depth = 0, diag = 0): def simulate_scene(self, frame_limit=120, depth = 0, diag = 0):
bpy.context.view_layer.update() bpy.context.view_layer.update()
bpy.ops.screen.animation_play() bpy.ops.screen.animation_play()