Exemple #1
0
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
Exemple #3
0
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
Exemple #4
0
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