def render_shadeless(blender_objects, path='flat.png'): """ Render a version of the scene with shading disabled and unique materials assigned to all objects, and return a set of all colors that should be in the rendered image. The image itself is written to path. This is used to ensure that all objects will be visible in the final rendered scene. """ render_args = bpy.context.scene.render # Cache the render args we are about to clobber old_filepath = render_args.filepath old_engine = render_args.engine old_use_antialiasing = render_args.use_antialiasing # Override some render settings to have flat shading render_args.filepath = path render_args.engine = 'BLENDER_RENDER' render_args.use_antialiasing = False # Move the lights and ground to layer 2 so they don't render # utils.set_layer(bpy.data.objects['Lamp_Key'], 2) # utils.set_layer(bpy.data.objects['Lamp_Fill'], 2) # utils.set_layer(bpy.data.objects['Lamp_Back'], 2) utils.set_layer(bpy.data.objects['Ground'], 2) # Add random shadeless materials to all objects object_colors = set() old_materials = [] for i, obj in enumerate(blender_objects): old_materials.append(obj.data.materials[0]) bpy.ops.material.new() mat = bpy.data.materials['Material'] mat.name = 'Material_%d' % i while True: r, g, b = [random.random() for _ in range(3)] if (r, g, b) not in object_colors: break object_colors.add((r, g, b)) mat.diffuse_color = [r, g, b] mat.use_shadeless = True obj.data.materials[0] = mat # Render the scene bpy.ops.render.render(write_still=True) # Undo the above; first restore the materials to objects for mat, obj in zip(old_materials, blender_objects): obj.data.materials[0] = mat # Move the lights and ground back to layer 0 # utils.set_layer(bpy.data.objects['Lamp_Key'], 0) # utils.set_layer(bpy.data.objects['Lamp_Fill'], 0) # utils.set_layer(bpy.data.objects['Lamp_Back'], 0) utils.set_layer(bpy.data.objects['Ground'], 0) # Set the render settings back to what they were render_args.filepath = old_filepath render_args.engine = old_engine render_args.use_antialiasing = old_use_antialiasing return object_colors
def generate_images(folder, blender_objects): if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons['cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' bpy.context.scene.cycles.device = 'GPU' render_args = bpy.context.scene.render old_filepath = render_args.filepath ground = bpy.data.objects['Ground'] ground.location[0] = ground.location[1] = 0 ground.rotation_euler[2] = 0 ground.scale[0] = ground.scale[1] = 100 ground.scale[2] = 0 ground_extra = ground.copy() ground_extra.name = 'Ground_extra' ground_extra.rotation_euler[2] = np.pi bpy.context.scene.objects.link(ground_extra) for idx in range(args.num_views): theta = 2 * np.pi * np.random.uniform(args.min_theta, args.max_theta) phi = 0.5 * np.pi * np.random.uniform(args.min_phi, args.max_phi) rho = np.random.uniform(args.min_rho, args.max_rho) cos_theta = np.cos(theta) sin_theta = np.sin(theta) cos_phi = np.cos(phi) sin_phi = np.sin(phi) bpy.context.scene.camera.location[0] = rho * cos_phi * cos_theta bpy.context.scene.camera.location[1] = rho * cos_phi * sin_theta bpy.context.scene.camera.location[2] = rho * sin_phi with open(os.path.join(folder, 'view_{}.json'.format(idx)), 'w') as f: json.dump({'theta': theta, 'phi': phi, 'rho': rho}, f) # Scene render_args.filepath = os.path.join(folder, 'image_{}.png'.format(idx)) bpy.ops.render.render(write_still=True) # Segmentation generate_mask(os.path.join(folder, 'segment_{}.png'.format(idx)), blender_objects) # Background for i, obj in enumerate(blender_objects): utils.set_layer(obj, 2) # render_args.filepath = os.path.join(folder, 'back_{}.png'.format(idx)) # bpy.ops.render.render(write_still=True) # Objects for i, obj in enumerate(blender_objects): utils.set_layer(obj, 0) # render_args.filepath = os.path.join(folder, 'object_{}_{}.png'.format(idx, i)) # bpy.ops.render.render(write_still=True) generate_mask(os.path.join(folder, 'mask_{}_{}.png'.format(idx, i)), blender_objects) utils.set_layer(obj, 2) for i, obj in enumerate(blender_objects): utils.set_layer(obj, 0) render_args.filepath = old_filepath return
def generate_images(folder, blender_objects): if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons[ 'cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' bpy.context.scene.cycles.device = 'GPU' render_args = bpy.context.scene.render old_filepath = render_args.filepath # Scene render_args.filepath = os.path.join(folder, 'image.png') bpy.ops.render.render(write_still=True) # Segmentation generate_mask(os.path.join(folder, 'segment.png'), blender_objects) # Background for i, obj in enumerate(blender_objects): utils.set_layer(obj, 2) # render_args.filepath = os.path.join(folder, 'back.png') # bpy.ops.render.render(write_still=True) # Objects for i, obj in enumerate(blender_objects): utils.set_layer(obj, 0) # render_args.filepath = os.path.join(folder, 'object_{}.png'.format(i)) # bpy.ops.render.render(write_still=True) generate_mask(os.path.join(folder, 'mask_{}.png'.format(i)), blender_objects) utils.set_layer(obj, 2) render_args.filepath = old_filepath return
def render_shadeless(blender_objects, path='flat.png'): """ Render a version of the scene with shading disabled and unique materials assigned to all objects, and return a set of all colors that should be in the rendered image. The image itself is written to path. This is used to ensure that all objects will be visible in the final rendered scene. """ render_args = bpy.context.scene.render # Cache the render args we are about to clobber old_filepath = render_args.filepath old_engine = render_args.engine if bpy.app.version <= (2, 79, 0): old_use_antialiasing = render_args.use_antialiasing old_view_transform = bpy.context.scene.view_settings.view_transform # Override some render settings to have flat shading render_args.filepath = path if bpy.app.version <= (2, 79, 0): render_args.engine = 'BLENDER_RENDER' # default rendering engine render_args.use_antialiasing = False else: render_args.engine = 'BLENDER_EEVEE' # default rendering engine # Move the lights and ground to layer 2 so they don't render if bpy.app.version <= (2, 79, 0): utils.set_layer(bpy.data.objects['Lamp_Key'], 2) utils.set_layer(bpy.data.objects['Lamp_Fill'], 2) utils.set_layer(bpy.data.objects['Lamp_Back'], 2) utils.set_layer(bpy.data.objects['Ground'], 2) else: # coll = bpy.data.collections.new("Collection") # bpy.context.scene.collection.children.link(coll) # print(bpy.data.objects.keys()) # coll.objects.link(bpy.data.objects['Plane']) # coll.objects.link(bpy.data.objects['Lamp_Fill']) # coll.objects.link(bpy.data.objects['Lamp_Key']) # coll.objects.link(bpy.data.objects['Lamp_Back']) # bpy.context.window.view_layer.layer_collection.children["Collection"].exclude = True # # Update view layer # layer = bpy.context.view_layer # layer.update() bpy.context.scene.objects['Plane'].hide_render = True bpy.context.scene.objects['Lamp_Fill'].hide_render = True bpy.context.scene.objects['Lamp_Key'].hide_render = True bpy.context.scene.objects['Lamp_Back'].hide_render = True # v1 = bpy.context.scene.view_layers.new(name="Lights layer") # v1.active_layer_collection(coll) # bpy.context.window.view_layer = v1 # # bpy.data.objects['Plane'].hide_set(False) # # bpy.data.objects['Lamp_Key'].hide_set(False) # # bpy.data.objects['Lamp_Fill'].hide_set(False) # # bpy.data.objects['Lamp_Back'].hide_set(False) # Add random shadeless materials to all objects object_colors = set() old_materials = [] for i, obj in enumerate(blender_objects): old_materials.append(obj.data.materials[0]) bpy.ops.material.new() mat = bpy.data.materials['Material'] mat.name = 'Material_%d' % i while True: r, g, b = [random.random() for _ in range(3)] if (r, g, b) not in object_colors: break object_colors.add((r, g, b)) if bpy.app.version <= (2, 79, 0): mat.use_shadeless = True mat.diffuse_color = [r, g, b] else: mat.use_nodes = True mat.node_tree.nodes.remove( mat.node_tree.nodes.get( 'Principled BSDF')) # Remove default node material_output = mat.node_tree.nodes.get('Material Output') emission = mat.node_tree.nodes.new('ShaderNodeEmission') emission.inputs['Strength'].default_value = 1 emission.inputs['Color'].default_value = [r, g, b, 1.] print(r, g, b) mat.node_tree.links.new(material_output.inputs[0], emission.outputs[0]) obj.active_material = mat bpy.context.scene.view_settings.view_transform = 'Standard' obj.data.materials[0] = mat # Render the scene bpy.ops.render.render(write_still=True) # Undo the above; first restore the materials to objects for mat, obj in zip(old_materials, blender_objects): obj.data.materials[0] = mat obj.active_material = mat # Move the lights and ground back to layer 0 if bpy.app.version <= (2, 79, 0): utils.set_layer(bpy.data.objects['Lamp_Key'], 0) utils.set_layer(bpy.data.objects['Lamp_Fill'], 0) utils.set_layer(bpy.data.objects['Lamp_Back'], 0) utils.set_layer(bpy.data.objects['Ground'], 0) else: bpy.context.scene.objects['Plane'].hide_render = False bpy.context.scene.objects['Lamp_Fill'].hide_render = False bpy.context.scene.objects['Lamp_Key'].hide_render = False bpy.context.scene.objects['Lamp_Back'].hide_render = False bpy.context.scene.view_settings.view_transform = old_view_transform # Set the render settings back to what they were render_args.filepath = old_filepath render_args.engine = old_engine if bpy.app.version <= (2, 79, 0): render_args.use_antialiasing = old_use_antialiasing return object_colors
def render_masks(blender_objects, path_prefix): render_args = bpy.context.scene.render # Cache the render args we are about to clobber old_filepath = render_args.filepath old_engine = render_args.engine old_use_antialiasing = render_args.use_antialiasing # Override some render settings to have flat shading render_args.filepath = path_prefix render_args.engine = 'BLENDER_RENDER' render_args.use_antialiasing = False render_args.layers['RenderLayer'].use_pass_object_index = True bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree render_layers = tree.nodes.new('CompositorNodeRLayers') index_buffer = render_layers.outputs['IndexOB'] masker_nodes = [] output_nodes = [] masker_to_output_links = [] for i, obj in enumerate(blender_objects): obj.pass_index = i + 1 masker = tree.nodes.new('CompositorNodeIDMask') masker.index = i + 1 masker_nodes.append(masker) tree.links.new(index_buffer, masker.inputs[0]) mask_file_output = tree.nodes.new("CompositorNodeOutputFile") mask_file_output.file_slots[0].path = 'mask_{:02}_modal_###.png'.format(i + 1) output_nodes.append(mask_file_output) masker_to_output_links.append(tree.links.new(masker.outputs[0], mask_file_output.inputs[0])) # Render all the modal masks bpy.ops.render.render(write_still=False) for i, obj in enumerate(blender_objects): maybe_crop(os.path.join(path_prefix, output_nodes[i].file_slots[0].path.replace('###', '001'))) utils.set_layer(obj, 2) tree.links.remove(masker_to_output_links[i]) tree.nodes.remove(output_nodes[i]) # Render each amodal mask for i, obj in enumerate(blender_objects): utils.set_layer(obj, 0) output_node = tree.nodes.new("CompositorNodeOutputFile") output_node.file_slots[0].path = 'mask_{:02}_amodal_###.png'.format(i + 1) masker_to_output = tree.links.new(masker_nodes[i].outputs[0], output_node.inputs[0]) bpy.ops.render.render(write_still=False) maybe_crop(os.path.join(path_prefix, output_node.file_slots[0].path.replace('###', '001'))) tree.links.remove(masker_to_output) tree.nodes.remove(output_node) utils.set_layer(obj, 2) for i, obj in enumerate(blender_objects): utils.set_layer(obj, 0) # Set the render settings back to what they were render_args.filepath = old_filepath render_args.engine = old_engine render_args.use_antialiasing = old_use_antialiasing
def render_scene(args, num_objects=5, output_index=0, output_split='none', output_image='render.png', output_scene='render_json', output_masks=None, output_blendfile=None, ): # Load the main blendfile bpy.ops.wm.open_mainfile(filepath=args.base_scene_blendfile) # Load materials utils.load_materials(args.material_dir) # Set render arguments so we can get pixel coordinates later. # We use functionality specific to the CYCLES renderer so BLENDER_RENDER # cannot be used. render_args = bpy.context.scene.render render_args.engine = "CYCLES" render_args.filepath = output_image render_args.resolution_x = args.width render_args.resolution_y = args.height render_args.resolution_percentage = 100 render_args.tile_x = args.render_tile_size render_args.tile_y = args.render_tile_size if args.use_gpu == 1: # Blender changed the API for enabling CUDA at some point if bpy.app.version < (2, 78, 0): bpy.context.user_preferences.system.compute_device_type = 'CUDA' bpy.context.user_preferences.system.compute_device = 'CUDA_0' else: cycles_prefs = bpy.context.user_preferences.addons['cycles'].preferences cycles_prefs.compute_device_type = 'CUDA' # Some CYCLES-specific stuff bpy.data.worlds['World'].cycles.sample_as_light = True bpy.context.scene.cycles.blur_glossy = 2.0 bpy.context.scene.cycles.samples = args.render_num_samples bpy.context.scene.cycles.transparent_min_bounces = args.render_min_bounces bpy.context.scene.cycles.transparent_max_bounces = args.render_max_bounces if args.use_gpu == 1: bpy.context.scene.cycles.device = 'GPU' if args.output_depth: # Following is based on stanford-shapenet-renderer bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree render_layers = tree.nodes.new('CompositorNodeRLayers') depth_file_output = tree.nodes.new(type="CompositorNodeOutputFile") depth_file_output.label = 'Depth Output' depth_file_output.file_slots[0].path = '../../' + output_image + '_depth' map = tree.nodes.new(type="CompositorNodeNormalize") # thus, most distant points have pixel intensity of one, and nearest zero tree.links.new(render_layers.outputs['Depth'], map.inputs[0]) tree.links.new(map.outputs[0], depth_file_output.inputs[0]) # This will give ground-truth information about the scene and its objects scene_struct = { 'split': output_split, 'image_index': output_index, 'image_filename': os.path.basename(output_image), 'objects': [], 'directions': {}, } # Put a plane on the ground so we can compute cardinal directions bpy.ops.mesh.primitive_plane_add(radius=5) plane = bpy.context.object def rand(L): return 2.0 * L * (random.random() - 0.5) # Add random jitter to camera position if args.camera_jitter > 0: for i in range(3): bpy.data.objects['Camera'].location[i] += rand(args.camera_jitter) # Figure out the left, up, and behind directions along the plane and record # them in the scene structure camera = bpy.data.objects['Camera'] plane_normal = plane.data.vertices[0].normal cam_behind = camera.matrix_world.to_quaternion() * Vector((0, 0, -1)) cam_left = camera.matrix_world.to_quaternion() * Vector((-1, 0, 0)) cam_up = camera.matrix_world.to_quaternion() * Vector((0, 1, 0)) plane_behind = (cam_behind - cam_behind.project(plane_normal)).normalized() plane_left = (cam_left - cam_left.project(plane_normal)).normalized() plane_up = cam_up.project(plane_normal).normalized() # Delete the plane; we only used it for normals anyway. The base scene file # contains the actual ground plane. utils.delete_object(plane) # Save all six axis-aligned directions in the scene struct scene_struct['directions']['behind'] = tuple(plane_behind) scene_struct['directions']['front'] = tuple(-plane_behind) scene_struct['directions']['left'] = tuple(plane_left) scene_struct['directions']['right'] = tuple(-plane_left) scene_struct['directions']['above'] = tuple(plane_up) scene_struct['directions']['below'] = tuple(-plane_up) # Add random jitter to lamp positions if args.key_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Key'].location[i] += rand(args.key_light_jitter) if args.back_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Back'].location[i] += rand(args.back_light_jitter) if args.fill_light_jitter > 0: for i in range(3): bpy.data.objects['Lamp_Fill'].location[i] += rand(args.fill_light_jitter) # Now make some random objects objects, blender_objects = add_random_objects(scene_struct, num_objects, args, camera) if args.no_background: # This must come after add_random_objects, as that also changes the ground layer utils.set_layer(bpy.data.objects['Ground'], 2) else: # Note that in base_scene, the ground has no material (hence uses blender's default) bpy.data.materials.new(name='Ground_Material') ground_mat = bpy.data.materials['Ground_Material'] background_intensity = args.background_intensities[random.randrange(len(args.background_intensities))] ground_mat.diffuse_color = [background_intensity] * 3 bpy.data.objects['Ground'].data.materials.append(ground_mat) # Render the scene and dump the scene data structure scene_struct['objects'] = objects scene_struct['relationships'] = compute_all_relationships(scene_struct) while True: try: bpy.ops.render.render(write_still=True) break except Exception as e: print(e) if args.crop: maybe_crop(output_image) if args.output_depth: raise NotImplementedError if output_masks is not None: render_masks(blender_objects, output_masks) with open(output_scene, 'w') as f: json.dump(scene_struct, f, indent=2) if output_blendfile is not None: bpy.ops.wm.save_as_mainfile(filepath=output_blendfile)
def generate_mask(path, blender_objects, channel_split=3, antialiasing=True): render_args = bpy.context.scene.render # Cache the render args we are about to clobber old_filepath = render_args.filepath old_engine = render_args.engine old_use_antialiasing = render_args.use_antialiasing old_alpha_mode = render_args.alpha_mode old_color_mode = render_args.image_settings.color_mode # Override some render settings to have flat shading render_args.filepath = path render_args.engine = 'BLENDER_RENDER' render_args.use_antialiasing = antialiasing render_args.alpha_mode = 'TRANSPARENT' render_args.image_settings.color_mode = 'RGBA' # Move the lights and ground to layer 2 so they don't render utils.set_layer(bpy.data.objects['Lamp_Key'], 2) utils.set_layer(bpy.data.objects['Lamp_Fill'], 2) utils.set_layer(bpy.data.objects['Lamp_Back'], 2) utils.set_layer(bpy.data.objects['Ground'], 2) # Add random shadeless materials to all objects old_materials = [] for i, obj in enumerate(blender_objects): old_materials.append(obj.data.materials[0]) bpy.ops.material.new() mat = bpy.data.materials['Material'] mat.name = 'Material_%d' % i r = (i % channel_split) / (channel_split - 1) idx = i // channel_split g = (idx % channel_split) / (channel_split - 1) idx //= channel_split b = (idx % channel_split) / (channel_split - 1) mat.diffuse_color = [r, g, b] mat.use_shadeless = True obj.data.materials[0] = mat # Render the scene bpy.ops.render.render(write_still=True) # Undo the above; first restore the materials to objects for mat, obj in zip(old_materials, blender_objects): obj.data.materials[0] = mat # Move the lights and ground back to layer 0 utils.set_layer(bpy.data.objects['Lamp_Key'], 0) utils.set_layer(bpy.data.objects['Lamp_Fill'], 0) utils.set_layer(bpy.data.objects['Lamp_Back'], 0) utils.set_layer(bpy.data.objects['Ground'], 0) # Set the render settings back to what they were render_args.filepath = old_filepath render_args.engine = old_engine render_args.use_antialiasing = old_use_antialiasing render_args.alpha_mode = old_alpha_mode render_args.image_settings.color_mode = old_color_mode return
def render_shadeless(blender_objects, path='flat.png'): """ Render a version of the scene with shading disabled and unique materials assigned to all objects, and return a set of all colors that should be in the rendered image. The image itself is written to path. This is used to ensure that all objects will be visible in the final rendered scene. """ render_args = bpy.context.scene.render # Cache the render args we are about to clobber old_filepath = render_args.filepath old_engine = render_args.engine old_use_antialiasing = render_args.use_antialiasing # Override some render settings to have flat shading render_args.filepath = path render_args.engine = 'BLENDER_RENDER' render_args.use_antialiasing = False # Move the lights and ground to layer 2 so they don't render utils.set_layer(bpy.data.objects['Lamp_Key'], 2) utils.set_layer(bpy.data.objects['Lamp_Fill'], 2) utils.set_layer(bpy.data.objects['Lamp_Back'], 2) utils.set_layer(bpy.data.objects['Ground'], 2) # Add random shadeless materials to all objects object_colors = set() text_colors = {} old_materials = [] for i, obj in enumerate(blender_objects): old_materials.append(obj.data.materials[0]) bpy.ops.material.new() mat = bpy.data.materials['Material'] mat.name = 'Material_%d' % i r, g, b = i * .01, i * .01, i * .01 if "Mesh" in obj.data.name or "CUText" in obj.data.name: text_colors[obj.data.name] = (r, g, b) else: object_colors.add((r, g, b)) mat.diffuse_color = [r, g, b] mat.use_shadeless = True obj.data.materials[0] = mat # Need to do this to not transform the colors too much during rendering bpy.context.scene.render.image_settings.view_settings.view_transform = "Raw" bpy.context.scene.render.image_settings.file_format = 'OPEN_EXR' bpy.context.scene.render.image_settings.color_mode = 'RGB' # Render the scene bpy.ops.render.render(write_still=True) # Change these settings back so we render out the PNG images bpy.context.scene.render.image_settings.view_settings.view_transform = "Default" bpy.context.scene.render.image_settings.file_format = 'JPEG' bpy.context.scene.render.image_settings.color_mode = 'RGB' # Undo the above; first restore the materials to objects for mat, obj in zip(old_materials, blender_objects): obj.data.materials[0] = mat # Move the lights and ground back to layer data utils.set_layer(bpy.data.objects['Lamp_Key'], 0) utils.set_layer(bpy.data.objects['Lamp_Fill'], 0) utils.set_layer(bpy.data.objects['Lamp_Back'], 0) utils.set_layer(bpy.data.objects['Ground'], 0) # Set the render settings back to what they were render_args.filepath = old_filepath render_args.engine = old_engine render_args.use_antialiasing = old_use_antialiasing return object_colors, text_colors