Blender extension¶
The extension consists of:
A panel available in the “Scene” container:
ui.import_trajectory_panel
Two operators that create the static structure of the protein and insert animation frames for the trajectory in
ui.import_pdb_operator
andui.animate_trajectory_operator
.Two custom
UIList
classes that give the user a choice of segmentation, located inui.segmentations_ui_list
.
Main panel¶
The ImportTrajectoryPanel
class has only one entry point, the draw()
method. Its code is fairly straightforward, it goes through the individual visual elements of the panel and creates them in rows and columns. The file inputs it shows are connected to properties on the scene object that are prefixed by ProteinRunway_
. If a segmentation file is added, a callback in the main __init__.py
file triggers the parsing of the file and a new set of global properties are added that drive the drawing of the segmentation UI lists.
An intro to panels: https://docs.blender.org/api/current/bpy.types.Panel.html
Importing the static structure¶
The ImportPDBOperator
class is triggered when the PDB file input in the panel is changed. Its execute
method uses MDAnalysis to parse the file and apply segmentations if those have been set in ProteinRunway_segmentation_*
properties.
Once it collects the parameters it needs, the main method calls the helper draw_alpha_carbons
. That one, in turn, groups the atoms and passes them one domain at a time to draw_domain
.
Once control goes back to execute()
, it triggers the next operator in a slightly special way, by using bpy.ops.protein_runway.animate_trajectory('INVOKE_DEFAULT')
.
A basic explanation of operators: https://docs.blender.org/api/current/bpy.types.Operator.html
Animating the trajectory¶
The AnimateTrajectoryOperator
class is a “modal” operator, which means it’s not meant to be run once and waited, but it activates and responds to events. The documentation example is, in this case, not too helpful, because it describes a case when the operator responds to mouse moves and clicks: https://docs.blender.org/api/current/bpy.types.Operator.html#modal-execution
In our case, there is only one event we care for, a TIMER
event. The reason this is modal is so that it can maintain state between multiple invocations, but those calls are all triggered by a timer on a regular basis.
The code comments in the individual methods should describe how they fulfill the operator’s interface. The bulk of the actual work is done by the insert_frame
method that consults the current state for self.current_frame
and then moves all coordinates of the blender mesh that represents a domain and snapshots them by using keyframe_insert
.
Once a single frame is inserted, a progress bar in the panel is updated by changing another global property, ProteinRunway_progress
.
Choosing the segmentation¶
There is not much meaningful content in the SegmentationMethodsUiList
and SegmentationParamsUiList
classes since their point is to define the shape of data that the segmentation file is parsed into in a way that Blender can access it, and to fulfill the interface of two UIList
classes that show select boxes that depend on each other.
For both lists, the draw_item
method is very simple and only describes a single label. The filter_items
method is what determines what items in the second list will show based on the current selection in the first list. The code is a bit difficult to follow, but it’s hard to structure it in a way that’s more universally readable due to the constraints imposed by Blender’s interfaces.
The official documentation on UI lists provides a large example with many different moving parts: https://docs.blender.org/api/current/bpy.types.UIList.html