Archive for the ‘Splice’ Category

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");

Fabric splice – push op

Okay, let’s get this party started. Fabric Splice is freakin’ awesome and any studio can get 50 licenses for free.

Here’s the simplest possible deformer that i can possibly think of – the good old “push” operator from softimage. It moves vertices along the point normal.

require Math;
require Geometry;

operator doPushOp<<<index>>>(in Scalar amplitude, io PolygonMesh mesh0){
  Vec3 pos = mesh0.getPointPosition(index);
  Vec3 n  = mesh0.getPointNormal(index);
  Vec3 newPos = pos + (n * amplitude);
  mesh0.setPointPosition(index, newPos);

operator pushop(in Scalar amplitude, io PolygonMesh meshes[]) {
  for (Size i=0; i<meshes.size(); i++) {
    doPushOp<<<meshes[i].pointCount()>>>(amplitude, meshes[i]);

Return top