0
$\begingroup$

I am currently developing an exporter for FFDs (Lattice). I currently have support for FFDs animated through shape keys but now I have encountered a lattice whose points are driven by another object, rather than being animated itself, e.g. the lattice points’ positions are being driven by hooks (through the hook modifier). These hooks are defined as empty-objects, one for every point in the lattice that should be animated. And the empty-objects are animated by an Armature. With this setup, how can I get the position of a specific lattice point at a specific frame in python?

So far I have found that I’m able to get the target object of a hook modifier through "lattice.modifiers[n].object". Within the object I have also seen that the local and world matrices update with the animation. However I’m not sure how I would know which empty object affects which lattice point. I suppose the empty object’s position and the lattice point are supposed to be at the exact same position, but is that a guarantee? I have been trying to multiply a hook’s local position with its world matrix, but it doesn’t seem match the position I get when de-parenting it from the armature (which it should right?). I have seen that you are able to use "Assign" to assign the hook modifier to specific vertices in Edit Mode, but I don't know how to get this information.

Any comment that can get me in the right direction is greatly appreciated!

Thanks

$\endgroup$
0
$\begingroup$

Depending on how many hooks there are a (probably too tedious solution) would be to create a vertex group containing only that vertex for each hook. Then you can get those from script. Selecting the vertices for a hook modifier has always been an enigma to me, which I don't like.

If any of the hook modifiers has a strength < 1, the method of using it's hook object's location will fail.

A fairly brute force solution can be found here: How do I get the deformed coordinate of a vertex with Python? remember the vertices of a lattice are called points.

A Similarly brute force solution would be to copy your lattice, apply the modifiers, read the applied vert info and then delete the object again.

All those solutions are fairly ugly, but it's all I can come up with atm.

For meshes, bmesh offers a solution of copying the modifier's info to a temp mesh: https://blenderartists.org/t/get-vertices-coordinate-after-deformation/617992 Don't know if you can transfer that to a lattice.

Also: you don't have to multiply .matrix_world with anything. It gives you the absolute position (and loc/rot), no matter what parenting/constraints are influencing it.

$\endgroup$
  • $\begingroup$ Thanks for your answer! When trying to apply modifiers to the lattice I get the error message: "cannot apply modifier for this object type". Unfortunately bmesh does not seem to work with lattices and I don't know of any other addons that does anything similar. I would like to make it work as it currently is, but creating vertex groups might be a way. All hook modifiers have a strength of 1. I will look into this further. I am currently looking further into getting the animated position of an empty. $\endgroup$ – NiklasN Jun 13 '18 at 14:16
  • $\begingroup$ animated position of empties, including constraints and parenting: my_object.matrix_world.to_location() $\endgroup$ – Frederik Steinmetz Jun 16 '18 at 16:43
0
$\begingroup$

I have succeeded in finding a way with the help of Frederik's answer, but it is not very clean. It only works when animating with hooks, the hook strength needs to be 1.0 and the starting position of the hook needs to match that of the lattice point that it should control.

I get all hook modifiers on the lattice (lattice.modifiers[i].type == 'HOOK') and save their position (hookModifier.center) and compare that to each point's position (point.co) in the lattice to know what hookModifier is affecting which point. I'm using math.isclose for each of x, y and z here.

I get the position of the hook for each frame by doing the following:

bpy.context.scene.frame_set(frame)
pos = lattice.matrix_world.inverted() * hook.matrix_world.to_translation()

As I'm exporting the lattice points in local space (and the object's world position, rotation and scale) I have to multiply the hook's world position with the inverse world matrix of the lattice to get it into the lattice local space.

Note that bpy.context.frame_set() is a heavy operation so only use it when necessary.

If any of you have any suggestions on optimizing my solution, please present them.

$\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.