Page MenuHome

Implement a Track Surface constraint
Needs ReviewPublic

Authored by Luca Rood (LucaRood) on Tue, Dec 4, 2:24 PM.
"Love" token, awarded by zeddb."Love" token, awarded by Noss."Love" token, awarded by Tanguy."Yellow Medal" token, awarded by koloved."Love" token, awarded by amonpaike."Love" token, awarded by Arkhangels."Love" token, awarded by LukeD."Love" token, awarded by Scaredyfish."Love" token, awarded by lucky3.



This constraint is like a hybrid between Shrinkwrap and Damped Track, in that it follows a surface like Shrinkwrap, but does not move the object, and instead only rotates it so that an imaginary point a given distance along one axis snaps to the closest point on the surface. When the surface cannot be reached by a rotation, the modifier does nothing (alternatively I could change it to track the closest point on the surface, when out of reach, but the usefulness of this behaviour might be debatable).

I believe the best way to describe it is through a small demo.
In this first gif you can see the default behaviour of the constraint (the tracking point has been set 1m along the Y axis, to coincide with the bone's tail).

The next gif shows face culling behaviour, which allows one side of the surface to be ignored, while snapping to it on the other side (similarly to the Shrinkwrap constraint).

Lastly, one can also limit the rotation of the constraint around a given axis, so that instead of snapping to the closest point on the surface, it finds the closest circle intersection (here the rotation is locked around the Z axis).

I see the use cases for this constraint being mostly in mechanical rigs, where something must slide over a surface while pivoting around a defined point (think linkage suspensions, windscreen wipers, etc.)

To make the implementation as optimal as possible, I extended the functionality of BLI_bvhtree_range_query, to optionally allow matches only on the range surface, instead of the entire volume. This is not a strictly necessary change, but it does eliminate a considerable number of false matches, and the gains here only grow as the mesh becomes more dense (and as the constraint distance parameter becomes larger).

For the case when the axis is locked, only circle intersections need to be matched, but I did not modify the BVH function for this case, as plane/bbox intersections are much more expensive than the usual BVH distance checks. So I deemed the BVH spherical surface search to be optimal enough even for the locked axis case.

Diff Detail

rB Blender

Event Timeline

Luca Rood (LucaRood) planned changes to this revision.Fri, Dec 7, 7:06 PM

I discovered that this isn't working when the target has a scale transformation... I'll fix that as soon as I have some time.

This update fixes/improves several things:

  • Fixed the scaling issue.
  • Improved culling behaviour, which previously suffered from some ambiguity.
  • Implemented auto-detection of bone length, and a reset operator (when used with non-bones, it just resets to a distance of 1.0).
  • Fixed RNA property, which was allowing for negative distances.

For fixing the scaling issue, I had to make some changes to the BVH search code, so that the range query would still be a sphere in global space, even when the target object is unevenly scaled.

In order to avoid having to rebuild a BHV tree in global space all the time, I added support for global space (or any other alternative space) range queries, where normally scaling would distort the range sphere. The method works by passing a transformation matrix to the range query function, and only transforming the resulting BVH distance vector, and not the BVH data itself.

The advantages are:

  • The BVH tree does not have to be reconstructed when the object is transformed, thus enabling the usage of the BVH cache.
  • Only a single transformation operation is performed for each searched node, thus significantly reducing the amount of data to be transformed.

The disadvantage is that this extra transform operation has to be performed each time the query is executed, instead of only once at tree construction, but the cost savings from caching the BVH tree, and from only transforming strictly necessary data should greatly outweigh the extra cost of the matrix multiplication at each query.