3
$\begingroup$

I have a function looking at a difference in vertex positions, and storing that difference on a third mesh -

def mesh_difference(A, B, difference):
    # Get the objects from the collection using their names
    object_A = bpy.data.objects[A]
    object_B = bpy.data.objects[B]
    object_difference = bpy.data.objects[difference]

    # Get the meshes from the objects
    mesh_A = object_A.data
    mesh_B = object_B.data
    mesh_difference = object_difference.data

    # Get the vertices of each mesh
    verts_A = mesh_A.vertices
    verts_B = mesh_B.vertices
    verts_difference = mesh_difference.vertices

    # Loop through the vertices and calculate the difference in position
    for i in range(len(verts_A)):
        vert_A = verts_A[i]
        vert_B = verts_B[i]
        vert_difference = verts_difference[i]

        # Check if the positions of the vertices are different between mesh_A and mesh_B
        if vert_A.co != vert_B.co:
            # Calculate the difference in position
            diff_x = vert_A.co.x - vert_B.co.x
            diff_y = vert_A.co.y - vert_B.co.y
            diff_z = vert_A.co.z - vert_B.co.z

            # Move the vertex on mesh_difference by the absolute difference in position
            vert_difference.co.x += diff_x
            vert_difference.co.y += diff_y
            vert_difference.co.z += diff_z

While this is working fine, I'd like to explore other options that may be faster or more memory efficient, since for large meshes this is getting a but to slow/heavy. I started looking into numpy, but I'm doing something wrong I think since the function isn't doing anything -

import bpy
import numpy as np

def mesh_difference(object_A_name, object_B_name, object_difference_name):
    # Get the objects from the collection using their names
    object_A = bpy.data.objects[object_A_name]
    object_B = bpy.data.objects[object_B_name]
    object_difference = bpy.data.objects[object_difference_name]

    # Get the meshes from the objects
    mesh_A = object_A.data
    mesh_B = object_B.data
    mesh_difference = object_difference.data

    # Get the vertices of each mesh as numpy arrays
    verts_A = np.array([vert.co for vert in mesh_A.vertices])
    verts_B = np.array([vert.co for vert in mesh_B.vertices])
    verts_difference = np.array([vert.co for vert in mesh_difference.vertices])

    # Calculate the difference in position
    verts_difference -= verts_A - verts_B

Any ideas as of why the numpy function isn't working, or if there are more efficient alternatives to the first option?

A solution using a slightly modified version of a suggestiong from below -

import bpy, numpy as np
from bpy import context as C, data as D


def mesh_difference(A, B, difference):
    ob1 = D.objects[A]
    ob2 = D.objects[B]
    ob3 = D.objects[difference]

    verts1 = ob1.data.vertices
    verts2 = ob2.data.vertices
    verts3 = ob3.data.vertices

    arr1 = np.empty(len(verts1)*3, dtype=float)
    arr2 = np.empty(len(verts2)*3, dtype=float)
    arr3 = np.empty(len(verts2)*3, dtype=float)

    verts1.foreach_get('co', arr1)
    verts2.foreach_get('co', arr2)
    verts3.foreach_get('co', arr3)
    verts3.foreach_set('co', arr3-(arr2 - arr1))
    ob3.data.update()


mesh_difference('A', 'B', 'Cube')

Quite a bit faster -

Time taken: 0.5296132564544678 seconds

Time taken: 0.0469057559967041 seconds

$\endgroup$
1
  • 2
    $\begingroup$ the power of foreach_get $\endgroup$
    – Harry McKenzie
    Commented Jan 19, 2023 at 2:45

1 Answer 1

6
$\begingroup$
import bpy, numpy as np
from bpy import context as C, data as D


def mesh_difference(A, B, difference):
    ob1 = D.objects[A]
    ob2 = D.objects[B]
    ob3 = D.objects[difference]

    verts1 = ob1.data.vertices
    verts2 = ob2.data.vertices
    verts3 = ob3.data.vertices

    arr1 = np.empty(len(verts1)*3, dtype=float)
    arr2 = np.empty(len(verts2)*3, dtype=float)

    verts1.foreach_get('co', arr1)
    verts2.foreach_get('co', arr2)
    verts3.foreach_set('co', arr2 - arr1)
    ob3.data.update()


mesh_difference('Cube', 'Cube.001', 'Cube.002')
$\endgroup$
5
  • $\begingroup$ brilliant! that was the right idea, thank you. I slightly modified it add the deltas to subtract the differences from an existing array (I'll use it for shapekey correctives, so I'd need it to be relative to the existing positions of the 'difference' mesh), but this is what I was looking for. $\endgroup$
    – dan283
    Commented Jan 19, 2023 at 1:39
  • $\begingroup$ foreach_get() sounds like a loop, but internally .. is it just slamming chunks of memory around? .. only if you happen to know,, $\endgroup$
    – Robin Betts
    Commented Jan 19, 2023 at 12:03
  • 1
    $\begingroup$ @RobinBetts I don't know. You're not getting an access to the original data, you get a copy, so it seems it is a loop that copies the data. $\endgroup$ Commented Jan 19, 2023 at 12:45
  • $\begingroup$ memcpy() ? probably not.... $\endgroup$
    – Robin Betts
    Commented Jan 19, 2023 at 14:09
  • 1
    $\begingroup$ @RobinBetts memcpy still will be implemented as a loop, though understandably it can be implemented more efficiently than just a boring loop written by a Blender dev. $\endgroup$ Commented Jan 19, 2023 at 14:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .