Posts Tagged ‘rigging’

Delta mush in Splice

Because all the cool kids are into it, here’s an (early, unoptimised, naive, fairly gnarly) implementation of Delta Mush in Fabric Splice. It’s a regular splice node, not a deformer (still sorting that out).

It takes you from the world’s worst skinning job (on the left), to something that is slightly less awful (on the right).

Tangent space matrix code from Roy Nieterau, relax operator from Phil Taylor.

Update: 9/9/2014 – smoothPos now weights points by distance – end effect is you need fewer smooth iterations.
Update 11/9/2014 – Deltas are now simple vectors. Smooth function now better and faster thanks to exceedingly kind help from Roy Nieterau

require Math;
require Geometry;

operator smoothPos<<<index>>>(Vec3 inPositions[], io Vec3 outPositions[], PolygonMesh mesh) {
  Vec3 result = inPositions[ index ];
  LocalL16UInt32Array surroundingPoints;
  mesh.getPointSurroundingPoints( index, false, surroundingPoints );
  UInt32 nbNei = surroundingPoints.size();
  if( nbNei ) {
    Scalar neiSumDistance = 0;
    Vec3 delta;
    Scalar neiDistance;
    Vec3 toNeighbour;
    for( UInt32 i = 0; i < nbNei; ++i ) {
      UInt32 neiPt = surroundingPoints.get(i);
      toNeighbour = inPositions[ neiPt ] - result; // vector to neighbour
      neiDistance = toNeighbour.length();
      delta += toNeighbour * neiDistance; // weight by distance
      neiSumDistance += neiDistance;
    delta /= (neiSumDistance * nbNei); // divide by sum of all neighbour distances (weighted) and amount of neighbours (average: mean)
    result += delta;
  outPositions[index] = result;

operator relax_operator(in Scalar factor, in Integer iterations, io PolygonMesh mesh0) {

  GeometryAttributes attributes = mesh0.getAttributes();
  Ref<Vec3Attribute> positionsAttr = attributes.getPositions();
  Vec3 positions1[] = positionsAttr.values;
  Vec3 positions2[] = positions1.clone();

  for(Index i = 0; i < iterations; i++){
    smoothPos<<<mesh0.pointCount()>>>(positions1, positions2, mesh0);
    if(i < iterations-1){
      swap(positions1, positions2);
      positionsAttr.values = positions1;
  positionsAttr.values = positions2;
  Ref<Vec3Attribute> normalsAttr = mesh0.getNormals();



function Mat44 tangentSpaceMatrix(PolygonMesh mesh, Index point)
  //Roy Nieterau

  GeometryAttributes attributes = mesh.getAttributes();
  Ref<Vec4Attribute> tangentsAttr = attributes.getAttribute("tangents", Vec4Attribute);
  Vec4 tangents[] = tangentsAttr.values;

  Vec3 pos = mesh.getPointPosition(point);
   Vec3 normal = mesh.getPointNormal(point);
    Vec3 tangent = tangents[point].toVec3();
    Vec3 binormal = normal.cross(tangent);

    Mat44 mat(tangent.x, binormal.x, normal.x, pos.x,
              tangent.y, binormal.y, normal.y, pos.y,
              tangent.z, binormal.z, normal.z, pos.z,
              0       , 0        , 0         , 1    );
    return mat;

operator initialOffest<<<index>>>(in PolygonMesh refMesh, in PolygonMesh refMeshsmooth, 
            io PolygonMesh outMesh, io Vec3 delta[]) {
  Vec3 srcPos = refMesh.getPointPosition(index);
  Vec3 dstPos = refMeshsmooth.getPointPosition(index);

  Vec3 d = srcPos - dstPos;
  Mat44 srcMat = tangentSpaceMatrix(refMeshsmooth, index);

  delta[index] = srcMat.inverse() * d;

operator deformTask<<<index>>>(in PolygonMesh inMesh, io PolygonMesh outMesh,  io Vec3 delta[], in Scalar factor) {

  Vec3 oPos = inMesh.getPointPosition(index);
  Vec3 pos = outMesh.getPointPosition(index);

  Mat44 mat = tangentSpaceMatrix(outMesh, index);

  Vec3 newVec =   mat * delta[index];
  outMesh.setPointPosition(index, oPos.linearInterpolate(newVec, factor));


operator deltaMush(in PolygonMesh inMesh, io PolygonMesh outMesh, in PolygonMesh refMesh, 
                   io PolygonMesh refMeshSmooth, in Integer smoothIterations, in Boolean reset,
                   io Boolean init,
                   in Scalar factor, io Vec3 delta[]) {
  UInt64 start = getCurrentTicks();
  // validation
  if (smoothIterations < 1) {
    outMesh = inMesh.clone();
    setError("need some iterations");
  if (reset == true) {
    init = false;
  outMesh = inMesh.clone();
  if (factor > 0) {
    relax_operator(1.0, smoothIterations, outMesh);

    if(init == false) {
      refMeshSmooth = refMesh.clone();
      relax_operator(1.0, smoothIterations, refMeshSmooth);

      initialOffest<<<refMeshSmooth.pointCount()>>>(refMesh, refMeshSmooth, outMesh, delta);
      init = true;

    deformTask<<<outMesh.pointCount()>>>(inMesh, outMesh, delta, Math_clamp(factor, 0, 1));
  //outMesh = refMeshSmooth;
  UInt64 end = getCurrentTicks();
  //report("Elapsed time: " + getSecondsBetweenTicks(start, end) + " seconds");

From keyframe animation to deform animation in Maya

Usually point caching systems will only deal with objects that are driven by deformation (eg, nCache) – hence the name, point caching. Other bigger, badder systems (eg, alembic) can cope with both transforms and deformations. However, what if you have a transform driven object that you desperately need to export to a point cache?
Read more

Pose driver

In rigging land, and I’m making a rotation driver from built-in maya nodes. This usually drives some front of chain blendshapes (use Chad Vernon’s awesome cvShapeInverter tool) to do corrective blends. This is similar in concept to the Comet poseDeformer.
Read more

Return top