8 Skinning

8.7 Application to muscle wrapping

It is sometimes possible to use skinning as a computationally cheaper way to implement muscle wrapping (Chapter 7).

Typically, the end points (i.e., origin and insertion points) of a point-to-point muscle are attached to different bodies. As these bodies move with respect to each other, the path of the muscle may wrap around portions of these bodies and perhaps other intermediate bodies as well. The wrapping mechanism of Chapter 7 manages this by performing the computations necessary to allow one or more wrappable segments of a MultiPointSpring to wrap around a prescribed set of rigid bodies. However, if the induced path deformation is not too great, it may be possible to achieve a similar effect at much lower computational cost by simply “skinning” the via points of the multipoint spring to the underlying rigid bodies.

The general approach involves:

  1. 1.

    Creating a SkinMeshBody which references as master bodies the bodies containing the origin and insertion points, and possibly other bodies as well;

  2. 2.

    Creating the wrapped muscle using a MultiPointSpring with via points that are attached to the skin body.

It should be noted that for this application, the skin body does not need to contain a mesh. Instead, “skinning” connections can be made solely between the master bodies and the via points. An easy way to do this is to simply use skin body markers as via points. Another way is to create the via points as separate particles, and then attach them to the skin body using one of its createPointAttachment methods.

It should also be noted that unlike with the wrapping methods of Chapter 7, skin-based wrapping can be applied around FEM models as well as rigid bodies.

Generally, we observe better wrapping behavior if the frameBlending property of the SkinMeshBody is set to DUAL_QUATERNION_LINEAR instead of the default value of LINEAR.

8.7.1 Example: wrapping for a finger joint

Figure 8.7: PhalanxSkinWrapping model loaded into ArtiSynth and running with no load on the distal bone (left). The pull tool is then used to exert forces on the distal bone and pull it around the joint (middle). The viewer has been set to orthographic projection to enable better visualization of the wrapping behavior of the muscle via points (shown in white). The results appear better when the SkinMeshBody’s frameBlending property is set to DUAL_QUATERNION_LINEAR (middle) instead of LINEAR (right).

An example of skinning-based muscle wrapping is given by artisynth.demos.tutorial.PhalanxSkinWrapping, which is identical to the demo artisynth.demos.tutorial.PhalanxWrapping except for using skinning to achieve the wrapping effect. The portion of the code which differs is shown below:

1       // create a SkinMeshBody and use it to create "skinned" muscle via points
2       SkinMeshBody skinBody = new SkinMeshBody();
3       skinBody.addMasterBody (proximal);
4       skinBody.addMasterBody (distal);
5       skinBody.setFrameBlending (FrameBlending.DUAL_QUATERNION_LINEAR);
6       mech.addMeshBody (skinBody);
7       SkinMarker via1 = skinBody.addMarker (new Point3d (0.0215, 0, -0.015));
8       SkinMarker via2 = skinBody.addMarker (new Point3d (0.025, 0, -0.018));
9       SkinMarker via3 = skinBody.addMarker (new Point3d (0.026, 0, -0.0225));
11       // create a cylindrical mesh around the joint as a visualization aid to
12       // see how well the via points "wrap" as the lower bone moves
13       PolygonalMesh mesh = MeshFactory.createCylinder (
14          /*rad=*/0.0075, /*h=*/0.04, /*nsegs=*/32);
15       FixedMeshBody meshBody = new FixedMeshBody (
16          MeshFactory.createCylinder (/*rad=*/0.0075, /*h=*/0.04, /*nsegs=*/32));
17       meshBody.setPose (TJW);
18       mech.addMeshBody (meshBody);
20       // create a wrappable muscle using a SimpleAxialMuscle material
21       MultiPointSpring muscle = new MultiPointMuscle ("muscle");
22       muscle.setMaterial (
23          new SimpleAxialMuscle (/*k=*/0.5, /*d=*/0, /*maxf=*/0.04));
24       muscle.addPoint (origin);
25       // add via points to the muscle
26       muscle.addPoint (via1);
27       muscle.addPoint (via2);
28       muscle.addPoint (via3);
29       muscle.addPoint (insertion);
30       mech.addMultiPointSpring (muscle);
32       // create control panel to allow frameBlending to be set
33       ControlPanel panel = new ControlPanel();
34       panel.addWidget (skinBody, "frameBlending");
35       addControlPanel (panel);
37       // set render properties
38       RenderProps.setSphericalPoints (mech, 0.002, Color.BLUE);
39       RenderProps.setSphericalPoints (skinBody, 0.002, Color.WHITE);
40       RenderProps.setCylindricalLines (muscle, 0.001, Color.RED);
41       RenderProps.setFaceColor (meshBody, new Color (200, 200, 230));

First, a SkinMeshBody is created referencing the proximal and distal bones as master bodies, with the frameBlending property set to DUAL_QUATERNION_LINEAR (lines 1-6). Next, we create a set of three via points that will be attached to the skin body to guide the muscle around the joint in lieu of making it actually wrap around a cylinder (lines 7-9).

In the original PhalanxWrapping demo, a RigidCylinder was used as a muscle wrap surface. In this demo, we replace this with a simple cylindrical mesh which has no dynamic function but allows us to visualize the wrapping behavior of the via points (lines 11-18). The muscle itself is created using the three via points but with no wrappable segments or bodies (lines 20-30).

A control panel is added to allow for the adjustment of the skin body’s frameBlending property (lines 32-35). Finally, render properties are set as for the original demo, only with the skin body markers rendered as white spheres to make them more visible (lines 37-41).

To run this example in ArtiSynth, select All demos > tutorial > PhalanxSkinWrapping from the Models menu. The model should load and initially appear as in Figure 8.7 (left). The pull tool can then be used to move the distal joint while simulating, to illustrate how well the via points “wrap” around the joint, using the cylindrical mesh as a visual reference (Figure 8.7, middle). Changing the frameBlending property to LINEAR results in a less satisfactory behavior (Figure 8.7, right).