# Select vertices, which are affected by a shape key

Is it possible -- without using a previously defined vertex group -- to select those vertice, which are affected by a shape key? How?

• perhaps to make the question clearer, do you mean is it possible to know exactly what vertices are affected by a shape key? I haven't heard of that – moonboots Aug 24 '18 at 7:50

I think a shape key stores the coordinates of any vertex of the mesh, regardless of whether the position has been changed or not. So it seems as if the only way to select vertices affected by the shape key is to individually compare whether the position of the vertices is the same for different shape keys.

import bpy
tolerance = 1e-5
obj = bpy.context.active_object
shape_keys = obj.data.shape_keys.key_blocks
sk1_data = shape_keys['Key 1'].data
skb_data = shape_keys['Basis'].data

bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.select_all(action="DESELECT")
bpy.ops.mesh.select_mode(type="VERT")
bpy.ops.object.mode_set(mode="OBJECT")

for i, (x, y) in enumerate(zip(sk1_data, skb_data)):
if (x.co - y.co).length > tolerance:
obj.data.vertices[i].select = True

bpy.ops.object.mode_set(mode="EDIT")


EDIT: As per batFINGER's suggestion, replaced comparison based on equality with a tolerance based approach.

BMesh version

Using the same principle as @binweg's answer with an edit bmesh

• Shapekey vertex coordinate needs to be further than TOL (local) from vertex coordinate. Always suggest using a tolerance approach when looking at floats, rather than relying on 10.0000000001 == 10 for example.
• The two points of interest are vector coords. Test the length of the vector calcuated from their difference.
• Uses the active shapekey.
• Selected result is those verts further than tolerance from base mesh, IF the shapekey is the solo shape at full value
• For the script to "poll" needs to be run in edit mesh mode. The object must have an active shapekey.

script

import bpy
import bmesh

context = bpy.context
TOL = 1e-5 # tolerance
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)

for v in bm.verts:
bv = me.vertices[v.index]
v.select = (ask.data[v.index].co - bv.co).length > TOL

bmesh.update_edit_mesh(me)

• I might have used this script wrong, but for me this script doesn't work. In edit mode bm's values always seem to be identical to the active shape key's values, so for me there is no selection. Only by replacing v.co with me.vertices[v.index].co or ask.relative_key.data[v.index].co I manage to run it. I appreciate your suggestion of using tolerances. I initially decided against it as I was under the assumption that, even if some coordinates are not exactly integers, when you create a new shape key the value gets copied just like it is. But I guess it's better to be safe than sorry. – binweg Aug 25 '18 at 6:24
• @binweg cheers... Have used the mesh coord as suggested. Forgot the nuances of different bmesh modes. from_edit_mesh vs from_mesh vs from_object. A second non live edit bmesh could be another way to go, but ultimately the mesh vert coord is the go. – batFINGER Aug 25 '18 at 6:54