diff --git a/blender_util.py b/blender_util.py index 9ce4faf..c00691f 100644 --- a/blender_util.py +++ b/blender_util.py @@ -13,7 +13,6 @@ class BlenderUtils: CAMERA_NAME: str = "Camera" CAMERA_RIGHT_NAME: str = "CameraRight" CAMERA_OBJECT_NAME: str = "CameraObject" - LIGHT_NAME: str = "Light" DISPLAY_TABLE_NAME: str = "display_table" MESH_FILE_NAME: str = "mesh.obj" @@ -68,11 +67,25 @@ class BlenderUtils: @staticmethod def setup_scene(init_light_and_camera_config, table_model_path, binocular_vision): - bpy.context.scene.render.engine = 'BLENDER_WORKBENCH' + bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT' bpy.context.scene.display.shading.show_xray = False bpy.context.scene.display.shading.use_dof = False bpy.context.scene.display.render_aa = 'OFF' bpy.context.scene.view_settings.view_transform = 'Standard' + + bpy.context.scene.eevee.use_ssr = False # 关闭屏幕空间反射 + bpy.context.scene.eevee.use_bloom = False # 关闭辉光 + bpy.context.scene.eevee.use_gtao = False # 关闭环境光遮蔽 + bpy.context.scene.eevee.use_soft_shadows = False # 关闭软阴影 + bpy.context.scene.eevee.use_shadows = False # 关闭所有阴影 + bpy.context.scene.world.use_nodes = False # 如果你不需要环境光,关闭环境节点 + + + #bpy.context.scene.eevee.use_sss = False # 关闭次表面散射 + + # 2. 设置最低的采样数 + bpy.context.scene.eevee.taa_render_samples = 1 + bpy.context.scene.eevee.taa_samples = 1 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)) @@ -135,9 +148,7 @@ class BlenderUtils: def init_light_and_camera(init_light_and_camera_config, binocular_vision): camera = BlenderUtils.get_obj(BlenderUtils.CAMERA_NAME) - light = BlenderUtils.get_obj(BlenderUtils.LIGHT_NAME) BlenderUtils.set_camera_params(camera, init_light_and_camera_config[BlenderUtils.CAMERA_NAME], binocular_vision) - BlenderUtils.set_light_params(light, init_light_and_camera_config[BlenderUtils.LIGHT_NAME]) @staticmethod def get_obj_diag(name): @@ -167,51 +178,15 @@ class BlenderUtils: min_z = min([v.z for v in vertices_world]) return min_z - @staticmethod - def setup_render_mask(): - bpy.context.scene.display.shading.light = 'FLAT' - bpy.context.scene.display.shading.color_type = 'MATERIAL' - - @staticmethod - def setup_render_normal(): - bpy.context.scene.display.shading.light = 'MATCAP' - bpy.context.scene.display.shading.color_type = 'OBJECT' - bpy.context.scene.display.shading.studio_light = 'check_normal+y.exr' - @staticmethod def render_and_save(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) - - # BlenderUtils.setup_render_normal() - - # 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.use_nodes = False - # scene.render.filepath = "" - - # normal_dir = os.path.join(output_dir, "normal") - # if not os.path.exists(normal_dir): - # os.makedirs(normal_dir) - - - # scene.render.filepath = os.path.join(output_dir, normal_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) - - - BlenderUtils.setup_render_mask() for cam_name in target_cameras: 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" scene = bpy.context.scene scene.render.filepath = "" @@ -255,6 +230,17 @@ class BlenderUtils: output_depth.format.color_depth = '16' tree.links.new(map_range.outputs[0], output_depth.inputs[0]) + + 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(rl.outputs['Normal'], output_normal.inputs[0]) bpy.ops.render.render(write_still=True) @@ -309,7 +295,6 @@ class BlenderUtils: keep_objects.add(BlenderUtils.CAMERA_OBJECT_NAME) keep_objects.add(BlenderUtils.CAMERA_NAME) keep_objects.add(BlenderUtils.CAMERA_RIGHT_NAME) - keep_objects.add(BlenderUtils.LIGHT_NAME) keep_objects.add(BlenderUtils.TABLE_NAME) for obj in all_objects: @@ -336,7 +321,6 @@ class BlenderUtils: no_save_objects.add(BlenderUtils.CAMERA_OBJECT_NAME) no_save_objects.add(BlenderUtils.CAMERA_NAME) no_save_objects.add(BlenderUtils.CAMERA_RIGHT_NAME) - no_save_objects.add(BlenderUtils.LIGHT_NAME) no_save_objects.add(BlenderUtils.TABLE_NAME) scene_info = {} for obj in all_objects: diff --git a/data_generator.py b/data_generator.py index 2019fc5..698fd3b 100644 --- a/data_generator.py +++ b/data_generator.py @@ -83,7 +83,7 @@ class DataGenerator: def generate_display_platform(self): config = self.random_config[BlenderUtils.DISPLAY_TABLE_NAME] - + height = random.uniform(config["min_height"], config["max_height"]) radius = random.uniform(config["min_radius"], config["max_radius"]) while height > 0.5 * radius: @@ -103,12 +103,29 @@ class DataGenerator: bpy.context.object.rigid_body.type = 'PASSIVE' bpy.ops.object.shade_auto_smooth() + # 创建不受光照影响的材质 mat = bpy.data.materials.new(name="RedMaterial") - mat.diffuse_color = (1.0, 0.0, 0.0, 1.0) # Red with full alpha (1.0) - if len(platform.data.materials) > 0: - platform.data.materials[0] = mat - else: - platform.data.materials.append(mat) + mat.use_nodes = True + + # 清除默认节点 + nodes = mat.node_tree.nodes + for node in nodes: + nodes.remove(node) + + # 添加 Emission 节点 + emission_node = nodes.new(type='ShaderNodeEmission') + emission_node.inputs['Color'].default_value = (1.0, 0.0, 0.0, 1.0) # 红色 + + # 添加 Material Output 节点 + output_node = nodes.new(type='ShaderNodeOutputMaterial') + + # 连接节点 + links = mat.node_tree.links + links.new(emission_node.outputs['Emission'], output_node.inputs['Surface']) + + # 将材质赋给对象 + platform.data.materials.clear() + platform.data.materials.append(mat) self.display_table_config = { "height": height, @@ -126,19 +143,19 @@ class DataGenerator: if random.random() <= config["random_rotation_ratio"]: rotation = ( - random.uniform(0, 2*np.pi), - random.uniform(0, 2*np.pi), - random.uniform(0, 2*np.pi) + random.uniform(0, 2 * np.pi), + random.uniform(0, 2 * np.pi), + random.uniform(0, 2 * np.pi) ) else: rotation = (0, 0, 0) - z=0.05 + z = 0.05 platform_bbox = self.platform.bound_box platform_bbox_world = [self.platform.matrix_world @ mathutils.Vector(corner) for corner in platform_bbox] platform_top_z = max([v.z for v in platform_bbox_world]) - obj_mesh_path = BlenderUtils.get_obj_path(self.obj_dir,name) + obj_mesh_path = BlenderUtils.get_obj_path(self.obj_dir, name) obj = BlenderUtils.load_obj(name, obj_mesh_path) obj_bottom_z = BlenderUtils.get_object_bottom_z(obj) @@ -149,12 +166,31 @@ class DataGenerator: bpy.ops.rigidbody.object_add() bpy.context.object.rigid_body.type = 'ACTIVE' + + # 创建不受光照影响的材质 mat = bpy.data.materials.new(name="GreenMaterial") - mat.diffuse_color = (0.0, 1.0, 0.0, 1.0) # Green with full alpha (1.0) - if len(obj.data.materials) > 0: - obj.data.materials[0] = mat - else: - obj.data.materials.append(mat) + mat.use_nodes = True + + # 清除默认节点 + nodes = mat.node_tree.nodes + for node in nodes: + nodes.remove(node) + + # 添加 Emission 节点 + emission_node = nodes.new(type='ShaderNodeEmission') + emission_node.inputs['Color'].default_value = (0.0, 1.0, 0.0, 1.0) # 绿色 + + # 添加 Material Output 节点 + output_node = nodes.new(type='ShaderNodeOutputMaterial') + + # 连接节点 + links = mat.node_tree.links + links.new(emission_node.outputs['Emission'], output_node.inputs['Surface']) + + # 将材质赋给对象 + obj.data.materials.clear() + obj.data.materials.append(mat) + self.target_obj = obj @@ -219,6 +255,13 @@ class DataGenerator: file_path = os.path.join(depth_dir, depth_file) new_file_path = os.path.join(depth_dir, f"{name}.png") os.rename(file_path,new_file_path) + normal_dir = os.path.join(scene_dir, "normal") + for normal_file in os.listdir(normal_dir): + if not normal_file.endswith(".png"): + name, _ = os.path.splitext(normal_file) + file_path = os.path.join(normal_dir, normal_file) + new_file_path = os.path.join(normal_dir, f"{name}.png") + os.rename(file_path,new_file_path) return True def simulate_scene(self, frame_limit=120, depth = 0, diag = 0): @@ -274,6 +317,7 @@ class DataGenerator: count_success = 0 self.set_progress("generate scene", 0, total) result = "retry" + print(f"Generating scene for {total} objects") for target_obj_name in self.obj_name_list: self.add_log(f"Generating scene for object <{target_obj_name}>", "info") scene_info_path = os.path.join(self.output_dir, target_obj_name, "scene_info.json") diff --git a/run_blender.py b/run_blender.py index 3fc5c47..3b9ad5b 100644 --- a/run_blender.py +++ b/run_blender.py @@ -10,7 +10,8 @@ if __name__ == "__main__": config_path = sys.argv[sys.argv.index('--') + 1] with open(config_path, "r") as file: config = yaml.safe_load(file) - + print("init data generator") dg = DataGenerator(config) + print("generate all scene data") dg.gen_all_scene_data() \ No newline at end of file