Skip to content

Commit

Permalink
Add Mesh Motion Blur options to VTK To Blender Mesh (#108)
Browse files Browse the repository at this point in the history
- Thanks to Dominik Werner (dwerner95) for looking up this
  Shape Key animation technique and the initial implementation (#108)!
- Motion Blur option is available in the VTK To Blender Mesh node.
  You need to specify a point vector array name applied for
  motion blur, as well as a time step between frames for
  calculating blur length. Motion blur is calculated for forward
  linear transformation.
- Added optional motion blur to example tree cubeflow_vector_glyphs.
  Enable motion blur for particles mesh to see the effect.
- Bumped version number to 0.11 to mark this new feature.
  • Loading branch information
tkeskita committed Dec 31, 2023
1 parent 7f03c0d commit 7664092
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 2 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
bl_info = {
"name": "BVTKNodes, Blender VTK Nodes",
"author": "BVTKNodes Developers",
"version": (0, 10),
"version": (0, 11),
"blender": (3, 3, 0),
"location": "BVTK Node Tree Editor > New",
"description": "Create and execute VTK pipelines in Blender Node Editor",
Expand Down
112 changes: 112 additions & 0 deletions converters.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .core import *
from .cache import BVTKCache
import bmesh
from vtk.util import numpy_support

try:
import pyopenvdb
Expand Down Expand Up @@ -215,6 +216,57 @@ class BVTK_Node_VTKToBlenderMesh(Node, BVTK_Node):
generate_material: bpy.props.BoolProperty(
name="Generate Material", default=False, update=BVTK_Node.outdate_vtk_status
)
motion_blur: bpy.props.BoolProperty(
name="Motion Blur", default=False, update=BVTK_Node.outdate_vtk_status
)
motion_blur_by: bpy.props.StringProperty(
default="", name="Motion Blur By", update=BVTK_Node.outdate_vtk_status
)
motion_blur_time_step: bpy.props.FloatProperty(
default=1.0,name="Time Step for Motion Blur",update=BVTK_Node.outdate_vtk_status
)

def motion_blur_by_enum_generator(self, context=None):
"""Enum list generator for motion_blur property.
Generate array items available for coloring.
"""

items = [("None", "Empty (clear value)", "Empty (clear value)", ENUM_ICON, 0)]

(
input_node,
vtk_output_obj,
vtk_connection,
) = self.get_input_node_and_output_vtk_objects()
if vtk_output_obj:
if hasattr(vtk_output_obj, "GetPointData"):
p_data = vtk_output_obj.GetPointData()
p_descr = "Color by point data using "
for i in range(p_data.GetNumberOfArrays()):
arr_name = str(p_data.GetArrayName(i))
if p_data.GetArray(i).GetNumberOfComponents() != 3:
continue
items.append(
(
"P_" + arr_name,
arr_name,
p_descr + arr_name + " array",
"VERTEXSEL",
len(items),
)
)
return items

def motion_blur_set_value(self, context=None):
"""Set value of motion_blur_set_value using value from EnumProperty"""
if self.motion_blur_property_list == "None":
self.motion_blur_by = ""
else:
self.motion_blur_by = str(self.motion_blur_property_list)

motion_blur_property_list: bpy.props.EnumProperty(
items=motion_blur_by_enum_generator, update=motion_blur_set_value, name="Choices"
)

def m_properties(self):
return [
Expand All @@ -225,6 +277,9 @@ def m_properties(self):
"smooth",
"recalc_norms",
"generate_material",
"motion_blur",
"motion_blur_by",
"motion_blur_time_step",
]

def m_connections(self):
Expand All @@ -245,6 +300,12 @@ def draw_buttons_special(self, context, layout):
layout.prop(self, "smooth")
layout.prop(self, "recalc_norms")
layout.prop(self, "generate_material")
layout.prop(self, "motion_blur")
if self.motion_blur:
row = layout.row(align=True)
row.prop(self, "motion_blur_by")
row.prop(self, "motion_blur_property_list", icon_only=True)
layout.prop(self,"motion_blur_time_step")
layout.operator("node.bvtk_node_force_update_upstream").node_path = node_path(
self
)
Expand All @@ -269,6 +330,9 @@ def apply_properties_special(self):
recalc_norms=self.recalc_norms,
generate_material=self.generate_material,
color_mapper=color_mapper,
motion_blur=self.motion_blur,
motion_blur_array_name = self.motion_blur_by,
motion_blur_time_step = self.motion_blur_time_step,
)
if val:
self.ui_message = val
Expand Down Expand Up @@ -561,19 +625,29 @@ def vtkdata_to_blender_mesh(
smooth=False,
recalc_norms=False,
generate_material=False,
motion_blur=False,
motion_blur_array_name=None,
motion_blur_time_step=1.0,
):
"""Convert linear and polyhedron VTK cells into a boundary Blender
surface mesh object.
"""

from mathutils import Vector
if not vtk_obj:
return "No VTK object on input"
if issubclass(vtk_obj.__class__, vtk.vtkImageData):
imgdata_to_blender(vtk_obj, name)
return
me, ob = mesh_and_object(name)

if me.is_editmode:
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)

# Initialize the Basis shape key for mesh motion blur
if motion_blur and not ob.data.shape_keys:
ob.shape_key_add(name="Basis", from_mix=False)

# Get all VTK vertex coordinates
data_p = vtk_obj.GetPoints()
vcoords = [data_p.GetPoint(i) for i in range(vtk_obj.GetNumberOfPoints())]
Expand Down Expand Up @@ -628,7 +702,45 @@ def vtkdata_to_blender_mesh(
val = unwrap_and_color_the_mesh(
ob, vtk_obj, name, color_mapper, bm, generate_material, vimap
)

# Mesh motion blur
if motion_blur:
nFrame = bpy.context.scene.frame_current
l.debug("Set up motion blur for frame %d" % nFrame)
if ((not bm.verts.layers.shape.keys()) or \
(not "key_blur" in bm.verts.layers.shape.keys())):
key_shape = bm.verts.layers.shape.new("key_blur")
else:
key_shape = bm.verts.layers.shape["key_blur"]

if len(motion_blur_array_name) < 3:
return "Motion blur array name is wrong (minimum 3 letters)"
array_data = get_vtk_array_data(vtk_obj, motion_blur_array_name[2:], array_type=motion_blur_array_name[0])
if not array_data:
return "Did not find point array %r" % motion_blur_array_name[2:]
array_data = numpy_support.vtk_to_numpy(array_data)

# Calculate shape key coordinates
for i, bv in enumerate(bm.verts):
bv[key_shape] = bv.co + 2.0 * motion_blur_time_step * Vector(array_data[i])

bm.to_mesh(me)

# Add keyframes to shape key Value parameter to animate motion blur
if motion_blur:
ob.data.shape_keys.animation_data_clear()
kb = ob.data.shape_keys.key_blocks["key_blur"]
kb.value = 1.0
kb.keyframe_insert("value",frame=nFrame+1)
kb.value = 0.0
kb.keyframe_insert("value",frame=nFrame-1)
bpy.context.scene.cycles.use_motion_blur = True
bpy.context.scene.eevee.use_motion_blur = True
# Must use "Start on Frame" Position for motion blur to avoid frame changes
bpy.context.scene.cycles.motion_blur_position = "START"
bpy.context.scene.eevee.motion_blur_position = "START"
bpy.context.scene.view_layers.update()

if val:
start_info = "Coloring failed,"
else:
Expand Down
15 changes: 15 additions & 0 deletions docs/BVTKNodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,21 @@ following additions:
upstream nodes and this node. This was added for special cases where
the update system does not detect a possible need for running an
update.
- **Motion Blur**: Boolean option to enable mesh motion blur. If
enabled, the following options become available:
- **Motion Blur By** specifies name of a point vector field (3 value
components) which is to be used for creating pointwise motion
for the mesh. The naming convention is the same used in *Color
Mapper* Node. E.g. value "P_velocity" means that the point vector
field name to be applied is "velocity".
- **Time Step for Motion Blur** specifies the time difference between
two frames. It is used for calculating the length scale of motion blur.

Blender's Motion Blur settings are located in the Render Properties
Panel. The *Position* is set to *Start on Frame* to get correct
blur for rendering an animation. A still example of motion blur is
available in the example node tree *cubeflow_vector_glyphs*. You need
to enable *Motion Blur* in the *Blender To VTK Mesh* Node.

.. image:: images/vtk_to_blender_mesh_node.png

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# The short X.Y version
version = u''
# The full version, including alpha/beta/rc tags
release = u'0.10'
release = u'0.11'


# -- General configuration ---------------------------------------------------
Expand Down
Binary file modified docs/images/vtk_to_blender_mesh_node.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions docs/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ What's New
This information applies to the
`tkeskita/bvtknodes <https://github.com/tkeskita/BVtkNodes>`_ version.

Version 0.11
------------

- 2023-12-31: Motion Blur is available in VTK To Blender Mesh
Node. Mesh motion blur is implemented using Blender Shape
Keys, based on mesh point transformation by a vector point field.

Version 0.10
------------

Expand Down
3 changes: 3 additions & 0 deletions examples/cubeflow_vector_glyphs.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,9 @@
250.0
],
"m_Name": "mesh",
"motion_blur": false,
"motion_blur_by": "P_GlyphVector",
"motion_blur_time_step": 2.0,
"mute": false,
"name": "VTK To Blender Mesh",
"recalc_norms": false,
Expand Down

0 comments on commit 7664092

Please sign in to comment.