def add_camera_animation(op, cameras, parent_collection, number_interpolation_frames, interpolation_type, consider_missing_cameras_during_animation, remove_rotation_discontinuities, image_dp, image_fp_type): op.report({'INFO'}, 'Adding Camera Animation: ...') if len(cameras) == 0: return if consider_missing_cameras_during_animation: cameras = enhance_cameras_with_dummy_cameras(op, cameras, image_dp, image_fp_type) # Using the first reconstructed camera as template for the animated camera. The values # are adjusted with add_transformation_animation() and add_camera_intrinsics_animation(). some_cam = cameras[0] bcamera = add_single_camera(op, "Animated Camera", some_cam) cam_obj = add_obj(bcamera, "Animated Camera", parent_collection) cameras_sorted = sorted(cameras, key=lambda camera: camera.get_relative_fp()) transformations_sorted = [] camera_intrinsics_sorted = [] for camera in cameras_sorted: if isinstance(camera, DummyCamera): matrix_world = None camera_intrinsics = None else: matrix_world = compute_camera_matrix_world(camera) shift_x, shift_y = compute_shift(camera, relativ_to_largest_extend=True) camera_intrinsics = CameraIntrinsics(camera.get_field_of_view(), shift_x, shift_y) transformations_sorted.append(matrix_world) camera_intrinsics_sorted.append(camera_intrinsics) add_transformation_animation( op=op, animated_obj_name=cam_obj.name, transformations_sorted=transformations_sorted, number_interpolation_frames=number_interpolation_frames, interpolation_type=interpolation_type, remove_rotation_discontinuities=remove_rotation_discontinuities) add_camera_intrinsics_animation( op=op, animated_obj_name=cam_obj.name, intrinsics_sorted=camera_intrinsics_sorted, number_interpolation_frames=number_interpolation_frames)
def add_points_as_mesh(op, points, reconstruction_collection): op.report({'INFO'}, 'Adding Points as Mesh: ...') stop_watch = StopWatch() point_cloud_obj_name = "Mesh Point Cloud" point_cloud_mesh = bpy.data.meshes.new(point_cloud_obj_name) point_cloud_mesh.update() point_cloud_mesh.validate() point_world_coordinates = [tuple(point.coord) for point in points] point_cloud_mesh.from_pydata(point_world_coordinates, [], []) point_cloud_obj = add_obj(point_cloud_mesh, point_cloud_obj_name, reconstruction_collection) op.report({'INFO'}, 'Duration: ' + str(stop_watch.get_elapsed_time())) op.report({'INFO'}, 'Adding Points as Mesh: Done') return point_cloud_obj.name
def add_camera_image_plane(matrix_world, blender_image, camera, name, transparency, add_image_plane_emission, image_planes_collection, op): """ Create mesh for image plane """ # op.report({'INFO'}, 'add_camera_image_plane: ...') # op.report({'INFO'}, 'name: ' + str(name)) width = camera.width height = camera.height focal_length = camera.get_focal_length() p_x, p_y = camera.get_principal_point() assert width is not None and height is not None bpy.context.scene.render.engine = 'CYCLES' mesh = bpy.data.meshes.new(name) mesh.update() mesh.validate() plane_distance = 1.0 # Distance from camera position # Right vector in view frustum at plane_distance: right = Vector((1, 0, 0)) * (width / focal_length) * plane_distance # Up vector in view frustum at plane_distance: up = Vector((0, 1, 0)) * (height / focal_length) * plane_distance # Camera view direction: view_dir = -Vector((0, 0, 1)) * plane_distance plane_center = view_dir shift_x, shift_y = compute_shift(camera, relativ_to_largest_extend=False) corners = ((-0.5, -0.5), (+0.5, -0.5), (+0.5, +0.5), (-0.5, +0.5)) points = [ (plane_center + (c[0] + shift_x) * right + (c[1] + shift_y) * up)[0:3] for c in corners ] mesh.from_pydata(points, [], [[0, 1, 2, 3]]) mesh.uv_layers.new() # Add mesh to new image plane object: mesh_obj = add_obj(mesh, name, image_planes_collection) image_plane_material = bpy.data.materials.new(name="image_plane_material") # Adds "Principled BSDF" and a "Material Output" node image_plane_material.use_nodes = True nodes = image_plane_material.node_tree.nodes links = image_plane_material.node_tree.links shader_node_tex_image = nodes.new(type='ShaderNodeTexImage') shader_node_principled_bsdf = nodes.get('Principled BSDF') shader_node_principled_bsdf.inputs['Alpha'].default_value = transparency links.new(shader_node_tex_image.outputs['Color'], shader_node_principled_bsdf.inputs['Base Color']) if add_image_plane_emission: links.new(shader_node_tex_image.outputs['Color'], shader_node_principled_bsdf.inputs['Emission']) shader_node_tex_image.image = blender_image # Assign it to object if mesh_obj.data.materials: # assign to 1st material slot mesh_obj.data.materials[0] = image_plane_material else: # no slots mesh_obj.data.materials.append(image_plane_material) mesh_obj.matrix_world = matrix_world mesh.update() mesh.validate() # op.report({'INFO'}, 'add_camera_image_plane: Done') return mesh_obj
def add_cameras(op, cameras, parent_collection, image_dp=None, add_background_images=False, add_image_planes=False, convert_camera_coordinate_system=True, camera_collection_name='Cameras', image_plane_collection_name='Image Planes', camera_scale=1.0, image_plane_transparency=0.5, add_image_plane_emission=True): """ ======== The images are currently only shown in BLENDER RENDER ======== ======== Make sure to enable TEXTURE SHADING in the 3D view to make the images visible ======== :param cameras: :param image_dp: :param add_image_planes: :param convert_camera_coordinate_system: :param camera_collection_name: :param image_plane_collection_name: :return: """ op.report({'INFO'}, 'Adding Cameras: ...') stop_watch = StopWatch() camera_collection = add_collection(camera_collection_name, parent_collection) if add_image_planes: op.report({'INFO'}, 'Adding image planes: True') image_planes_collection = add_collection(image_plane_collection_name, parent_collection) camera_image_plane_pair_collection = add_collection( "Camera Image Plane Pair Collection", parent_collection) else: op.report({'INFO'}, 'Adding image planes: False') # Adding cameras and image planes: for index, camera in enumerate(cameras): # camera_name = "Camera %d" % index # original code # Replace the camera name so it matches the image name (without extension) blender_image_name_stem = camera.get_blender_obj_gui_str() camera_name = blender_image_name_stem + '_cam' bcamera = add_single_camera(op, camera_name, camera) camera_object = add_obj(bcamera, camera_name, camera_collection) matrix_world = compute_camera_matrix_world(camera) camera_object.matrix_world = matrix_world camera_object.scale *= camera_scale if not add_image_planes and not add_background_images: continue if camera.has_undistorted_absolute_fp(): path_to_image = camera.get_undistored_absolute_fp() else: path_to_image = camera.get_absolute_fp() if not os.path.isfile(path_to_image): continue blender_image = bpy.data.images.load(path_to_image) if add_background_images: # op.report({'INFO'}, 'Adding background image for: ' + camera_name) camera_data = bpy.data.objects[camera_name].data camera_data.show_background_images = True background_image = camera_data.background_images.new() background_image.image = blender_image if add_image_planes and not camera.is_panoramic(): # op.report({'INFO'}, 'Adding image plane for: ' + camera_name) # Group image plane and camera: camera_image_plane_pair_collection_current = add_collection( "Camera Image Plane Pair Collection %s" % blender_image_name_stem, camera_image_plane_pair_collection) image_plane_name = blender_image_name_stem + '_image_plane' # do not add image planes by default, this is slow ! image_plane_obj = add_camera_image_plane( matrix_world, blender_image, camera=camera, name=image_plane_name, transparency=image_plane_transparency, add_image_plane_emission=add_image_plane_emission, image_planes_collection=image_planes_collection, op=op) camera_image_plane_pair_collection_current.objects.link( camera_object) camera_image_plane_pair_collection_current.objects.link( image_plane_obj) op.report({'INFO'}, 'Duration: ' + str(stop_watch.get_elapsed_time())) op.report({'INFO'}, 'Adding Cameras: Done')
def add_points_as_mesh(op, points, add_points_as_particle_system, mesh_type, point_extent, add_particle_color_emission, reconstruction_collection, set_particle_color_flag, particle_overwrite_color=None): op.report({'INFO'}, 'Adding Points: ...') stop_watch = StopWatch() particle_obj_name = "Particle Shape" point_cloud_obj_name = "Point Cloud" point_cloud_mesh = bpy.data.meshes.new(point_cloud_obj_name) point_cloud_mesh.update() point_cloud_mesh.validate() point_world_coordinates = [tuple(point.coord) for point in points] point_cloud_mesh.from_pydata(point_world_coordinates, [], []) point_cloud_obj = add_obj(point_cloud_mesh, point_cloud_obj_name, reconstruction_collection) if add_points_as_particle_system: op.report({'INFO'}, 'Representing Points in the Point Cloud with Meshes: True') op.report({'INFO'}, 'Mesh Type: ' + str(mesh_type)) # The default size of elements added with # primitive_cube_add, primitive_uv_sphere_add, etc. is (2,2,2) point_scale = point_extent * 0.5 bpy.ops.object.select_all(action='DESELECT') if mesh_type == "PLANE": bpy.ops.mesh.primitive_plane_add(size=point_scale) elif mesh_type == "CUBE": bpy.ops.mesh.primitive_cube_add(size=point_scale) elif mesh_type == "SPHERE": bpy.ops.mesh.primitive_uv_sphere_add(radius=point_scale) else: bpy.ops.mesh.primitive_uv_sphere_add(radius=point_scale) particle_obj = bpy.context.object particle_obj.name = particle_obj_name reconstruction_collection.objects.link(particle_obj) bpy.context.collection.objects.unlink(particle_obj) material_name = "PointCloudMaterial" material = bpy.data.materials.new(name=material_name) particle_obj.data.materials.append(material) # enable cycles, otherwise the material has no nodes bpy.context.scene.render.engine = 'CYCLES' material.use_nodes = True node_tree = material.node_tree # Print all available nodes with: # bpy.data.materials['material_name'].node_tree.nodes.keys() if 'Material Output' in node_tree.nodes: # is created by default material_output_node = node_tree.nodes['Material Output'] else: material_output_node = node_tree.nodes.new( 'ShaderNodeOutputMaterial') if 'Principled BSDF' in node_tree.nodes: # is created by default principled_bsdf_node = node_tree.nodes['Principled BSDF'] else: principled_bsdf_node = node_tree.nodes.new( "ShaderNodeBsdfPrincipled") node_tree.links.new(principled_bsdf_node.outputs['BSDF'], material_output_node.inputs['Surface']) assert len(point_world_coordinates) == len(points) particle_color_node = create_particle_color_nodes( node_tree, points, set_particle_color_flag, particle_overwrite_color) # Add links for base color and emission to improve color visibility node_tree.links.new(particle_color_node.outputs['Color'], principled_bsdf_node.inputs['Base Color']) if add_particle_color_emission: node_tree.links.new(particle_color_node.outputs['Color'], principled_bsdf_node.inputs['Emission']) if len(point_cloud_obj.particle_systems) == 0: point_cloud_obj.modifiers.new("particle sys", type='PARTICLE_SYSTEM') particle_sys = point_cloud_obj.particle_systems[0] settings = particle_sys.settings settings.type = 'HAIR' settings.use_advanced_hair = True settings.emit_from = 'VERT' settings.count = len(points) # The final object extent is hair_length * obj.scale settings.hair_length = 100 # This must not be 0 settings.use_emit_random = False settings.render_type = 'OBJECT' settings.instance_object = particle_obj bpy.context.view_layer.update() else: op.report({'INFO'}, 'Representing Points in the Point Cloud with Meshes: False') op.report({'INFO'}, 'Duration: ' + str(stop_watch.get_elapsed_time())) op.report({'INFO'}, 'Adding Points: Done') return point_cloud_obj.name