1
$\begingroup$

I am trying to render a series of *.vtp files (output of a cfd simulation) in Blender (v2.79). I have successfully installed pip into Blender's python, then using pip, installed vtk (i.e. pip install vtk).

The *.vtp files contain arrays of points that describe the location of particles. So, I create a new object and mesh, read the vtp file, transform the particle coordinates to mesh vertices. I also registered a callback so that when the frame changes, the mesh vertices are replaced with the particle positions in the correct vtp file.

I don't think I am updating the mesh vertices correctly.

I have pieced together the following code by scavenging random posts:

import vtk
from vtk.util import numpy_support
import os
import numpy as np
import bpy
import glob


def new_mesh(objname="MyObject", meshname="mesh"):
    """Create a mew mesh object"""
    mesh = bpy.data.meshes.new(meshname)  # add a new mesh
    obj = bpy.data.objects.new(objname, mesh)  # add a new object using the mesh

    scene = bpy.context.scene
    scene.objects.link(obj)  # put the object into the scene (link)
    scene.objects.active = obj  # set as the active object in the scene
    obj.select = True  # select object

    return mesh


def vtp_to_blender(fname, mesh=None):
    """given a vtp (particle) file, convert the particle positions to a blender
    mesh"""

    # check for file name
    if not os.path.exists(fname):
        print('Warning: file does not exist: {}'.format(fname))
        return

    # get the file name
    objname = os.path.basename(fname)

    # create reader
    reader = vtk.vtkXMLPolyDataReader()
    reader.SetFileName(fname)
    reader.Update()
    poly_data = reader.GetOutput()
    array = numpy_support.vtk_to_numpy(poly_data.GetPoints().GetData())

    if mesh is None:
        mesh = new_mesh(objname, 'points')

    verts = mesh.vertices
    if len(verts) != len(array):
        verts.add(len(array) - len(verts))
    verts.foreach_set('co', array.flatten())
    mesh.update()

def handle_frame_change(scene, mesh, flist):
    """callback to change the vtp file"""
    frame = scene.frame_current
    vtp_to_blender(flist[max(frame-1, 0)], mesh)

def test():
    mesh = new_mesh()
    flist = sorted(glob.glob('path/to/PART_*.vtp'))
    bpy.app.handlers.frame_change_pre.append(lambda scene: handle_frame_change(scene, mesh, flist))

if __name__ == "__main__":
    test()

This all works nicely and the vertices are move when I hit "play". However, I have two problems:

1. If attached a sphere to each vertex by adding a sphere to the scene, setting the parent to the vtp file(s), and selecting duplication -> verts on the parent vtp object, when I hit "play" I get this Traceback:

Traceback (most recent call last):
  File "/Text", line 59, in <lambda>
  File "/Text", line 52, in handle_frame_change
  File "/Text", line 45, in vtp_to_blender
RuntimeError: Error: Cannot add vertices in edit mode

2. If I apply any transforms to the vtp file object and hit "play", the transform persists when the mesh is updated however I occasionally receive segfaults with the following backtrace:

# backtrace
blender-2.79b/blender(BLI_system_backtrace+0x20) [0x1a6c700]
blender-2.79b/blender() [0x1078395]
/lib64/libc.so.6(+0x35270) [0x2b6f8a753270]
blender-2.79b/blender(CustomData_get_active_layer+0x1c) [0x1794e2c]
blender-2.79b/blender(CustomData_bmesh_update_active_layers+0xd5) [0x1796155]
blender-2.79b/blender(BKE_mesh_update_customdata_pointers+0x58) [0x18012a8]
blender-2.79b/blender(ED_mesh_vertices_add+0x16e) [0x12ba99e]
blender-2.79b/blender(RNA_function_call+0x12) [0x190e5d2]
blender-2.79b/blender() [0x1471ef3]
blender-2.79b/blender(PyObject_Call+0x5c) [0x2e4f06c]
blender-2.79b/blender(PyEval_EvalFrameEx+0x3812) [0x2f123a2]
blender-2.79b/blender() [0x2f1869e]
blender-2.79b/blender(PyEval_EvalFrameEx+0x6c8a) [0x2f1581a]
blender-2.79b/blender(PyEval_EvalFrameEx+0x74eb) [0x2f1607b]
blender-2.79b/blender() [0x2f1869e]
blender-2.79b/blender(PyEval_EvalCodeEx+0x23) [0x2f18773]
blender-2.79b/blender() [0x2e79674]
blender-2.79b/blender(PyObject_Call+0x5c) [0x2e4f06c]
blender-2.79b/blender(bpy_app_generic_callback+0x9c) [0x147a01c]
blender-2.79b/blender(BLI_callback_exec+0x2d) [0x1a30f6d]
blender-2.79b/blender(BKE_scene_update_for_newframe_ex+0x52) [0x18765e2]
blender-2.79b/blender(ED_update_for_newframe+0xa6) [0x1361056]
blender-2.79b/blender(wm_event_do_notifiers+0x188) [0x107eb48]
blender-2.79b/blender(WM_main+0x20) [0x1078f80]
blender-2.79b/blender(main+0x3f8) [0x1016a38]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x2b6f8a73fc05]
blender-2.79b/blender() [0x10752ee]
$\endgroup$
0
$\begingroup$

I figured it out! just in case anyone stumbles on this, this trick is to use a temporary bmesh and then to over-write the mesh of the object. So the vtp_to_blender function should be:

def vtp_to_blender(fname, mesh=None):
    """given a vtp (particle) file, convert the particle positions to a blender
    mesh"""

    # make sure we are in object mode
    try:
        bpy.ops.object.mode_set(mode="OBJECT")
    except:
        return

    # check for file name
    if not os.path.exists(fname):
        print('Warning: file does not exist: {}'.format(fname))
        return

    # get the file name
    objname = os.path.basename(fname)

    # create a new mesh if needed
    if mesh is None:
        mesh = new_mesh(objname, 'points')

    # create reader
    reader = vtk.vtkXMLPolyDataReader()
    reader.SetFileName(fname)
    reader.Update()
    poly_data = reader.GetOutput()
    array = numpy_support.vtk_to_numpy(poly_data.GetPoints().GetData())

    # use a temporary mesh to build the vertices
    temp_mesh = bpy.data.meshes.new('temp')  # add a new mesh
    verts = temp_mesh.vertices
    # add the vertices from the vtk reader without looping!
    verts.add(len(array))
    verts.foreach_set('co', array.flatten())

    # create a new bmesh, fill with temp mesh
    bm = bmesh.new()
    bm.from_mesh(temp_mesh)

    # write the bmesh to the object mesh
    bm.to_mesh(mesh)

    # free and update
    bm.free()
    mesh.update()
    bpy.context.scene.update()
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.