diff --git a/__init__.py b/__init__.py index 5e129c1..9423771 100755 --- a/__init__.py +++ b/__init__.py @@ -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", diff --git a/converters.py b/converters.py old mode 100755 new mode 100644 index b7fefd9..7d89159 --- a/converters.py +++ b/converters.py @@ -2,6 +2,7 @@ from .core import * from .cache import BVTKCache import bmesh +from vtk.util import numpy_support try: import pyopenvdb @@ -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 [ @@ -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): @@ -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 ) @@ -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 @@ -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())] @@ -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: diff --git a/docs/BVTKNodes.rst b/docs/BVTKNodes.rst index 416636f..cf30004 100644 --- a/docs/BVTKNodes.rst +++ b/docs/BVTKNodes.rst @@ -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 diff --git a/docs/conf.py b/docs/conf.py index 09b06d1..650c7b0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 --------------------------------------------------- diff --git a/docs/images/vtk_to_blender_mesh_node.png b/docs/images/vtk_to_blender_mesh_node.png index 6b74ff7..c9bcd79 100644 Binary files a/docs/images/vtk_to_blender_mesh_node.png and b/docs/images/vtk_to_blender_mesh_node.png differ diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 906cf99..77296dd 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -6,6 +6,13 @@ What's New This information applies to the `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 ------------ diff --git a/examples/cubeflow_vector_glyphs.json b/examples/cubeflow_vector_glyphs.json index 7b17d67..d124bb1 100644 --- a/examples/cubeflow_vector_glyphs.json +++ b/examples/cubeflow_vector_glyphs.json @@ -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,