View Daniel Harjanto's profile on LinkedIn

Instancing without instance

by Daniel Harjanto a.k.a misterdi

This tutorial will discuss on how to instance geometry without using instance, how to implement the concept in making connection for blendshape target.

 

The case

  • I need to create several object that have almost the same geometry, so when I modified the master all duplicates will reflect the changes too. But I also need to have freedom to tweak the duplicates independently.
  • If I use duplicate instance, if I select a component in the model with show affected region on, it also showing it in all other duplicates, and it is a bit annoying.
  • After creating a blendshape, I can not tweak the model. As soon as I move the blendshape slider all the tweaks that I have made was overwritten by the other blendshape target. I need to tweak all my blendshape target to match the tweak that I want since I have to use several blendshape slider at once.

Examining how instance works

When you use Edit->Duplicate Option box and set the option to instance, in the viewport you what you is similar as set the option to copy.

But if look at the outliner and display the shape node you will see that all those duplicate will have same name for the shapenode. But maybe it doesn't tell anything, names doesn't tell anything. Maybe it just a coincidence that they have same name.

So let us inspect the hypergraph, with pCube1, pCube2 and pCube3 selected, open the hypergraph and display input and output Connection.

There are only one shape node shown, it is pCubeShape1, but the colors are not as white/grey color, it has purplish color and several connection to a shading Engine. If you open the connection (double clicking on the arrow), connection editor will be opened and you see those connection is connecting InstObjGroup[] to DagSetMembers[].


Definitely there is only one shape node and all the transform node using this node, which mean if you change the shape node, all instance will have the new shape no matter on which object you do the change. Also if you select one component, all of the instance will show the selected component.

Definitely we can not solve the first case and second case. We cannot modify the instance object without affecting other object. And we need different approach.

 

Passing geometry data.

Fortunately Maya is developed as a node base application where user can define their own flow of data into these nodes. There are several geometry data (attributes) can be used depending of the type of the geometry itself.

inMesh, outMesh, worldMesh for polyMesh objects, or
create, local, worldSpace for NURBS curves and NURBS surface.

Please consult the online manual for description of these attributes.

Let's do an example.

Create polygon Cube and a polygon Sphere, rename the cube to Box and the sphere to Ball. Arrange it so you can see clearly both Box and Ball.

Open Hypergraph, select Box and Ball, and display Input and Output Connection.

From BoxShape is shape node for the Box, and BallShape is shape node for the Ball, both have input connection from polyCube1 (node that create a poly Cube) and polySphere1 (node that create a polySphere).
polyCube1 and polySphere1 ".output" attribute is connected to ".inMesh" of the shape nodes.

Since we have to shape nodes, we can modify the shape (tweaking) independently, but that still does not solve case 1, we need that one shape replicate the other shape.

In this case we want Box to follow Sphere shape, so it should not be a cube anymore but a sphere instead.

In hypergraph drag and drop BallShape (the master) to BoxShape (the slave), and choose Other... when it ask for connection.
A Connection Editor will be opened, with BallShape in Outputs and BoxShape in Inputs.
Scroll down in Outputs to find "outMesh" attributes and scroll down in Inputs to find "inMesh" attributes.
You may find that "inMesh" attributes in Inputs is grey italic, this show that this attribute has an input connection (from polyCube1), but thats is OK since we will overwrite this connection.

Select outMesh from Outputs and then select inMesh from Inputs.

As soon as you click on "inMesh" the Box shape now become a sphere, and also the purple arrow in Hypergraph now pointing from BallShape to BoxShape, BoxShape does not have input connection from polyCube1 anymore.

Now we have to check the condition:

  • If we change the BallShape, will the BoxShape also changed?
  • Can I change the BoxShape without affecting the BallShape?

If both case is true, then we have solved the Case no. 1 and no. 2

Several other thing:

  • Remember BallShape is the master, and BoxShape is the slave (duplicate) in this case
  • For NURBS curve and NURBS surface it is the same workflow, just different attributes.
  • If you need to connect hundreds of shape to the master, it may take sometimes to do manually in the connection editor, use MEL script to help speed things up.
    Command to connect attributes should be `connectAttr`, for example in our example it could be written as:
    • `connectAttr -f BallShape.outMesh BoxShape.inMesh`
      • where BallShape is the master (source attribute) and BoxShape is the slave (destination attribute) and -f was use to force the connection overwriting old connection (from polyCube1).

More generic MEL command could be put in a loop, for example we have an object called as "master" with its shape node called as "masterShape", and we have 10 other slaves called as "slave1", "slave2", ...., "slave10" with its shape node called as "slaveShape1", "slaveShape2", ...., "slaveShape10"

   string $master = "masterShape";
   string $masterAttr = $master + ".outMesh";
   for ($i = 1; $i <= 10; $i++)
   {

        $slaveAttr = "slaveShape" + $i + ".inMesh";
        connectAttr -f $masterAttr $slaveAttr;
   }


We can continue to Case no. 3

 

Implementation in blendShape

In some other software, when you do something like blendShape, and you modify (tweak) the master, all other targets will automatically reflect the modification. For examples if you have 30 or more target shape for facial expression, blendshape has been set with all those Set Driven Key non-sense, and the the director says "Boss, the cheek bone is to high, I want it to be lower a bit, and those forehead is to small, make it bigger, and one more thing that chin is to square, make it round a bit", it would be nice if you can change one master and every target will follow.

Let's take a look how blendShape works in Hypergraph.

For the example I will try to use a very simple geometry, a cube with 2 x 2 x 2 division on each axis, with 3 blendshape target : target1, target2, target3, which is duplicate from the base model and reshape afterward as below:

When you create a blendShape, in hypergraph you will notice there are several other nodes involved, an intermediate object (usually with "Orig" in its name), a tweak node, and ofcourse the blendShape node.

You can tweak the base model as usual in Maya, by pulling or pushing the vertices or even with the artisan brush.

However with the default setup, if you do tweaking the base model, whenever you move any slider in the blendshape editor all the tweak that has been applied on the base model is overwritten by the shape of the blendshape target.And it is normal, since with blendshape, maya will try to reach the target shape when its weight value become 1.0

There is a possibility moving tweak node up to the end of the chain, so you can tweak the final shape without overwritten by the blendShape target.

     swap to     

This will tell Maya, to calculate first the blendshape node and applied the tweak on top of the result. But I don't like the workflow, you can see the effect of the tweak in the blendShape target, which may not be the shape that you want. It's some sort of predicting or extrapolating things when you use this method. The picture shown below is set with blendShape weight for target1 set to 1.0.

Better way, if you tweak the base model and the tweak is carried on onto the blendShape target, and you can then fine tune the blendShape target to the shape you want.

In this case we will you the same concept as previously mention, but we need to connect right attribute in right node.
Assuming we are using polyMesh for base model and its targets, if you connect the intermediate shape outMesh to the inMesh of each targets, then the tweak you do to the base model will not propagate to the targetShape, it's not good.

You should connect the output of the tweak node to the inMesh of the targetShape instead.

With all connection established, now if we modify (tweak) the base model you will see that all blendShape target will also modified. You can see how the tweak will effect the target model, and since both base model got the same tweak, then when you move the slider it will reach the target shape at value of 1.0 of the slider.

When you are happy with all the blendShape targets, then you can simply delete their connection to the tweak node. Since it maintain exact relationship of the tweak in base model and its target shape, you can tweak your model independent of the blendShape target weight value, but it will not obey the weight value for the tweak. It means, when you move those vertices 2 unit down, it will move those corresponding vertices in all target shape 2 unit down also no matter of what value in the blendshape slider. I always try to avoid tweaking the base model with any value of the blendshape slider other than 0.0

Fine tuning the blendshape target after tweaking the base model seems to me can not be avoided, but at least most part of the dirty works have been done by the connection.

 

How do this thing works?

In Maya, when you do tweak on the objects from its creation stage, Maya will store those information in the shape node. For polyMesh for instance, Maya will store information into an array attribute called ".pnts"

  • pnts (pt) float3
    • This attribute is the array of vertex tweaks (relative movements). The attribute values are always significant regardless of whether the object has history or not.
    • pntx (px) distance (float) 0.0cm
      • Vertex position tweak in x.
    • pnty (py) distance (float) 0.0cm
      • Vertex position tweak in y.
    • pntz (pz) distance (float) 0.0cm
      • Vertex position tweak in z.

Tweak outputGeometry is like a layer on top of this information, which mean as long as you have this information than you can do the steps above. This should be reflected in your workflow, the targets are reshape duplicates from the base model. As what the manual said, it is always significant regardless of whether the object has history or not.

Values of this attributes could be seen in the channel box,

This value as default is in relative mode, and measure as distance in each axis.

And next thing to do, how to recover this kind of attribute when it is gone?, exporting object out as an obj and re-importing is definitely destroy this information on top of rearrangement of vertex number which will break the blendshape. It should be possible using MEL script to calculate distances between vertices of base model to the target model, and use this value as the pnts attributes, but it will take sometimes for me to do this. Too bad, I need to do some other works to pay my bill, but hopefully if I got some spare time, I can do R&D on this matter.

<<back>>