Rendering

Display objects

In OVITO, data objects are separated from display objects, which are responsible for producing a visual representation of the data. For example, a SimulationCell is a pure data object, which stores the simulation cell vectors and the periodic boundary flags. The corresponding display object (a SimulationCellDisplay) takes this information to generate the actual box geometry to visualize the dimensions of the simulation cell in the viewports. The display object also stores parameters such as the simulation cell display color and line width, which control the visual appearance.

The display object is attached to the data object and can be accessed through the display attribute of the DataObject base class:

>>> cell = node.source.cell
>>> cell                                     # This is the data object
<SimulationCell at 0x7f9a414c8060>

>>> cell.display                             # This is the attached display object
<SimulationCellDisplay at 0x7fc3650a1c20>

>>> cell.display.rendering_color = (1,0,0)   # Giving the simulation box a red color

All display objects are derived from the Display base class, which provides the enabled attribute to turn the display on or off:

>>> cell.display.enabled = False         # This hides the simulation cell

The visual display of particles is controlled by a ParticleDisplay object, which is attached to the position ParticleProperty. For example, to display cubic particles, we would write:

>>> pos = node.source.particle_properties.position      # ParticleProperty storing the positions
>>> pos.display.shape = ParticleDisplay.Shape.Square

Note

Note that display objects flow down the modification pipeline together with the data objects they are attached to. Normally they are not modified by modifiers in the pipeline, only the data objects are. That means it doesn’t matter whether you change display parameters in the input of the modification pipeline or in the output. In the examples above we have accessed the input data collection (node.source), but changing the display parameters in the output data collection (node.output) would have worked equally well.

Some modifiers produce new data objects when the modification pipeline is evaluated. For example, the CalculateDisplacementsModifier generates a new ParticleProperty that stores the computed displacement vectors. To enable the display of displacement vectors as arrows, the CalculateDisplacementsModifier attaches a VectorDisplay to the new particle property. We can access this display object in two equivalent ways: either directly though the vector_display attribute of the modifier:

>>> modifier = CalculateDisplacementsModifier()
>>> node.modifiers.append(modifier)
>>> modifier.vector_display.enabled = True       # Enable the display of arrows
>>> modifier.vector_display.color = (0,0,1)      # Give arrows a blue color

or via the display attribute of the resulting particle property:

>>> node.compute()                                      # Ensure pipeline output exists
>>> node.output.particle_properties.displacement.display.enabled = True     # Enable the display of arrows
>>> node.output.particle_properties.displacement.display.color = (0,0,1)    # Give arrows a blue color

Similarly, the CreateBondsModifier attached a BondsDisplay to the Bonds data object it computes.

Viewports

A Viewport defines the view of the three-dimensional scene, in which the display objects generate a visual representation of the data. To render a picture of the scene from a script, you typically create a new ad hoc Viewport instance and configure it by setting the camera position and orientation:

>>> from ovito.vis import *
>>> vp = Viewport()
>>> vp.type = Viewport.Type.PERSPECTIVE
>>> vp.camera_pos = (-100, -150, 150)
>>> vp.camera_dir = (2, 3, -3)
>>> vp.fov = math.radians(60.0)

As known from the graphical OVITO program, there exist various viewport types such as TOP, FRONT, PERSPECTIVE, etc. The PERSPECTIVE and ORTHO viewport types allow you to freely orient the camera in space and are usually what you want. Don’t forget to set the viewport type first before setting up the camera as demonstrated in the example above. That’s because changing the viewport type will reset the camera to a default orientation.

The PERSPECTIVE viewport type uses a perspective projection, and you specify the field of view (fov) as an angle (measured vertically). The ORTHO viewport type uses a parallel projection; then the fov parameter specifies the size of the visible area in the vertical direction in length units. You can call the Viewport.zoom_all() method to let OVITO choose a reasonable camera zoom and position such that all objects are completely visible.

OVITO’s graphical user interface defines four standard viewports. You can access and manipulate them from a script via the dataset.viewports list.

Rendering

Parameters that control the rendering process, e.g. the desired image resolution, output filename, background color, are managed by a RenderSettings objects. You can create a new instance of this class and specify the parameters:

from ovito.vis import *
settings = RenderSettings(
    filename = "myimage.png",
    size = (800, 600)
)

You can choose between three different rendering engines, which can produce the final image of the scene. The default renderer is the OpenGLRenderer, which implements a fast, hardware-accelerated OpenGL rendering method. The second option is the TachyonRenderer, which is a software-only raytracing engine and which is able to produce better looking results in many cases. Finally, the POVRayRenderer offloads the rendering to the external POV-Ray program, which must be installed on the local computer. Each of these rendering backends has specific parameters, and you can access the current renderer through the RenderSettings.renderer attribute:

settings.renderer = TachyonRenderer() # Activate the TachyonRenderer backend
settings.renderer.shadows = False     # Turn off cast shadows

After the render settings have been specified, we can let OVITO render the image by calling Viewport.render():

vp.render(settings)

Note that render() returns a QImage, giving you the possibility to manipulate the rendered picture before saving it to disk.