Skip to content

Commit

Permalink
Fix incorrectly transformed points for GPU blendshapes with no skinning.
Browse files Browse the repository at this point in the history
When the mesh only has blendshapes (no skinning), the deformed point
positions are already in the prim's local space so it's simplest to just
skip applying any additional transforms.

The previous behaviour was incorrect because the final skel space ->
world space -> model space transform expected the points to be in skel
space, which was not the case when only blendshapes were present.
Similarly, the bind transform is only required when skinning is enabled.

The results are now consistent with the CPU skinning computation.

Fixes: #2425
  • Loading branch information
cameronwhite committed Sep 15, 2023
1 parent df0e5a5 commit ecd13d2
Showing 1 changed file with 24 additions and 25 deletions.
49 changes: 24 additions & 25 deletions pxr/usdImaging/usdSkelImaging/shaders/skinning.glslfx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ const float EPS = 1e-5;

void compute(int index)
{
// model space -> bind space
mat4 geomBindXform = HdGet_geomBindXform();

vec3 restP = HdGet_restPoints(index);

// apply blend shapes
Expand All @@ -39,11 +36,14 @@ void compute(int index)
restP += offset.xyz * weight;
}
}
vec4 initP = geomBindXform * vec4(restP, 1);


int numInfluencesPerComponent = HdGet_numInfluencesPerComponent();
vec3 p;
if (numInfluencesPerComponent > 0) {
// model space -> bind space
mat4 geomBindXform = HdGet_geomBindXform();
vec4 initP = geomBindXform * vec4(restP, 1);

p = vec3(0,0,0);

bool constantPointInfluence = HdGet_hasConstantInfluences();
Expand All @@ -60,17 +60,17 @@ void compute(int index)
p += ((skinningXform * initP) * jointWeight).xyz;
}
}

// skel space -> world space -> model space
// XXX: Casts to mat4 below are necessary because the matrices passed
// down use doubles and not floats.
mat4 skelToPrimLocal = mat4( HdGet_primWorldToLocal() ) *
mat4( HdGet_skelLocalToWorld() );
p = (skelToPrimLocal * vec4(p,1)).xyz;
} else {
p = initP.xyz;
p = restP;
}

// skel space -> world space -> model space
// XXX: Casts to mat4 below are necessary because the matrices passed
// down use doubles and not floats.
mat4 skelToPrimLocal = mat4( HdGet_primWorldToLocal() ) *
mat4( HdGet_skelLocalToWorld() );
p = (skelToPrimLocal * vec4(p,1)).xyz;

HdSet_skinnedPoints(index, p);
}

Expand Down Expand Up @@ -135,9 +135,6 @@ vec3 GetDualQuaternionTranslation(vec4 real, vec4 dual)

void compute(int index)
{
// model space -> bind space
mat4 geomBindXform = HdGet_geomBindXform();

vec3 restP = HdGet_restPoints(index);

// apply blend shapes
Expand All @@ -151,11 +148,13 @@ void compute(int index)
restP += offset.xyz * weight;
}
}
vec3 initP = (geomBindXform * vec4(restP, 1)).xyz;

int numInfluencesPerComponent = HdGet_numInfluencesPerComponent();
vec3 p;
if (numInfluencesPerComponent > 0) {
// model space -> bind space
mat4 geomBindXform = HdGet_geomBindXform();
vec3 initP = (geomBindXform * vec4(restP, 1)).xyz;

#ifdef HD_HAS_skinningScaleXforms
vec3 scaledP = vec3(0, 0, 0);
Expand Down Expand Up @@ -220,17 +219,17 @@ void compute(int index)
p = TransformByQuaternion(weightedSumDQReal, initP)
+ GetDualQuaternionTranslation(weightedSumDQReal, weightedSumDQDual);
#endif

// skel space -> world space -> model space
// XXX: Casts to mat4 below are necessary because the matrices passed
// down use doubles and not floats.
mat4 skelToPrimLocal = mat4(HdGet_primWorldToLocal()) *
mat4(HdGet_skelLocalToWorld());
p = (skelToPrimLocal * vec4(p,1)).xyz;
} else {
p = initP;
p = restP;
}

// skel space -> world space -> model space
// XXX: Casts to mat4 below are necessary because the matrices passed
// down use doubles and not floats.
mat4 skelToPrimLocal = mat4(HdGet_primWorldToLocal()) *
mat4(HdGet_skelLocalToWorld());
p = (skelToPrimLocal * vec4(p,1)).xyz;

HdSet_skinnedPoints(index, p);
}

Expand Down

0 comments on commit ecd13d2

Please # to comment.