Controlling the Scene¶
The scene in yt_idv
is made up of several components, all of which are
managed via objects possessing traitlets.
At the top most level, there is the yt_idv.scene_graph.SceneGraph
object, which usually lives on a rendering context as the scene
attribute.
This class, which is riddled with traitlets, manages the drawing of all of the
different visualization components and annotations.
There are three types of objects that the SceneGraph
manages:
annotations
– These are subclasses ofSceneAnnotation
and are generally rendered with only one type of shader. This includes things like a text annotation and box outlines.
components
– These are subclasses ofSceneComponent
and are data visualization components. This includes block rendering and mesh rendering, and may at some point be expanded to include particle rendering.
data_objects
– These are subclasses ofSceneData
. Some types of data can be reused and shared between components and annotations. These objects manage data that needs to be stored on the GPU. For instance, this includes 3D textures that correspond to the block data and the vectors that define the coordinates of the grid edges, as well as font glyph information.
Each of these objects has a set of attributes that define its appearance and how it is drawn. These attributes can be changed with either programmatic access of by accessing them in the GUI.
In addition to these, the scene also possesses:
camera
– at present, this is always an instance ofTrackballCamera
. It controls the orientation and position of the viewpoint, as well as its field of view.
image
– this will read the image back and return it as a 4-component, 2D floating point array.
Volume Rendering¶
A volume rendering component can be added to a scene by calling
add_volume()
.
The volume rendering in yt_idv
is similarly implemented to the software
volume rendering in yt itself. It utilizes a kdtree decomposition of the
source data object to construct 3D textures that reside on the graphics card,
and then conducts a front-to-back evaluation of them in order.
The data that lives on the GPU is a
BlockCollection
. This contains, for
each “block,” a 3D texture of the data field to render and a 3D texture of the
bitmap of included points. (Future versions of yt_idv
will endeavor to
make it easier to modify these bitmaps to perform selections.)
The rendering component is an instance of
BlockRendering
. This has several
properties that are likely of interest for controlling the rendering.
Modifying these will update the rendering the next time a frame is rendered.
It is worth noting that because we are using traitlets validation, even though
some of these are backed by OpenGL-specific values, they often will
automatically convert data. For instance, the colormap
property will
convert a string to the appropriate texture on the GPU.
render_method
– this is a string that changes the fragment shaders used to render the blocks. For a volume rendering component, this can be"projection"
,"max_intensity"
or"transfer_function"
.colormap
– setting this to a string will change the colormap to that matplotlib colormap. This only has effect if using"projection"
or"max_intensity"
.cmap_min
andcmap_max
– these are floating point values for the colormap bounds. If either or both are set to None, the colormap will be dynamically .cmap_log
– a bool governing whether or not the values should be logged before the colormap is applied.transfer_function
– this is an instance of a special class of 2D texture that has RGBA channels. You can access or modify itsdata
attribute to change the transfer function values. This only has impact if you are using therender_method
of"transfer_function"
.
Boxes can also be added as an annotation to show the 3D textures being rendered
by a BlockRendering
. This will re-use the
underlying BlockCollection
, and
can be added by manually constructing an annotation:
from yt_idv.scene_annotations.block_outline import BlockOutline
sg = rc.add_scene(dd, "density")
block_data = rc.scene.data_objects[0]
rc.scene.annotations.append(BlockOutline(data=block_data))
The block outlines here will match the textures rendered, which will likely be different from the underlying grid structure.
Text Annotations¶
Text annotations can be added to a scene by calling
add_text()
. This will utilize a (default)
set of font glyphs (in “DejaVu Sans”) to display text. It is also possible to
construct an alternate instance of
TextCharacters
with a different
font, and specify that as data
to the add_text
call.
The instance of TextAnnotation
that
provides the actual annotation has several properties that are of interest in
changing its appearance.
text
– this is the unicode string displayed. Changing this will update the draw instructions and thus the annotation.origin
– this is a tuple of floats, each of which are between -1 and 1, for the origin (bottom left) to display the text. This is in screen coordinates, where (-1, -1) is the lower left corner of the screen.scale
– the multiplicative factor for the size of the text.
An annotation such as this can be used for displaying captions, time, etc.
Box Annotations¶
Box annotations can be added to a scene by calling
add_box()
. This accepts a set of corners
for the min (i.e., “left”) and the max (i.e., “right”) edges of the box. The
attributes that might be of interest to control the rendering are:
box_width
– this float governs the width of the lines that are drawn. This is in coordinate space of the domain, rather than the screen. *box_alpha
– this float is the opacity of the boxes. It ranges from 0.0 to 1.0.
Camera Control¶
Each scene has an instance of a
TrackballCamera
object. (Other
cameras may be implemented in the future, but for now, everything is this.)
This has a set of parameters that allow you to change its position and direction.
Note
One interesting thing is that the projection matrix used here is identical to the projection matrix used by pythreejs, which means it’s possible to link the two up!
position
– this is the position of the camerafocus
– what point (in data coordinates) is the camera looking at?up
– this vector is the vector corresponding to “up” in the scenefov
– this floating point value controls the field of view. By default this is 45.near_plane
andfar_plane
– these control the near/far values input into the projection matrix. The important quantity here is their ratio; by default we allow for a 2e4 ratio.
In general, it’s tricky to get the position of the camera just right, and there
are also a number of properties of it that are not properly exposed. This is
an area of future improvement in yt_idv
, especially for things like
automating “nice” camera motion between points and viewing directions.