Optimizations and cleanup

This commit is contained in:
Anthony J. Thibault 2017-12-22 15:24:54 -08:00
parent e86fd4f992
commit bcd813ac62
7 changed files with 113 additions and 193 deletions

View file

@ -112,9 +112,9 @@ void CauterizedModel::updateClusterMatrices() {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
#if defined(SKIN_DQ)
// AJT: TODO: optimize
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
AnimPose p(m);
state.clusterTransforms[j] = Model::TransformDualQuaternion(m);
#else
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
@ -145,9 +145,9 @@ void CauterizedModel::updateClusterMatrices() {
}
#if defined(SKIN_DQ)
// AJT: TODO: optimize
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
AnimPose p(m);
state.clusterTransforms[j] = Model::TransformDualQuaternion(m);
#else
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
@ -220,7 +220,10 @@ void CauterizedModel::updateRenderItems() {
Transform renderTransform = modelTransform;
if (clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix()));
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(transform);
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
#endif
@ -230,7 +233,10 @@ void CauterizedModel::updateRenderItems() {
renderTransform = modelTransform;
if (clusterTransformsCauterized.size() == 1) {
#if defined(SKIN_DQ)
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix()));
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
#endif

View file

@ -332,7 +332,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
Transform renderTransform = transform;
if (state.clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix()));
Transform transform(state.clusterTransforms[0].getRotation(),
state.clusterTransforms[0].getScale(),
state.clusterTransforms[0].getTranslation());
renderTransform = transform.worldTransform(Transform(transform));
#else
renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0]));
#endif
@ -549,7 +552,10 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Transform
_adjustedLocalBound = _localBound;
if (clusterTransforms.size() > 0) {
#if defined(SKIN_DQ)
_adjustedLocalBound.transform(clusterTransforms[0].getMatrix());
Transform rootTransform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
_adjustedLocalBound.transform(rootTransform);
#else
_adjustedLocalBound.transform(clusterTransforms[0]);
#endif
@ -557,7 +563,10 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Transform
for (int i = 1; i < (int)clusterTransforms.size(); ++i) {
AABox clusterBound = _localBound;
#if defined(SKIN_DQ)
clusterBound.transform(clusterTransforms[i].getMatrix());
Transform transform(clusterTransforms[i].getRotation(),
clusterTransforms[i].getScale(),
clusterTransforms[i].getTranslation());
clusterBound.transform(transform);
#else
clusterBound.transform(clusterTransforms[i]);
#endif

View file

@ -277,7 +277,10 @@ void Model::updateRenderItems() {
Transform renderTransform = modelTransform;
if (clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix()));
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
#endif
@ -1184,6 +1187,7 @@ void Model::updateClusterMatrices() {
const FBXCluster& cluster = mesh.clusters.at(j);
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
#if defined(SKIN_DQ)
// AJT: TODO: optimize
glm::mat4 mat;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat);
state.clusterTransforms[j] = TransformDualQuaternion(mat);

View file

@ -36,14 +36,8 @@
#include "TextureCache.h"
#include "Rig.h"
#define SKIN_ASSERT(cond) \
do { \
if (!(cond)) { \
int* p = 0; \
*p = 0xbadf00d; \
} \
} while(false)
// Use dual quaternion skinning!
// Must match define in Skinning.slh
#define SKIN_DQ
class AbstractViewStateInterface;
@ -275,9 +269,9 @@ public:
_dq = DualQuaternion(rot, trans);
}
glm::vec3 getScale() const { return glm::vec3(_scale); }
glm::quat getRot() const { return _dq.getRotation(); }
glm::vec3 getTrans() const { return _dq.getTranslation(); }
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRot(), getTrans()); };
glm::quat getRotation() const { return _dq.getRotation(); }
glm::vec3 getTranslation() const { return _dq.getTranslation(); }
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRotation(), getTranslation()); };
protected:
glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
DualQuaternion _dq;

View file

@ -11,6 +11,10 @@
<@if not SKINNING_SLH@>
<@def SKINNING_SLH@>
// Use dual quaternion skinning
// Must match #define SKIN_DQ in Model.h
<@def SKIN_DQ@>
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
@ -18,33 +22,46 @@ layout(std140) uniform skinClusterBuffer {
mat4 clusterMatrices[MAX_CLUSTERS];
};
vec4 quatConj(vec4 v) {
return vec4(-v.x, -v.y, -v.z, v.w);
}
vec4 quatMul(vec4 q1, vec4 q2) {
return vec4( q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x,
-q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y,
q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z,
-q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w);
}
vec3 rotateByQuat(vec4 q, vec3 p) {
return vec3(quatMul(quatMul(q, vec4(p.x, p.y, p.z, 0.0)), quatConj(q)));
}
void dqMul(vec4 lhsReal, vec4 lhsImag, vec4 rhsReal, vec4 rhsImag, out vec4 realOut, out vec4 imagOut) {
realOut = quatMul(lhsReal, rhsReal);
imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal);
<@if SKIN_DQ@>
mat4 dualQuatToMat4(vec4 real, vec4 imag) {
float twoRealXSq = 2.0 * real.x * real.x;
float twoRealYSq = 2.0 * real.y * real.y;
float twoRealZSq = 2.0 * real.z * real.z;
float twoRealXY = 2.0 * real.x * real.y;
float twoRealXZ = 2.0 * real.x * real.z;
float twoRealXW = 2.0 * real.x * real.w;
float twoRealZW = 2.0 * real.z * real.w;
float twoRealYZ = 2.0 * real.y * real.z;
float twoRealYW = 2.0 * real.y * real.w;
vec4 col0 = vec4(1.0 - twoRealYSq - twoRealZSq,
twoRealXY + twoRealZW,
twoRealXZ - twoRealYW,
0.0);
vec4 col1 = vec4(twoRealXY - twoRealZW,
1 - twoRealXSq - twoRealZSq,
twoRealYZ + twoRealXW,
0.0);
vec4 col2 = vec4(twoRealXZ + twoRealYW,
twoRealYZ - twoRealXW,
1 - twoRealXSq - twoRealYSq,
0.0);
vec4 col3 = vec4(2.0 * (-imag.w * real.x + imag.x * real.w - imag.y * real.z + imag.z * real.y),
2.0 * (-imag.w * real.y + imag.x * real.z + imag.y * real.w - imag.z * real.x),
2.0 * (-imag.w * real.z - imag.x * real.y + imag.y * real.x + imag.z * real.w),
1.0);
return mat4(col0, col1, col2, col3);
}
// dual quaternion linear blending
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
@ -64,46 +81,20 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
iAccum += imag * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
iAccum /= norm;
float xe = iAccum.x;
float ye = iAccum.y;
float ze = iAccum.z;
float we = iAccum.w;
float x0 = rAccum.x;
float y0 = rAccum.y;
float z0 = rAccum.z;
float w0 = rAccum.w;
float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0);
float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0);
float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0);
vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0,
2.0 * x0 * y0 + 2.0 * w0 * z0,
2.0 * x0 * z0 - 2.0 * w0 * y0,
0.0);
vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0,
1 - 2.0 * x0 * x0 - 2.0 * z0 * z0,
2.0 * y0 * z0 + 2.0 * w0 * x0,
0.0);
vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0,
2.0 * y0 * z0 - 2.0 * w0 * x0,
1 - 2.0 * x0 * x0 - 2.0 * y0 * y0,
0.0);
vec4 col3 = vec4(t0, t1, t2, 1.0);
mat4 m = mat4(col0, col1, col2, col3);
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, iAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
}
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
out vec4 skinnedPosition, out vec3 skinnedNormal) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0);
@ -128,40 +119,13 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
iAccum += imag * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
iAccum /= norm;
float xe = iAccum.x;
float ye = iAccum.y;
float ze = iAccum.z;
float we = iAccum.w;
float x0 = rAccum.x;
float y0 = rAccum.y;
float z0 = rAccum.z;
float w0 = rAccum.w;
float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0);
float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0);
float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0);
vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0,
2.0 * x0 * y0 + 2.0 * w0 * z0,
2.0 * x0 * z0 - 2.0 * w0 * y0,
0.0);
vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0,
1 - 2.0 * x0 * x0 - 2.0 * z0 * z0,
2.0 * y0 * z0 + 2.0 * w0 * x0,
0.0);
vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0,
2.0 * y0 * z0 - 2.0 * w0 * x0,
1 - 2.0 * x0 * x0 - 2.0 * y0 * y0,
0.0);
vec4 col3 = vec4(t0, t1, t2, 1.0);
mat4 m = mat4(col0, col1, col2, col3);
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, iAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
skinnedNormal = vec3(m * vec4(inNormal, 0));
}
@ -169,6 +133,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent,
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0);
@ -193,134 +158,67 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
iAccum += imag * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
iAccum /= norm;
float xe = iAccum.x;
float ye = iAccum.y;
float ze = iAccum.z;
float we = iAccum.w;
float x0 = rAccum.x;
float y0 = rAccum.y;
float z0 = rAccum.z;
float w0 = rAccum.w;
float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0);
float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0);
float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0);
vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0,
2.0 * x0 * y0 + 2.0 * w0 * z0,
2.0 * x0 * z0 - 2.0 * w0 * y0,
0.0);
vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0,
1 - 2.0 * x0 * x0 - 2.0 * z0 * z0,
2.0 * y0 * z0 + 2.0 * w0 * x0,
0.0);
vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0,
2.0 * y0 * z0 - 2.0 * w0 * x0,
1 - 2.0 * x0 * x0 - 2.0 * y0 * y0,
0.0);
vec4 col3 = vec4(t0, t1, t2, 1.0);
mat4 m = mat4(col0, col1, col2, col3);
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, iAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
skinnedNormal = vec3(m * vec4(inNormal, 0));
skinnedTangent = vec3(m * vec4(inTangent, 0));
}
// SKIN_COMP
/*
<@else@> // SKIN_DQ
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec3 tAccum = vec3(0.0, 0.0, 0.0);
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (dot(r, rAccum) < 0) {
r = -r;
}
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
newPosition += clusterMatrix * inPosition * clusterWeight;
}
rAccum = normalize(rAccum);
skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
skinnedPosition = newPosition;
}
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
out vec4 skinnedPosition, out vec3 skinnedNormal) {
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec3 tAccum = vec3(0.0, 0.0, 0.0);
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (dot(r, rAccum) < 0) {
r = -r;
}
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
newPosition += clusterMatrix * inPosition * clusterWeight;
newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
}
rAccum = normalize(rAccum);
skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
skinnedNormal = rotateByQuat(rAccum, inNormal);
skinnedPosition = newPosition;
skinnedNormal = newNormal.xyz;
}
void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent,
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec3 tAccum = vec3(0.0, 0.0, 0.0);
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]);
vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]);
vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]);
if (dot(r, rAccum) < 0) {
r = -r;
}
sAccum += s * clusterWeight;
rAccum += r * clusterWeight;
tAccum += t * clusterWeight;
newPosition += clusterMatrix * inPosition * clusterWeight;
newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight;
}
rAccum = normalize(rAccum);
skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1);
skinnedNormal = rotateByQuat(rAccum, inNormal);
skinnedTangent = rotateByQuat(rAccum, inTangent);
skinnedPosition = newPosition;
skinnedNormal = newNormal.xyz;
skinnedTangent = newTangent.xyz;
}
*/
<@endif@>
<@endif@> // if SKIN_DQ
<@endif@> // if not SKINNING_SLH

View file

@ -52,17 +52,26 @@ void SoftAttachmentModel::updateClusterMatrices() {
// TODO: cache these look-ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
#if defined(SKIN_DQ)
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
#if defined(SKIN_DQ)
// AJT: TODO: OPTIMIZE
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
state.clusterTransforms[j] = Model::TransformDualQuaternion(m);
#else
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
}

View file

@ -58,7 +58,7 @@ public:
_rotation(rotation),
_scale(scale),
_translation(translation),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
_flags(0xf) // FLAG_TRANSLATION | FLAG_ROTATION | FLAG_SCALING | FLAG_NON_UNIFORM
{
if (!isValidScale(_scale)) {
_scale = Vec3(1.0f);