Exemplo n.º 1
0
def setup_render_freestyle(**options):
    """
    Setup the render setting

    :param n_frames: Animation length of a single oscillation cycle in
        frames
    :type n_frames: Positive int
    :param start_frame: The starting frame number of the rendered
        animation (default=0)
    :type start_frame: int or None
    :param end_frame: The ending frame number of the rendered Animation
        (default=start_frame+n_frames-1)
    :type end_frame: int or None
    :param preview: Write to a temporary preview file at low resolution
        instead of the output. Use first frame only. If no preview, set to
        empty string ''
    :type preview: str
    :param config: Path to user configuration settings -- this function makes
        use of 'x_pixels', 'y_pixels', 'box_thickness' and 'outline_thickness'
        keys in [general] section and 'outline' and 'box' keys in [colours]
        section
    :type config: str

    """

    opts = vsim2blender.Opts(options)
    start_frame = opts.get('start_frame', 0)
    n_frames = opts.get('n_frames', 30)

    if opts.get('static', False):
        end_frame = start_frame
    else:
        end_frame = opts.get('end_frame', start_frame + n_frames - 1)

    x_pixels = opts.get('x_pixels', 512)
    y_pixels = opts.get('y_pixels', 512)

    bpy.context.scene.render.resolution_x = x_pixels
    bpy.context.scene.render.resolution_y = y_pixels
    if opts.get('preview', False):
        bpy.context.scene.render.resolution_percentage = 40
    else:
        bpy.context.scene.render.resolution_percentage = 100

    # These flat renders don't use much memory, so render a single big
    # tiles for high speed
    bpy.context.scene.render.tile_x = x_pixels
    bpy.context.scene.render.tile_y = y_pixels

    bpy.context.scene.frame_start = start_frame
    bpy.context.scene.frame_end = end_frame

    bpy.context.scene.render.use_freestyle = True

    renderlayer = bpy.context.scene.render.layers['RenderLayer']

    if opts.get('show_box', True):
        # Wireframe box and add to "Group" for exclusion from outlining
        # Freestyle doesn't work with wireframes
        bpy.data.materials['Bounding Box'].type = 'SURFACE'
        mesh_to_wireframe(bpy.data.objects['Bounding Box'])
        mark_edges(bpy.data.objects['Bounding Box'])

        # Bounding box line settings
        bpy.ops.scene.freestyle_lineset_add()
        boxlines = renderlayer.freestyle_settings.linesets.active
        boxlinestyle = boxlines.linestyle
        boxlinestyle.thickness = opts.get('box_thickness', 5)
        boxlinestyle.color = str2list(
            opts.config.get('colours', 'box', fallback='1. 1. 1.'))

        # Bounding box tracer ignores everything but Freestyle marked edges
        boxlines.select_silhouette = False
        boxlines.select_border = False
        boxlines.select_crease = False
        boxlines.select_edge_mark = True

    # Outline settings
    bpy.ops.scene.freestyle_lineset_add()
    atomlines = renderlayer.freestyle_settings.linesets.active
    atomlinestyle = atomlines.linestyle
    atomlinestyle.thickness = opts.get('outline_thickness', 3)
    atomlinestyle.color = str2list(
        opts.config.get('colours', 'outline', fallback='0. 0. 0.'))
Exemplo n.º 2
0
def open_mode(**options):
    """
    Open v_sim ascii file in Blender

    :param input_file: Path to file
    :type input_file: str
    :param camera_rot: Camera tilt adjustment in degrees
    :type camera_rot: float
    :param config: Settings from configuration files
    :type config: configparser.ConfigParser
    :param mass_weighting: Weight eigenvectors by mass.
        This has usually already been done when generating the .ascii file,
        in which case the default value of 0 is acceptable.
        A value of 1 corresponds to the formally correct mass scaling of m^-0.5
        for non-weighted eigenvectors.
        A value of -1 will REMOVE existing mass-weighting.
        In-between values may be useful for re-scaling to see the range of
        movements in a system, but are not physically meaningful.
    :type mass_weighting: float
    :param end_frame: The ending frame number of the rendered Animation
        (default=start_frame+n_frames-1)
    :type end_frame: int or None
    :param miller: Miller indices of view
    :type miller: 3-tuple of floats
    :param mode_index: id of mode; 0 corresponds to first mode in ascii file
    :type mode_index: int
    :param n_frames: Animation length of a single oscillation
        cycle in frames (default=30)
    :type n_frames: Positive int
    :param normalise_vectors: Re-scale vectors so largest arrow is fixed length
    :type normalise_vectors: bool
    :param offset_box: Position of bbox in lattice vector coordinates.
        Default (0,0,0) (Left front bottom)
    :type offset_box: Vector or 3-tuple
    :param preview: Enable preview mode - single frame, smaller render
    :type preview: bool
    :param scale_arrow: Scale factor for arrows
    :type scale_arrow: float
    :param scale_atom: Scale of atoms, relative to covalent radius
    :type scale_atom: float
    :param scale_vib: Scale factor for oscillations
        (angstroms / normalised eigenvector).
    :type scale_vib: float
    :param show_box: If True, show bounding box
    :type show_box: bool
    :param start_frame: The starting frame number of the rendered
        animation (default=0)
    :type start_frame: int or None
    :param static: if True, ignore frame range and use single frame.
        Otherwise, add animation keyframes.
    :type static: bool
    :param supercell: supercell dimensions
    :type supercell: 3-tuple or 3-list of ints
    :param vectors: If True, show arrows
    :type vectors: bool
    :param zoom: Camera zoom adjustment
    :type zoom: float

    """

    # Initialise Opts object, accessing options and user config
    opts = vsim2blender.Opts(options)

    # Work out actual frame range.
    # Priority goes 1. static/preview 2. end_frame 3. n_frames
    start_frame = opts.get('start_frame', 0)
    n_frames = opts.get('n_frames', 30)

    # Preview images default to static, others default to animated
    preview = opts.get('preview', False)
    if preview:
        static = opts.get('static', True)
    else:
        static = opts.get('static', False)

    if static:
        end_frame = start_frame
    else:
        end_frame = opts.get('end_frame', start_frame + n_frames - 1)

    input_file = opts.get('input_file', False)
    if input_file:
        (vsim_cell, positions, symbols, vibs) = import_vsim(input_file)
        lattice_vectors = cell_vsim_to_vectors(vsim_cell)
    else:
        raise Exception('No .ascii file provided')

    if opts.get('mass_weighting', 0):
        f = opts.get('mass_weighting', 1)
        masses = [
            float(opts.config['masses'][symbol])**f for symbol in symbols
        ]
    else:
        masses = [1 for symbol in symbols]

    # Switch to a new empty scene
    bpy.ops.scene.new(type='EMPTY')

    # Draw bounding box
    if (opts.get('show_box', True)):
        bbox_offset = opts.get('offset_box', (0, 0, 0))
        bbox_offset = Vector(bbox_offset)
        draw_bounding_box(lattice_vectors, offset=bbox_offset)

    # Draw atoms after checking config
    mode_index = opts.get('mode_index', 0)
    supercell = (opts.get('supercell', (2, 2, 2)))
    vectors = opts.get('vectors', False)

    normalise_vectors = opts.get('normalise_vectors', False)
    # Variable for tracking largest arrow
    max_vector = 0
    arrow_objects = []

    mass_weighting = opts.get('mass_weighting', 0.)
    assert type(mass_weighting) == float

    for cell_id_tuple in itertools.product(range(supercell[0]),
                                           range(supercell[1]),
                                           range(supercell[2])):
        cell_id = Vector(cell_id_tuple)
        for (atom_index, (position, symbol,
                          mass)) in enumerate(zip(positions, symbols, masses)):
            atom = add_atom(position,
                            lattice_vectors,
                            symbol,
                            cell_id=cell_id,
                            scale_factor=opts.get('scale_atom', 1.),
                            name='{0}_{1}_{2}{3}{4}'.format(
                                atom_index, symbol, *cell_id_tuple),
                            config=opts.config)
            if vectors or not static:
                displacement_vector = vibs[mode_index].vectors[atom_index]
                qpt = vibs[mode_index].qpt
                B = (2 * math.pi *
                     Matrix(lattice_vectors).inverted().transposed())
                qpt_cartesian = Vector(qpt) * B

            if not static:
                animate_atom_vibs(atom,
                                  qpt_cartesian,
                                  displacement_vector,
                                  start_frame=start_frame,
                                  end_frame=end_frame,
                                  n_frames=n_frames,
                                  magnitude=opts.get('scale_vib', 1.),
                                  mass=mass)
            if vectors:
                arrow_vector = vector_with_phase(atom, qpt_cartesian,
                                                 displacement_vector)
                scale = arrow_vector.length
                loc = absolute_position(position,
                                        lattice_vectors=lattice_vectors,
                                        cell_id=cell_id)
                # Arrows are scaled by eigenvector magnitude
                arrow_objects.append(
                    add_arrow(loc=loc,
                              mass=mass,
                              rot_euler=vector_to_euler(arrow_vector),
                              scale=scale))

    if vectors:
        col = str2list(opts.config.get('colours', 'arrow',
                                       fallback='0. 0. 0.'))
        bpy.data.materials['Arrow'].diffuse_color = col

    # Rescaling; either by clamping max or accounting for cell size
    if vectors and normalise_vectors:
        master_scale = opts.get('scale_arrow', 1.)
        # Compare first element of object scales; they should be isotropic!
        max_length = max((arrow.scale[0] for arrow in arrow_objects))
        for arrow in arrow_objects:
            arrow.scale *= master_scale / max_length

    elif vectors:
        master_scale = opts.get('scale_arrow', 1.) * len(positions)
        for arrow in arrow_objects:
            arrow.scale *= master_scale

    # Position camera and colour world. Note that cameras as objects and
    # cameras as 'cameras' have different attributes, so need to look up
    # camera in bpy.data.cameras to set field of view.

    camera.setup_camera(lattice_vectors, field_of_view=0.2, opts=opts)

    bpy.context.scene.world = bpy.data.worlds['World']
    bpy.data.worlds['World'].horizon_color = str2list(
        opts.config.get('colours', 'background', fallback='0.5 0.5 0.5'))