From 565875e823893528184f37649deeaac27b28abd6 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 15 Dec 2017 15:23:10 -0800 Subject: [PATCH 01/43] WIP first attempt at dual quat skinning --- libraries/animation/src/Rig.cpp | 8 + libraries/animation/src/Rig.h | 1 + .../render-utils/src/CauterizedModel.cpp | 49 +++++++ .../render-utils/src/MeshPartPayload.cpp | 6 +- libraries/render-utils/src/Model.cpp | 25 ++++ libraries/render-utils/src/Skinning.slh | 112 ++++++++++---- libraries/shared/src/DualQuaternion.cpp | 81 ++++++++++ libraries/shared/src/DualQuaternion.h | 58 ++++++++ tests/shared/src/DualQuaternionTests.cpp | 138 ++++++++++++++++++ tests/shared/src/DualQuaternionTests.h | 26 ++++ 10 files changed, 475 insertions(+), 29 deletions(-) create mode 100644 libraries/shared/src/DualQuaternion.cpp create mode 100644 libraries/shared/src/DualQuaternion.h create mode 100644 tests/shared/src/DualQuaternionTests.cpp create mode 100644 tests/shared/src/DualQuaternionTests.h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 44745c5c2d..34a3207f47 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1731,6 +1731,14 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { } } +AnimPose Rig::getJointPose(int jointIndex) const { + if (isIndexValid(jointIndex)) { + return _internalPoseSet._absolutePoses[jointIndex]; + } else { + return AnimPose::identity; + } +} + void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { const AnimPose geometryToRigPose(_geometryToRigTransform); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 1ec4d9527f..7d7b55f4a8 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -159,6 +159,7 @@ public: // rig space glm::mat4 getJointTransform(int jointIndex) const; + AnimPose getJointPose(int jointIndex) const; // Start or stop animations as needed. void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index dbb82ab638..36b06b1035 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -9,6 +9,7 @@ #include "CauterizedModel.h" #include +#include #include "AbstractViewStateInterface.h" #include "MeshPartPayload.h" @@ -109,30 +110,78 @@ void CauterizedModel::updateClusterMatrices() { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); + + /* AJT: TODO REMOVE auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); + */ + // AJT: TODO OPTOMIZE + AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); + AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + + // pack scale rotation and translation into a mat4. + state.clusterMatrices[j][0].x = result.scale().x; + state.clusterMatrices[j][0].y = result.scale().y; + state.clusterMatrices[j][0].z = result.scale().z; + + DualQuaternion dq(result.rot(), result.trans()); + state.clusterMatrices[j][1].x = dq.real().x; + state.clusterMatrices[j][1].y = dq.real().y; + state.clusterMatrices[j][1].z = dq.real().z; + state.clusterMatrices[j][1].w = dq.real().w; + state.clusterMatrices[j][2].x = dq.imag().x; + state.clusterMatrices[j][2].y = dq.imag().y; + state.clusterMatrices[j][2].z = dq.imag().z; + state.clusterMatrices[j][2].w = dq.imag().w; } } // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. if (!_cauterizeBoneSet.empty()) { + static const glm::mat4 zeroScale( glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale; + auto cauterizePose = AnimPose(cauterizeMatrix); for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); + + // AJT: TODO REMOVE: + /* auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointMatrix = cauterizeMatrix; } glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); + */ + + auto jointPose = _rig.getJointPose(cluster.jointIndex); + if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { + jointPose = cauterizePose; + } + AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + + // pack scale rotation and translation into a mat4. + state.clusterMatrices[j][0].x = result.scale().x; + state.clusterMatrices[j][0].y = result.scale().y; + state.clusterMatrices[j][0].z = result.scale().z; + + DualQuaternion dq(result.rot(), result.trans()); + state.clusterMatrices[j][1].x = dq.real().x; + state.clusterMatrices[j][1].y = dq.real().y; + state.clusterMatrices[j][1].z = dq.real().z; + state.clusterMatrices[j][1].w = dq.real().w; + state.clusterMatrices[j][2].x = dq.imag().x; + state.clusterMatrices[j][2].y = dq.imag().y; + state.clusterMatrices[j][2].z = dq.imag().z; + state.clusterMatrices[j][2].w = dq.imag().w; } } } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2a59c7d3c5..eb3866df21 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -12,6 +12,7 @@ #include "MeshPartPayload.h" #include +#include #include "DeferredLightingEffect.h" @@ -330,7 +331,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in updateTransform(transform, offsetTransform); Transform renderTransform = transform; if (state.clusterMatrices.size() == 1) { - renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); + // convert form dual quaternion representation to a Transform. + glm::vec3 scale = glm::vec3(state.clusterMatrices[0][0]); + DualQuaternion dq(state.clusterMatrices[0][1], state.clusterMatrices[0][2]); + renderTransform = transform.worldTransform(Transform(dq.getRotation(), scale, dq.getTranslation())); } updateTransformForSkinnedMesh(renderTransform, transform); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b91f4dd405..6ff86516fc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "AbstractViewStateInterface.h" #include "MeshPartPayload.h" @@ -1176,8 +1177,32 @@ void Model::updateClusterMatrices() { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); + + // AJT: TODO REMOVE + /* auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); + */ + AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); + + // AJT: TODO: store inverseBindMatrix as an animpose + // AJT: TODO: optimize AnimPose::operator* + AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + + // pack scale rotation and translation into a mat4. + state.clusterMatrices[j][0].x = result.scale().x; + state.clusterMatrices[j][0].y = result.scale().y; + state.clusterMatrices[j][0].z = result.scale().z; + + DualQuaternion dq(result.rot(), result.trans()); + state.clusterMatrices[j][1].x = dq.real().x; + state.clusterMatrices[j][1].y = dq.real().y; + state.clusterMatrices[j][1].z = dq.real().z; + state.clusterMatrices[j][1].w = dq.real().w; + state.clusterMatrices[j][2].x = dq.imag().x; + state.clusterMatrices[j][2].y = dq.imag().y; + state.clusterMatrices[j][2].z = dq.imag().z; + state.clusterMatrices[j][2].w = dq.imag().w; } } diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 2d1f010029..10dc4042b2 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -18,52 +18,108 @@ layout(std140) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; -void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { - vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); +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); +} + +void blendClusters(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { + vec3 scale = vec3(0.0, 0.0, 0.0); + vec4 dqReal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 dqImag = 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; + + vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); + vec4 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); + vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + + scale += s * clusterWeight; + dqReal += dqr * clusterWeight; + dqImag += dqi * clusterWeight; } - skinnedPosition = newPosition; + scaleOut = scale; + + float dqLen = length(dqReal); + dqReal *= 1.0 / dqLen; + dqImag *= 1.0 / dqLen; + + rotOut = dqReal; + + vec4 invReal = quatConj(dqReal); + posOut.xyz = 2.0 * quatMul(dqImag, invReal).xyz; +} + +void blendClusters_rigid(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { + float maxWeight = 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 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); + vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + + if (clusterWeight > maxWeight) { + maxWeight = clusterWeight; + scaleOut = s; + rotOut = dqr; + vec4 invReal = quatConj(dqr); + posOut = 2.0 * quatMul(dqi, invReal).xyz; + } + } +} + +void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + + vec3 scale, pos; + vec4 rot; + blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); + + skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos; + skinnedPosition.w = 1; } void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { - 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - } + vec3 scale, pos; + vec4 rot; + blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); - skinnedPosition = newPosition; - skinnedNormal = newNormal.xyz; + skinnedNormal.xyz = rotateByQuat(rot, inNormal * scale); } void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { - 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; - } + vec3 scale, pos; + vec4 rot; + blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); - skinnedPosition = newPosition; - skinnedNormal = newNormal.xyz; - skinnedTangent = newTangent.xyz; + skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos; + skinnedPosition.w = 1; + + skinnedNormal = rotateByQuat(rot, inNormal * scale); + skinnedTangent = rotateByQuat(rot, inTangent * scale); } -<@endif@> \ No newline at end of file +<@endif@> diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp new file mode 100644 index 0000000000..3b5aaf6d6d --- /dev/null +++ b/libraries/shared/src/DualQuaternion.cpp @@ -0,0 +1,81 @@ +// +// DualQuaternion.cpp +// +// Created by Anthony J. Thibault on Dec 13th 2017. +// Copyright (c) 2017 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DualQuaternion.h" +#include "GLMHelpers.h" + +// delegating constructor +DualQuaternion::DualQuaternion(const glm::mat4& m) : DualQuaternion(glmExtractRotation(m), extractTranslation(m)) { +} + +DualQuaternion::DualQuaternion(const glm::quat& real, const glm::quat& imag) : _real(real), _imag(imag) { +} + +DualQuaternion::DualQuaternion(const glm::vec4& real, const glm::vec4& imag) : + _real(real.w, real.x, real.y, real.z), + _imag(imag.w, imag.x, imag.y, imag.z) { +} + +DualQuaternion::DualQuaternion(const glm::quat& rotation, const glm::vec3& translation) { + _real = rotation; + _imag = glm::quat(0, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation; +} + +DualQuaternion DualQuaternion::operator*(const DualQuaternion& rhs) const { + return DualQuaternion(_real * rhs._real, _real * rhs._imag + _imag * rhs._real); +} + +DualQuaternion DualQuaternion::operator*(float scalar) const { + return DualQuaternion(_real * scalar, _imag * scalar); +} + +DualQuaternion DualQuaternion::operator+(const DualQuaternion& rhs) const { + return DualQuaternion(_real + rhs._real, _imag + rhs._imag); +} + +glm::vec3 DualQuaternion::xformPoint(const glm::vec3& rhs) const { + DualQuaternion v(glm::quat(), glm::quat(0.0f, rhs.x, rhs.y, rhs.z)); + DualQuaternion dualConj(glm::conjugate(_real), -glm::conjugate(_imag)); + DualQuaternion result = *this * v * dualConj; + return vec3(result._imag.x, result._imag.y, result._imag.z); +} + +glm::quat DualQuaternion::getRotation() const { + return _real; +} + +glm::vec3 DualQuaternion::getTranslation() const { + glm::quat result = 2.0f * (_imag * glm::inverse(_real)); + return glm::vec3(result.x, result.y, result.z); +} + + +glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const { + return _real * rhs; +} + +DualQuaternion DualQuaternion::inverse() const { + glm::quat invReal = glm::inverse(_real); + return DualQuaternion(invReal, - invReal * _imag * invReal); +} + +DualQuaternion DualQuaternion::conjugate() const { + return DualQuaternion(glm::conjugate(_real), glm::conjugate(_imag)); +} + +float DualQuaternion::length() const { + DualQuaternion result = *this * conjugate(); + return sqrtf(result._real.w); +} + +DualQuaternion DualQuaternion::normalize() const { + float invLen = 1.0f / length(); + return *this * invLen; +} diff --git a/libraries/shared/src/DualQuaternion.h b/libraries/shared/src/DualQuaternion.h new file mode 100644 index 0000000000..ed8cdf54ff --- /dev/null +++ b/libraries/shared/src/DualQuaternion.h @@ -0,0 +1,58 @@ +// +// DualQuaternion.h +// +// Created by Anthony J. Thibault on Dec 13th 2017. +// Copyright (c) 2017 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#ifndef hifi_DualQuaternion +#define hifi_DualQuaternion + +#include +#include +#include +#include + +class DualQuaternion { +public: + explicit DualQuaternion(const glm::mat4& m); + DualQuaternion(const glm::quat& real, const glm::quat& imag); + DualQuaternion(const glm::quat& rotation, const glm::vec3& translation); + DualQuaternion(const glm::vec4& real, const glm::vec4& imag); + DualQuaternion operator*(const DualQuaternion& rhs) const; + DualQuaternion operator*(float scalar) const; + DualQuaternion operator+(const DualQuaternion& rhs) const; + + const glm::quat& real() const { return _real; } + glm::quat& real() { return _real; } + + const glm::quat& imag() const { return _imag; } + glm::quat& imag() { return _imag; } + + glm::quat getRotation() const; + glm::vec3 getTranslation() const; + + glm::vec3 xformPoint(const glm::vec3& rhs) const; + glm::vec3 xformVector(const glm::vec3& rhs) const; + + DualQuaternion inverse() const; + DualQuaternion conjugate() const; + float length() const; + DualQuaternion normalize() const; + +protected: + friend QDebug operator<<(QDebug debug, const DualQuaternion& pose); + glm::quat _real; + glm::quat _imag; +}; + +inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) { + debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), imag = (" << dq._imag.x << dq._imag.y << dq._imag.z << dq._imag.w << ")"; + return debug; +} + +#endif diff --git a/tests/shared/src/DualQuaternionTests.cpp b/tests/shared/src/DualQuaternionTests.cpp new file mode 100644 index 0000000000..8187ed78bd --- /dev/null +++ b/tests/shared/src/DualQuaternionTests.cpp @@ -0,0 +1,138 @@ +// +// DualQuaternionTests.cpp +// tests/shared/src +// +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "DualQuaternionTests.h" + +#include +#include +#include +#include + +#include <../GLMTestUtils.h> +#include <../QTestExtensions.h> + +QTEST_MAIN(DualQuaternionTests) + +static void quatComp(const glm::quat& q1, const glm::quat& q2) { + QCOMPARE_WITH_ABS_ERROR(q1.x, q2.x, EPSILON); + QCOMPARE_WITH_ABS_ERROR(q1.y, q2.y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(q1.z, q2.z, EPSILON); + QCOMPARE_WITH_ABS_ERROR(q1.w, q2.w, EPSILON); +} + +void DualQuaternionTests::ctor() { + glm::quat real = angleAxis(PI / 2.0f, Vectors::UNIT_Y); + glm::quat imag(0.0f, 1.0f, 2.0f, 3.0f); + + DualQuaternion dq(real, imag); + quatComp(real, dq.real()); + quatComp(imag, dq.imag()); + + glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X); + glm::vec3 translation(1.0, 2.0f, 3.0f); + dq = DualQuaternion(rotation, translation); + quatComp(rotation, dq.getRotation()); + QCOMPARE_WITH_ABS_ERROR(translation, dq.getTranslation(), EPSILON); + + rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z); + translation = glm::vec3(-1.0, 12.0f, 2.0f); + glm::mat4 m = createMatFromQuatAndPos(rotation, translation); + dq = DualQuaternion(m); + quatComp(rotation, dq.getRotation()); + QCOMPARE_WITH_ABS_ERROR(translation, dq.getTranslation(), EPSILON); +} + +void DualQuaternionTests::mult() { + + glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X); + glm::vec3 translation(1.0, 2.0f, 3.0f); + glm::mat4 m1 = createMatFromQuatAndPos(rotation, translation); + DualQuaternion dq1(m1); + + rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z); + translation = glm::vec3(-1.0, 12.0f, 2.0f); + glm::mat4 m2 = createMatFromQuatAndPos(rotation, translation); + DualQuaternion dq2(m2); + + DualQuaternion dq3 = dq1 * dq2; + glm::mat4 m3 = m1 * m2; + + rotation = glmExtractRotation(m3); + translation = extractTranslation(m3); + + quatComp(rotation, dq3.getRotation()); + QCOMPARE_WITH_ABS_ERROR(translation, dq3.getTranslation(), EPSILON); +} + +void DualQuaternionTests::xform() { + + glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X); + glm::vec3 translation(1.0, 2.0f, 3.0f); + glm::mat4 m1 = createMatFromQuatAndPos(rotation, translation); + DualQuaternion dq1(m1); + + rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z); + translation = glm::vec3(-1.0, 12.0f, 2.0f); + glm::mat4 m2 = createMatFromQuatAndPos(rotation, translation); + DualQuaternion dq2(m2); + + DualQuaternion dq3 = dq1 * dq2; + glm::mat4 m3 = m1 * m2; + + glm::vec3 p(1.0f, 2.0f, 3.0f); + + glm::vec3 p1 = transformPoint(m3, p); + glm::vec3 p2 = dq3.xformPoint(p); + + QCOMPARE_WITH_ABS_ERROR(p1, p2, 0.001f); + + p1 = transformVectorFast(m3, p); + p2 = dq3.xformVector(p); + + QCOMPARE_WITH_ABS_ERROR(p1, p2, 0.001f); +} + +void DualQuaternionTests::trans() { + glm::vec3 t1 = glm::vec3(); + DualQuaternion dq1(Quaternions::IDENTITY, t1); + glm::vec3 t2 = glm::vec3(1.0f, 2.0f, 3.0f); + DualQuaternion dq2(angleAxis(PI / 3.0f, Vectors::UNIT_X), t2); + glm::vec3 t3 = glm::vec3(3.0f, 2.0f, 1.0f); + DualQuaternion dq3(angleAxis(PI / 5.0f, Vectors::UNIT_Y), t3); + + QCOMPARE_WITH_ABS_ERROR(t1, dq1.getTranslation(), 0.001f); + QCOMPARE_WITH_ABS_ERROR(t2, dq2.getTranslation(), 0.001f); + QCOMPARE_WITH_ABS_ERROR(t3, dq3.getTranslation(), 0.001f); +} + +// Dual Quaternion Linear Blending test +void DualQuaternionTests::dlb() { + DualQuaternion dq1(Quaternions::IDENTITY, glm::vec3()); + DualQuaternion dq2(angleAxis(PI / 2.0f, Vectors::UNIT_X), glm::vec3(0.0f, 1.0f, 0.0f)); + + qDebug() << "dq1 =" << dq1; + qDebug() << "dq1.length = " << dq1.length(); + qDebug() << "dq2 =" << dq2; + qDebug() << "dq2.length = " << dq2.length(); + + // linear blend between dq1 and dq2 + DualQuaternion dq3 = dq1 * 0.5f + dq2 * 0.5f; + DualQuaternion dq4 = dq3.normalize(); + + qDebug() << "dq3 =" << dq3; + qDebug() << "dq3.length = " << dq3.length(); + qDebug() << "dq3.trans =" << dq3.getTranslation(); + + qDebug() << "dq4 =" << dq4; + qDebug() << "dq4.length = " << dq4.length(); + qDebug() << "dq4.trans =" << dq4.getTranslation(); +} diff --git a/tests/shared/src/DualQuaternionTests.h b/tests/shared/src/DualQuaternionTests.h new file mode 100644 index 0000000000..988973b689 --- /dev/null +++ b/tests/shared/src/DualQuaternionTests.h @@ -0,0 +1,26 @@ +// +// DualQuaternionTests.h +// tests/shared/src +// +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DualQuaternionTests_h +#define hifi_DualQuaternionTests_h + +#include + +class DualQuaternionTests : public QObject { + Q_OBJECT +private slots: + void ctor(); + void mult(); + void xform(); + void trans(); + void dlb(); +}; + +#endif // hifi_DualQuaternionTests_h From 532c8a23f98f8704ecc32f8769c47d508acfe036 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 15 Dec 2017 15:50:22 -0800 Subject: [PATCH 02/43] tests --- tests/shared/src/DualQuaternionTests.cpp | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/shared/src/DualQuaternionTests.cpp b/tests/shared/src/DualQuaternionTests.cpp index 8187ed78bd..1c34bfbee7 100644 --- a/tests/shared/src/DualQuaternionTests.cpp +++ b/tests/shared/src/DualQuaternionTests.cpp @@ -118,21 +118,30 @@ void DualQuaternionTests::trans() { void DualQuaternionTests::dlb() { DualQuaternion dq1(Quaternions::IDENTITY, glm::vec3()); DualQuaternion dq2(angleAxis(PI / 2.0f, Vectors::UNIT_X), glm::vec3(0.0f, 1.0f, 0.0f)); + DualQuaternion dq2Alt(-angleAxis(PI / 2.0f, Vectors::UNIT_X), glm::vec3(0.0f, 1.0f, 0.0f)); qDebug() << "dq1 =" << dq1; - qDebug() << "dq1.length = " << dq1.length(); qDebug() << "dq2 =" << dq2; - qDebug() << "dq2.length = " << dq2.length(); // linear blend between dq1 and dq2 DualQuaternion dq3 = dq1 * 0.5f + dq2 * 0.5f; - DualQuaternion dq4 = dq3.normalize(); + + // alternate linear blend between dq1 and dq2 + DualQuaternion dq4 = dq1 * 0.5 + dq2Alt * 0.5f; qDebug() << "dq3 =" << dq3; - qDebug() << "dq3.length = " << dq3.length(); - qDebug() << "dq3.trans =" << dq3.getTranslation(); - qDebug() << "dq4 =" << dq4; - qDebug() << "dq4.length = " << dq4.length(); - qDebug() << "dq4.trans =" << dq4.getTranslation(); + + glm::vec3 p1(0.0f, 0.5f, -0.5f); + glm::vec3 p2(0.0f, 0.5f, 0.5f); + + glm::vec3 p3 = dq3.xformPoint(p1); + glm::vec3 p4 = dq3.xformPoint(p2); + glm::vec3 p5 = dq4.xformPoint(p1); + glm::vec3 p6 = dq4.xformPoint(p2); + + qDebug() << "p3 =" << p3; + qDebug() << "p4 =" << p4; + qDebug() << "p5 =" << p5; + qDebug() << "p6 =" << p6; } From 23affb570b1be336a2404ea08fc2df3a78cdbf7c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 18 Dec 2017 15:26:02 -0800 Subject: [PATCH 03/43] WIP checkpoint, root transforms for shapes and non-animated fbx files are working. --- .../render-utils/src/CauterizedModel.cpp | 72 ++++++++++++------ .../render-utils/src/MeshPartPayload.cpp | 26 ++++++- libraries/render-utils/src/Model.cpp | 39 ++++++---- libraries/render-utils/src/Model.h | 11 +++ libraries/render-utils/src/Skinning.slh | 76 ++++++++++++++++++- .../render-utils/src/SoftAttachmentModel.cpp | 29 +++++++ 6 files changed, 207 insertions(+), 46 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 36b06b1035..cba716312a 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -16,7 +16,6 @@ #include "CauterizedMeshPartPayload.h" #include "RenderUtilsLogging.h" - CauterizedModel::CauterizedModel(QObject* parent) : Model(parent) { } @@ -111,11 +110,13 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - /* AJT: TODO REMOVE + /* AJT: TODO REMOVE */ +#ifdef SKIN_MATRIX + SKIN_ASSERT(false); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); - */ - // AJT: TODO OPTOMIZE +#endif +#ifdef SKIN_COMP AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); @@ -124,15 +125,15 @@ void CauterizedModel::updateClusterMatrices() { state.clusterMatrices[j][0].y = result.scale().y; state.clusterMatrices[j][0].z = result.scale().z; - DualQuaternion dq(result.rot(), result.trans()); - state.clusterMatrices[j][1].x = dq.real().x; - state.clusterMatrices[j][1].y = dq.real().y; - state.clusterMatrices[j][1].z = dq.real().z; - state.clusterMatrices[j][1].w = dq.real().w; - state.clusterMatrices[j][2].x = dq.imag().x; - state.clusterMatrices[j][2].y = dq.imag().y; - state.clusterMatrices[j][2].z = dq.imag().z; - state.clusterMatrices[j][2].w = dq.imag().w; + state.clusterMatrices[j][1].x = result.rot().x; + state.clusterMatrices[j][1].y = result.rot().y; + state.clusterMatrices[j][1].z = result.rot().z; + state.clusterMatrices[j][1].w = result.rot().w; + + state.clusterMatrices[j][2].x = result.trans().x; + state.clusterMatrices[j][2].y = result.trans().y; + state.clusterMatrices[j][2].z = result.trans().z; +#endif } } @@ -153,15 +154,16 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); +#ifdef SKIN_MATRIX + SKIN_ASSERT(false); // AJT: TODO REMOVE: - /* auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointMatrix = cauterizeMatrix; } glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); - */ - +#endif +#ifdef SKIN_COMP auto jointPose = _rig.getJointPose(cluster.jointIndex); if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointPose = cauterizePose; @@ -173,15 +175,15 @@ void CauterizedModel::updateClusterMatrices() { state.clusterMatrices[j][0].y = result.scale().y; state.clusterMatrices[j][0].z = result.scale().z; - DualQuaternion dq(result.rot(), result.trans()); - state.clusterMatrices[j][1].x = dq.real().x; - state.clusterMatrices[j][1].y = dq.real().y; - state.clusterMatrices[j][1].z = dq.real().z; - state.clusterMatrices[j][1].w = dq.real().w; - state.clusterMatrices[j][2].x = dq.imag().x; - state.clusterMatrices[j][2].y = dq.imag().y; - state.clusterMatrices[j][2].z = dq.imag().z; - state.clusterMatrices[j][2].w = dq.imag().w; + state.clusterMatrices[j][1].x = result.rot().x; + state.clusterMatrices[j][1].y = result.rot().y; + state.clusterMatrices[j][1].z = result.rot().z; + state.clusterMatrices[j][1].w = result.rot().w; + + state.clusterMatrices[j][2].x = result.trans().x; + state.clusterMatrices[j][2].y = result.trans().y; + state.clusterMatrices[j][2].z = result.trans().z; +#endif } } } @@ -249,13 +251,33 @@ void CauterizedModel::updateRenderItems() { Transform renderTransform = modelTransform; if (clusterMatrices.size() == 1) { +#ifdef SKIN_MATRIX + SKIN_ASSERT(false); renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0])); +#endif +#ifdef SKIN_COMP + glm::vec3 scale(clusterMatrices[0][0]); + glm::quat rot(clusterMatrices[0][1].w, clusterMatrices[0][1].x, clusterMatrices[0][1].y, clusterMatrices[0][1].z); + glm::vec3 trans(clusterMatrices[0][2]); + glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); + renderTransform = modelTransform.worldTransform(Transform(m)); +#endif } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); renderTransform = modelTransform; if (clusterMatricesCauterized.size() == 1) { +#ifdef SKIN_MATRIX + SKIN_ASSERT(false); renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0])); +#endif +#ifdef SKIN_COMP + glm::vec3 scale(clusterMatricesCauterized[0][0]); + glm::quat rot(clusterMatricesCauterized[0][1].w, clusterMatricesCauterized[0][1].x, clusterMatricesCauterized[0][1].y, clusterMatricesCauterized[0][1].z); + glm::vec3 trans(clusterMatricesCauterized[0][2]); + glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); + renderTransform = modelTransform.worldTransform(Transform(m)); +#endif } data.updateTransformForCauterizedMesh(renderTransform); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index eb3866df21..fcf6a61fb5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -331,10 +331,17 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in updateTransform(transform, offsetTransform); Transform renderTransform = transform; if (state.clusterMatrices.size() == 1) { - // convert form dual quaternion representation to a Transform. - glm::vec3 scale = glm::vec3(state.clusterMatrices[0][0]); - DualQuaternion dq(state.clusterMatrices[0][1], state.clusterMatrices[0][2]); - renderTransform = transform.worldTransform(Transform(dq.getRotation(), scale, dq.getTranslation())); +#ifdef SKIN_MATRIX + SKIN_ASSERT(false); + renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); +#endif +#ifdef SKIN_COMP + glm::vec3 scale(state.clusterMatrices[0][0]); + glm::quat rot(state.clusterMatrices[0][1].w, state.clusterMatrices[0][1].x, state.clusterMatrices[0][1].y, state.clusterMatrices[0][1].z); + glm::vec3 trans(state.clusterMatrices[0][2]); + glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); + renderTransform = transform.worldTransform(Transform(m)); +#endif } updateTransformForSkinnedMesh(renderTransform, transform); @@ -549,7 +556,18 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector maxWeight) { + maxWeight = clusterWeight; + scaleOut = s; + rotOut = r; + posOut = t; + } + } +} + void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { vec3 scale, pos; @@ -121,5 +143,55 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v skinnedTangent = rotateByQuat(rot, inTangent * scale); } +// ORIGINAL +/* +void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + 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]; + newPosition += clusterMatrix * inPosition * clusterWeight; + } + + skinnedPosition = newPosition; +} + +void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, + out vec4 skinnedPosition, out vec3 skinnedNormal) { + 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]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + } + + 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) { + 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]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; + } + + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; + skinnedTangent = newTangent.xyz; +} +*/ + <@endif@> diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 63991f9422..7d49a8cda1 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -50,6 +50,7 @@ void SoftAttachmentModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); +#ifdef SKIN_MATRIX // TODO: cache these look-ups as an optimization int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); glm::mat4 jointMatrix; @@ -58,7 +59,35 @@ void SoftAttachmentModel::updateClusterMatrices() { } else { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } + SKIN_ASSERT(false); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); +#endif +#ifdef SKIN_COMP + // TODO: cache these look-ups as an optimization + int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); + AnimPose jointPose; + if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { + jointPose = _rigOverride.getJointPose(jointIndexOverride); + } else { + jointPose = _rig.getJointPose(cluster.jointIndex); + } + AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + + // pack scale rotation and translation into a mat4. + state.clusterMatrices[j][0].x = result.scale().x; + state.clusterMatrices[j][0].y = result.scale().y; + state.clusterMatrices[j][0].z = result.scale().z; + + state.clusterMatrices[j][1].x = result.rot().x; + state.clusterMatrices[j][1].y = result.rot().y; + state.clusterMatrices[j][1].z = result.rot().z; + state.clusterMatrices[j][1].w = result.rot().w; + + state.clusterMatrices[j][2].x = result.trans().x; + state.clusterMatrices[j][2].y = result.trans().y; + state.clusterMatrices[j][2].z = result.trans().z; +#endif + } } From 515d13a4c15297cf1f75820aa59aba72cf3c0e40 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 18 Dec 2017 17:51:14 -0800 Subject: [PATCH 04/43] WIP checkpoint --- interface/src/avatar/MyAvatar.cpp | 7 ++- libraries/animation/src/AnimPose.cpp | 23 +++++++++ libraries/animation/src/AnimPose.h | 2 + .../render-utils/src/CauterizedModel.cpp | 50 ++++++++++++++++++- 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 02a1959a95..0fd7f7f012 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1820,7 +1820,8 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) { initHeadBones(); - _skeletonModel->setCauterizeBoneSet(_headBoneSet); + // AJT HACK DISABLE CAUTERIZE + //_skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); _isAnimatingScale = true; @@ -1912,7 +1913,9 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { // toggle using the cauterizedBones depending on where the camera is and the rendering pass type. const bool shouldDrawHead = shouldRenderHead(renderArgs); if (shouldDrawHead != _prevShouldDrawHead) { - _skeletonModel->setEnableCauterization(!shouldDrawHead); + // AJT: DISABLE CAUTER + // _skeletonModel->setEnableCauterization(!shouldDrawHead); + _skeletonModel->setEnableCauterization(false); for (int i = 0; i < _attachmentData.size(); i++) { if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 || diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 470bbab8b6..29c4c46d6e 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -69,6 +69,27 @@ AnimPose AnimPose::mirror() const { return AnimPose(_scale, glm::quat(_rot.w, _rot.x, -_rot.y, -_rot.z), glm::vec3(-_trans.x, _trans.y, _trans.z)); } +bool AnimPose::fuzzyEqual(const AnimPose& rhs) const { + const float SCALE_EPSILON = 0.00001f; + const float ROT_EPSILON = 0.00001f; + const float TRANS_EPSILON = 0.001f; + if ((fabsf(rhs._scale.x - _scale.x) < SCALE_EPSILON) && + (fabsf(rhs._scale.y - _scale.y) < SCALE_EPSILON) && + (fabsf(rhs._scale.z - _scale.z) < SCALE_EPSILON)) { + if ((fabsf(rhs._rot.x - _rot.x) < ROT_EPSILON) && + (fabsf(rhs._rot.y - _rot.y) < ROT_EPSILON) && + (fabsf(rhs._rot.z - _rot.z) < ROT_EPSILON) && + (fabsf(rhs._rot.w - _rot.w) < ROT_EPSILON)) { + if ((fabsf(rhs._trans.x - _trans.x) < TRANS_EPSILON) && + (fabsf(rhs._trans.y - _trans.y) < TRANS_EPSILON) && + (fabsf(rhs._trans.z - _trans.z) < TRANS_EPSILON)) { + return true; + } + } + } + return false; +} + AnimPose::operator glm::mat4() const { glm::vec3 xAxis = _rot * glm::vec3(_scale.x, 0.0f, 0.0f); glm::vec3 yAxis = _rot * glm::vec3(0.0f, _scale.y, 0.0f); @@ -76,3 +97,5 @@ AnimPose::operator glm::mat4() const { return glm::mat4(glm::vec4(xAxis, 0.0f), glm::vec4(yAxis, 0.0f), glm::vec4(zAxis, 0.0f), glm::vec4(_trans, 1.0f)); } + + diff --git a/libraries/animation/src/AnimPose.h b/libraries/animation/src/AnimPose.h index 2df3d1f2e4..0f29bac7ce 100644 --- a/libraries/animation/src/AnimPose.h +++ b/libraries/animation/src/AnimPose.h @@ -46,6 +46,8 @@ public: const glm::vec3& trans() const { return _trans; } glm::vec3& trans() { return _trans; } + bool fuzzyEqual(const AnimPose& rhs) const; + private: friend QDebug operator<<(QDebug debug, const AnimPose& pose); glm::vec3 _scale { 1.0f }; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index cba716312a..282aedf180 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -104,6 +104,12 @@ void CauterizedModel::updateClusterMatrices() { _needsUpdateClusterMatrices = false; const FBXGeometry& geometry = getFBXGeometry(); + bool debug = false; + + if (debug) { + qDebug() << "AJT: CauterizedModel::updateClusterMatrices(), url =" << _url; + } + for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -117,8 +123,14 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); #endif #ifdef SKIN_COMP + + if (debug) { + qDebug() << "AJT: _meshState[" << i << "], cluster[" << j << "]"; + } + AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + result.rot() = glm::normalize(result.rot()); // pack scale rotation and translation into a mat4. state.clusterMatrices[j][0].x = result.scale().x; @@ -133,6 +145,18 @@ void CauterizedModel::updateClusterMatrices() { state.clusterMatrices[j][2].x = result.trans().x; state.clusterMatrices[j][2].y = result.trans().y; state.clusterMatrices[j][2].z = result.trans().z; + + // AJT REMOVE + if (debug) { + glm::mat4 jointMatrix = _rig.getJointTransform(cluster.jointIndex); + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + qDebug() << "AJT: m =" << m; + qDebug() << "AJT: (AnimPose)m =" << AnimPose(m); + qDebug() << "AJT: result =" << result; + qDebug() << "AJT: (mat4)result =" << (glm::mat4)result; + SKIN_ASSERT(result.fuzzyEqual(AnimPose(m))); + } #endif } } @@ -146,7 +170,6 @@ void CauterizedModel::updateClusterMatrices() { glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale; - auto cauterizePose = AnimPose(cauterizeMatrix); for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; @@ -164,11 +187,19 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); #endif #ifdef SKIN_COMP + + if (debug) { + qDebug() << "AJT: CAUTERIZED _meshState[" << i << "], cluster[" << j << "]"; + } + auto jointPose = _rig.getJointPose(cluster.jointIndex); + /* if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointPose = cauterizePose; } + */ AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); + result.rot() = glm::normalize(result.rot()); // pack scale rotation and translation into a mat4. state.clusterMatrices[j][0].x = result.scale().x; @@ -183,6 +214,23 @@ void CauterizedModel::updateClusterMatrices() { state.clusterMatrices[j][2].x = result.trans().x; state.clusterMatrices[j][2].y = result.trans().y; state.clusterMatrices[j][2].z = result.trans().z; + + // AJT REMOVE + auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); + /* + if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { + jointMatrix = cauterizeMatrix; + } + */ + if (debug) { + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + qDebug() << "AJT: m =" << m; + qDebug() << "AJT: (AnimPose)m =" << AnimPose(m); + qDebug() << "AJT: result =" << result; + qDebug() << "AJT: (mat4)result =" << (glm::mat4)result; + SKIN_ASSERT(result.fuzzyEqual(AnimPose(m))); + } #endif } } From 18113d824c3f8c8340c6affc67c8bbf997728452 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 19 Dec 2017 15:57:06 -0800 Subject: [PATCH 05/43] Created Model::TransformComponents class --- .../src/CauterizedMeshPartPayload.cpp | 30 +++- .../src/CauterizedMeshPartPayload.h | 7 +- .../render-utils/src/CauterizedModel.cpp | 139 ++++------------- .../render-utils/src/MeshPartPayload.cpp | 83 ++++++----- libraries/render-utils/src/MeshPartPayload.h | 10 +- libraries/render-utils/src/Model.cpp | 53 ++----- libraries/render-utils/src/Model.h | 45 +++++- libraries/render-utils/src/Skinning.slh | 140 ++++++++---------- .../render-utils/src/SoftAttachmentModel.cpp | 34 +---- 9 files changed, 237 insertions(+), 304 deletions(-) diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 396cd13508..c64c98b271 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -20,19 +20,35 @@ using namespace render; CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} -void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterMatrices, const std::vector& cauterizedClusterMatrices) { - ModelMeshPartPayload::updateClusterBuffer(clusterMatrices); +#ifdef SKIN_COMP +void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms) { + ModelMeshPartPayload::updateClusterBuffer(clusterTransforms); - if (cauterizedClusterMatrices.size() > 1) { + if (cauterizedClusterTransforms.size() > 1) { if (!_cauterizedClusterBuffer) { - _cauterizedClusterBuffer = std::make_shared(cauterizedClusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) cauterizedClusterMatrices.data()); + _cauterizedClusterBuffer = std::make_shared(cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents), + (const gpu::Byte*) cauterizedClusterTransforms.data()); } else { - _cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) cauterizedClusterMatrices.data()); + _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents), + (const gpu::Byte*) cauterizedClusterTransforms.data()); } } } +#else +void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms) { + ModelMeshPartPayload::updateClusterBuffer(clusterTransforms); + + if (cauterizedClusterTransforms.size() > 1) { + if (!_cauterizedClusterBuffer) { + _cauterizedClusterBuffer = std::make_shared(cauterizedClusterTransforms.size() * sizeof(glm::mat4), + (const gpu::Byte*) cauterizedClusterTransforms.data()); + } else { + _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(glm::mat4), + (const gpu::Byte*) cauterizedClusterTransforms.data()); + } + } +} +#endif void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) { _cauterizedTransform = renderTransform; diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 44eddc6e31..1ee77c300f 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -14,8 +14,11 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { public: CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); - - void updateClusterBuffer(const std::vector& clusterMatrices, const std::vector& cauterizedClusterMatrices); +#ifdef SKIN_COMP + void updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms); +#else + void updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms); +#endif void updateTransformForCauterizedMesh(const Transform& renderTransform); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 282aedf180..606e1f0351 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -35,7 +35,7 @@ bool CauterizedModel::updateGeometry() { const FBXGeometry& fbxGeometry = getFBXGeometry(); foreach (const FBXMesh& mesh, fbxGeometry.meshes) { Model::MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); + state.clusterTransforms.resize(mesh.clusters.size()); _cauterizeMeshStates.append(state); } } @@ -116,47 +116,14 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - /* AJT: TODO REMOVE */ -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); -#endif #ifdef SKIN_COMP - - if (debug) { - qDebug() << "AJT: _meshState[" << i << "], cluster[" << j << "]"; - } - - AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); - AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); - result.rot() = glm::normalize(result.rot()); - - // pack scale rotation and translation into a mat4. - state.clusterMatrices[j][0].x = result.scale().x; - state.clusterMatrices[j][0].y = result.scale().y; - state.clusterMatrices[j][0].z = result.scale().z; - - state.clusterMatrices[j][1].x = result.rot().x; - state.clusterMatrices[j][1].y = result.rot().y; - state.clusterMatrices[j][1].z = result.rot().z; - state.clusterMatrices[j][1].w = result.rot().w; - - state.clusterMatrices[j][2].x = result.trans().x; - state.clusterMatrices[j][2].y = result.trans().y; - state.clusterMatrices[j][2].z = result.trans().z; - - // AJT REMOVE - if (debug) { - glm::mat4 jointMatrix = _rig.getJointTransform(cluster.jointIndex); - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - qDebug() << "AJT: m =" << m; - qDebug() << "AJT: (AnimPose)m =" << AnimPose(m); - qDebug() << "AJT: result =" << result; - qDebug() << "AJT: (mat4)result =" << (glm::mat4)result; - SKIN_ASSERT(result.fuzzyEqual(AnimPose(m))); - } + // AJT: TODO: optimize + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + state.clusterTransforms[j] = Model::TransformComponents(m); +#else + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } } @@ -177,60 +144,18 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - // AJT: TODO REMOVE: auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointMatrix = cauterizeMatrix; } - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); -#endif + #ifdef SKIN_COMP - - if (debug) { - qDebug() << "AJT: CAUTERIZED _meshState[" << i << "], cluster[" << j << "]"; - } - - auto jointPose = _rig.getJointPose(cluster.jointIndex); - /* - if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { - jointPose = cauterizePose; - } - */ - AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); - result.rot() = glm::normalize(result.rot()); - - // pack scale rotation and translation into a mat4. - state.clusterMatrices[j][0].x = result.scale().x; - state.clusterMatrices[j][0].y = result.scale().y; - state.clusterMatrices[j][0].z = result.scale().z; - - state.clusterMatrices[j][1].x = result.rot().x; - state.clusterMatrices[j][1].y = result.rot().y; - state.clusterMatrices[j][1].z = result.rot().z; - state.clusterMatrices[j][1].w = result.rot().w; - - state.clusterMatrices[j][2].x = result.trans().x; - state.clusterMatrices[j][2].y = result.trans().y; - state.clusterMatrices[j][2].z = result.trans().z; - - // AJT REMOVE - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); - /* - if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { - jointMatrix = cauterizeMatrix; - } - */ - if (debug) { - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - qDebug() << "AJT: m =" << m; - qDebug() << "AJT: (AnimPose)m =" << AnimPose(m); - qDebug() << "AJT: result =" << result; - qDebug() << "AJT: (mat4)result =" << (glm::mat4)result; - SKIN_ASSERT(result.fuzzyEqual(AnimPose(m))); - } + // AJT: TODO: optimize + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + state.clusterTransforms[j] = Model::TransformComponents(m); +#else + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } } @@ -288,43 +213,31 @@ void CauterizedModel::updateRenderItems() { auto itemID = self->_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; - auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); - auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices); + auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms); + auto clusterTransformsCauterized(self->getCauterizeMeshState(meshIndex).clusterTransforms); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey, + transaction.updateItem(itemID, [modelTransform, clusterTransforms, clusterTransformsCauterized, invalidatePayloadShapeKey, isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { - data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized); + data.updateClusterBuffer(clusterTransforms, clusterTransformsCauterized); Transform renderTransform = modelTransform; - if (clusterMatrices.size() == 1) { -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0])); -#endif + if (clusterTransforms.size() == 1) { #ifdef SKIN_COMP - glm::vec3 scale(clusterMatrices[0][0]); - glm::quat rot(clusterMatrices[0][1].w, clusterMatrices[0][1].x, clusterMatrices[0][1].y, clusterMatrices[0][1].z); - glm::vec3 trans(clusterMatrices[0][2]); - glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); - renderTransform = modelTransform.worldTransform(Transform(m)); + renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); +#else + renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); #endif } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); renderTransform = modelTransform; - if (clusterMatricesCauterized.size() == 1) { -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0])); -#endif + if (clusterTransformsCauterized.size() == 1) { #ifdef SKIN_COMP - glm::vec3 scale(clusterMatricesCauterized[0][0]); - glm::quat rot(clusterMatricesCauterized[0][1].w, clusterMatricesCauterized[0][1].x, clusterMatricesCauterized[0][1].y, clusterMatricesCauterized[0][1].z); - glm::vec3 trans(clusterMatricesCauterized[0][2]); - glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); - renderTransform = modelTransform.worldTransform(Transform(m)); + renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix())); +#else + renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); #endif } data.updateTransformForCauterizedMesh(renderTransform); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index fcf6a61fb5..3056dbc728 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -326,22 +326,17 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); - computeAdjustedLocalBound(state.clusterMatrices); + computeAdjustedLocalBound(state.clusterTransforms); updateTransform(transform, offsetTransform); Transform renderTransform = transform; - if (state.clusterMatrices.size() == 1) { -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); -#endif + if (state.clusterTransforms.size() == 1) { #ifdef SKIN_COMP - glm::vec3 scale(state.clusterMatrices[0][0]); - glm::quat rot(state.clusterMatrices[0][1].w, state.clusterMatrices[0][1].x, state.clusterMatrices[0][1].y, state.clusterMatrices[0][1].z); - glm::vec3 trans(state.clusterMatrices[0][2]); - glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); - renderTransform = transform.worldTransform(Transform(m)); + renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix())); +#else + renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0])); #endif + } updateTransformForSkinnedMesh(renderTransform, transform); @@ -371,20 +366,36 @@ void ModelMeshPartPayload::notifyLocationChanged() { } - -void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterMatrices) { +#ifdef SKIN_COMP +void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms) { // Once computed the cluster matrices, update the buffer(s) - if (clusterMatrices.size() > 1) { + if (clusterTransforms.size() > 1) { if (!_clusterBuffer) { - _clusterBuffer = std::make_shared(clusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) clusterMatrices.data()); + _clusterBuffer = std::make_shared(clusterTransforms.size() * sizeof(Model::TransformComponents), + (const gpu::Byte*) clusterTransforms.data()); } else { - _clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4), - (const gpu::Byte*) clusterMatrices.data()); + _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(Model::TransformComponents), + (const gpu::Byte*) clusterTransforms.data()); } } } +#else +void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms) { + // Once computed the cluster matrices, update the buffer(s) + if (clusterTransforms.size() > 1) { + if (!_clusterBuffer) { + _clusterBuffer = std::make_shared(clusterTransforms.size() * sizeof(glm::mat4), + (const gpu::Byte*) clusterTransforms.data()); + } + else { + _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(glm::mat4), + (const gpu::Byte*) clusterTransforms.data()); + } + } +} +#endif + void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) { _transform = renderTransform; @@ -550,23 +561,27 @@ void ModelMeshPartPayload::render(RenderArgs* args) { args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } -void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterMatrices) { - _adjustedLocalBound = _localBound; - if (clusterMatrices.size() > 0) { - _adjustedLocalBound.transform(clusterMatrices[0]); - for (int i = 1; i < (int)clusterMatrices.size(); ++i) { - AABox clusterBound = _localBound; -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - clusterBound.transform(clusterMatrices[i]); -#endif #ifdef SKIN_COMP - // AJT: FIXME: TODO: SLOW AS SHIT - glm::vec3 scale(clusterMatrices[i][0]); - glm::quat rot(clusterMatrices[i][1].w, clusterMatrices[i][1].x, clusterMatrices[i][1].y, clusterMatrices[i][1].z); - glm::vec3 trans(clusterMatrices[i][2]); - glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); - clusterBound.transform(m); +void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { +#else +void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { +#endif + _adjustedLocalBound = _localBound; + if (clusterTransforms.size() > 0) { +#ifdef SKIN_COMP + // AJT: TODO: optimize + _adjustedLocalBound.transform(clusterTransforms[0].getMatrix()); +#else + _adjustedLocalBound.transform(clusterTransforms[0]); +#endif + + for (int i = 1; i < (int)clusterTransforms.size(); ++i) { + AABox clusterBound = _localBound; +#ifdef SKIN_COMP + // AJT: TODO: optimize + clusterBound.transform(clusterTransforms[i].getMatrix()); +#else + clusterBound.transform(clusterTransforms[i]); #endif _adjustedLocalBound += clusterBound; } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index fb55883101..989a653b2f 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -87,7 +87,11 @@ public: typedef Payload::DataPointer Pointer; void notifyLocationChanged() override; - void updateClusterBuffer(const std::vector& clusterMatrices); +#ifdef SKIN_COMP + void updateClusterBuffer(const std::vector& clusterTransforms); +#else + void updateClusterBuffer(const std::vector& clusterTransforms); +#endif void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); // Render Item interface @@ -104,7 +108,11 @@ public: void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; +#ifdef SKIN_COMP + void computeAdjustedLocalBound(const std::vector& clusterTransforms); +#else void computeAdjustedLocalBound(const std::vector& clusterMatrices); +#endif gpu::BufferPointer _clusterBuffer; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 36d26dea7b..0f014032a3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -266,25 +266,20 @@ void Model::updateRenderItems() { auto itemID = self->_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; - auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); + auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey, + transaction.updateItem(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey, isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateClusterBuffer(clusterMatrices); + data.updateClusterBuffer(clusterTransforms); + Transform renderTransform = modelTransform; - if (clusterMatrices.size() == 1) { -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); - renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0])); -#endif + if (clusterTransforms.size() == 1) { #ifdef SKIN_COMP - glm::vec3 scale(clusterMatrices[0][0]); - glm::quat rot(clusterMatrices[0][1].w, clusterMatrices[0][1].x, clusterMatrices[0][1].y, clusterMatrices[0][1].z); - glm::vec3 trans(clusterMatrices[0][2]); - glm::mat4 m = createMatFromScaleQuatAndPos(scale, rot, trans); - renderTransform = modelTransform.worldTransform(Transform(m)); + renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); +#else + renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); #endif } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); @@ -338,7 +333,7 @@ bool Model::updateGeometry() { const FBXGeometry& fbxGeometry = getFBXGeometry(); foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); + state.clusterTransforms.resize(mesh.clusters.size()); _meshStates.push_back(state); // Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index @@ -1169,7 +1164,7 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { void Model::computeMeshPartLocalBounds() { for (auto& part : _modelMeshRenderItems) { const Model::MeshState& state = _meshStates.at(part->_meshIndex); - part->computeAdjustedLocalBound(state.clusterMatrices); + part->computeAdjustedLocalBound(state.clusterTransforms); } } @@ -1187,30 +1182,14 @@ void Model::updateClusterMatrices() { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - - // AJT: TODO FIXME -#ifdef SKIN_MATRIX - SKIN_ASSERT(false); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); -#endif #ifdef SKIN_COMP - AnimPose jointPose = _rig.getJointPose(cluster.jointIndex); - AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); - - // pack scale rotation and translation into a mat4. - state.clusterMatrices[j][0].x = result.scale().x; - state.clusterMatrices[j][0].y = result.scale().y; - state.clusterMatrices[j][0].z = result.scale().z; - - state.clusterMatrices[j][1].x = result.rot().x; - state.clusterMatrices[j][1].y = result.rot().y; - state.clusterMatrices[j][1].z = result.rot().z; - state.clusterMatrices[j][1].w = result.rot().w; - - state.clusterMatrices[j][2].x = result.trans().x; - state.clusterMatrices[j][2].y = result.trans().y; - state.clusterMatrices[j][2].z = result.trans().z; + // AJT: TODO: optimize + glm::mat4 mat; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat); + state.clusterTransforms[j] = TransformComponents(mat); +#else + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b798d77ab9..e8f11a421b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -43,8 +43,6 @@ } \ } while(false) -//#define SKIN_MATRIX -//#define SKIN_DUAL_QUAT #define SKIN_COMP class AbstractViewStateInterface; @@ -257,9 +255,50 @@ public: int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } + class TransformComponents { + public: + TransformComponents() {} + TransformComponents(const glm::mat4& m) { + AnimPose p(m); + _scale.x = p.scale().x; + _scale.y = p.scale().y; + _scale.z = p.scale().z; + _rot = p.rot(); + _trans.x = p.trans().x; + _trans.y = p.trans().y; + _trans.z = p.trans().z; + } + + TransformComponents(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) { + _scale.x = scale.x; + _scale.y = scale.y; + _scale.z = scale.z; + _rot = rot; + _trans.x = trans.x; + _trans.y = trans.y; + _trans.z = trans.z; + } + + glm::vec3 getScale() const { return glm::vec3(_scale); } + glm::quat getRot() const { return _rot; } + glm::vec3 getTrans() const { return glm::vec3(_trans); } + glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRot(), getTrans()); }; + + protected: + glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f }; + glm::quat _rot { 1.0f, 0.0f, 0.0f, 0.0f }; + glm::vec4 _trans { 0.0f, 0.0f, 0.0f, 0.0f }; + glm::vec4 _padding { 0.0f, 0.0f, 0.0f, 0.0f }; + }; + class MeshState { public: - std::vector clusterMatrices; +#ifdef SKIN_COMP + std::vector clusterTransforms; +#else + std::vector clusterTransforms; +#endif + }; const MeshState& getMeshState(int index) { return _meshStates.at(index); } diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 371efef145..63bb6ba46e 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -38,60 +38,11 @@ void dqMul(vec4 lhsReal, vec4 lhsImag, vec4 rhsReal, vec4 rhsImag, out vec4 real imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal); } -// dual quat blend -void blendClusters_dual_quat(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { - vec3 scale = vec3(0.0, 0.0, 0.0); - vec4 dqReal = vec4(0.0, 0.0, 0.0, 0.0); - vec4 dqImag = 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]; +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); - vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); - - scale += s * clusterWeight; - dqReal += dqr * clusterWeight; - dqImag += dqi * clusterWeight; - } - - scaleOut = scale; - - float dqLen = length(dqReal); - dqReal *= 1.0 / dqLen; - dqImag *= 1.0 / dqLen; - - rotOut = dqReal; - - vec4 invReal = quatConj(dqReal); - posOut.xyz = 2.0 * quatMul(dqImag, invReal).xyz; -} - -// rigid dual quat blend -void blendClusters_rigid_dual_quat(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { - float maxWeight = 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 dqr = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec4 dqi = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); - - if (clusterWeight > maxWeight) { - maxWeight = clusterWeight; - scaleOut = s; - rotOut = dqr; - vec4 invReal = quatConj(dqr); - posOut = 2.0 * quatMul(dqi, invReal).xyz; - } - } -} - -// rigid componentwise blend -void blendClusters(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scaleOut, out vec4 rotOut, out vec3 posOut) { - float maxWeight = 0.0; for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; @@ -100,51 +51,83 @@ void blendClusters(ivec4 skinClusterIndex, vec4 skinClusterWeight, out vec3 scal 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 (clusterWeight > maxWeight) { - maxWeight = clusterWeight; - scaleOut = s; - rotOut = r; - posOut = t; + if (dot(r, rAccum) < 0) { + r = -r; } + + sAccum += s * clusterWeight; + rAccum += r * clusterWeight; + tAccum += t * clusterWeight; } -} -void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + rAccum = normalize(rAccum); - vec3 scale, pos; - vec4 rot; - blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); - - skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos; - skinnedPosition.w = 1; + skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); } void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { - vec3 scale, pos; - vec4 rot; - blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); + 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); - skinnedNormal.xyz = rotateByQuat(rot, inNormal * scale); + 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; + } + + rAccum = normalize(rAccum); + + skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); + skinnedNormal = rotateByQuat(rAccum, inNormal); } void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { - vec3 scale, pos; - vec4 rot; - blendClusters(skinClusterIndex, skinClusterWeight, scale, rot, pos); + 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); - skinnedPosition.xyz = rotateByQuat(rot, (vec3(inPosition) * scale)) + pos; - skinnedPosition.w = 1; + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; - skinnedNormal = rotateByQuat(rot, inNormal * scale); - skinnedTangent = rotateByQuat(rot, inTangent * scale); + 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; + } + + rAccum = normalize(rAccum); + + skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); + skinnedNormal = rotateByQuat(rAccum, inNormal); + skinnedTangent = rotateByQuat(rAccum, inTangent); } -// ORIGINAL /* +// ORIGINAL void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); @@ -193,5 +176,4 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v } */ - <@endif@> diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 7d49a8cda1..8fa609b241 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -50,7 +50,6 @@ void SoftAttachmentModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); -#ifdef SKIN_MATRIX // TODO: cache these look-ups as an optimization int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); glm::mat4 jointMatrix; @@ -59,35 +58,14 @@ void SoftAttachmentModel::updateClusterMatrices() { } else { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } - SKIN_ASSERT(false); - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); -#endif #ifdef SKIN_COMP - // TODO: cache these look-ups as an optimization - int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); - AnimPose jointPose; - if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { - jointPose = _rigOverride.getJointPose(jointIndexOverride); - } else { - jointPose = _rig.getJointPose(cluster.jointIndex); - } - AnimPose result = jointPose * AnimPose(cluster.inverseBindMatrix); - - // pack scale rotation and translation into a mat4. - state.clusterMatrices[j][0].x = result.scale().x; - state.clusterMatrices[j][0].y = result.scale().y; - state.clusterMatrices[j][0].z = result.scale().z; - - state.clusterMatrices[j][1].x = result.rot().x; - state.clusterMatrices[j][1].y = result.rot().y; - state.clusterMatrices[j][1].z = result.rot().z; - state.clusterMatrices[j][1].w = result.rot().w; - - state.clusterMatrices[j][2].x = result.trans().x; - state.clusterMatrices[j][2].y = result.trans().y; - state.clusterMatrices[j][2].z = result.trans().z; + // AJT: TODO: Optimize + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + state.clusterTransforms[j] = Model::TransformComponents(m); +#else + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif - } } From 3896b31a727728c04835c020e87a9380a07dfe22 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 21 Dec 2017 14:20:41 -0800 Subject: [PATCH 06/43] Line numbers for shader when there are compilation errors --- libraries/gl/src/gl/GLShaders.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp index 8ef0198676..017c92b71c 100644 --- a/libraries/gl/src/gl/GLShaders.cpp +++ b/libraries/gl/src/gl/GLShaders.cpp @@ -63,12 +63,17 @@ namespace gl { } */ - qCWarning(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:"; + qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:"; + int lineNumber = 0; for (auto s : srcstr) { - qCWarning(glLogging) << s; + QString str(s); + QStringList lines = str.split("\n"); + for (auto& line : lines) { + qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line); + } } - qCWarning(glLogging) << "GLShader::compileShader - errors:"; - qCWarning(glLogging) << temp; + qCCritical(glLogging) << "GLShader::compileShader - errors:"; + qCCritical(glLogging) << temp; error = std::string(temp); delete[] temp; From 8bdddf721153a401344187352cb36945c47e4a0e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 21 Dec 2017 14:22:22 -0800 Subject: [PATCH 07/43] Full Dual Quaternion support --- .../src/CauterizedMeshPartPayload.cpp | 22 +-- .../src/CauterizedMeshPartPayload.h | 11 +- .../render-utils/src/CauterizedModel.cpp | 22 ++- .../render-utils/src/MeshPartPayload.cpp | 36 +--- libraries/render-utils/src/MeshPartPayload.h | 17 +- libraries/render-utils/src/Model.cpp | 9 +- libraries/render-utils/src/Model.h | 36 +++- libraries/render-utils/src/Skinning.slh | 176 ++++++++++++++++++ .../render-utils/src/SoftAttachmentModel.cpp | 7 +- libraries/shared/src/DualQuaternion.cpp | 3 + libraries/shared/src/DualQuaternion.h | 1 + 11 files changed, 267 insertions(+), 73 deletions(-) diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index c64c98b271..969be6cdd7 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -20,35 +20,19 @@ using namespace render; CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} -#ifdef SKIN_COMP -void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms) { +void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms) { ModelMeshPartPayload::updateClusterBuffer(clusterTransforms); if (cauterizedClusterTransforms.size() > 1) { if (!_cauterizedClusterBuffer) { - _cauterizedClusterBuffer = std::make_shared(cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents), + _cauterizedClusterBuffer = std::make_shared(cauterizedClusterTransforms.size() * sizeof(TransformType), (const gpu::Byte*) cauterizedClusterTransforms.data()); } else { - _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(Model::TransformComponents), + _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(TransformType), (const gpu::Byte*) cauterizedClusterTransforms.data()); } } } -#else -void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms) { - ModelMeshPartPayload::updateClusterBuffer(clusterTransforms); - - if (cauterizedClusterTransforms.size() > 1) { - if (!_cauterizedClusterBuffer) { - _cauterizedClusterBuffer = std::make_shared(cauterizedClusterTransforms.size() * sizeof(glm::mat4), - (const gpu::Byte*) cauterizedClusterTransforms.data()); - } else { - _cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(glm::mat4), - (const gpu::Byte*) cauterizedClusterTransforms.data()); - } - } -} -#endif void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) { _cauterizedTransform = renderTransform; diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 1ee77c300f..5dceb3debd 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -14,12 +14,17 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { public: CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); -#ifdef SKIN_COMP - void updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms); + +#if defined(SKIN_COMP) + using TransformType = Model::TransformComponents; +#elif defined(SKIN_DQ) + using TransformType = Model::TransformDualQuaternion; #else - void updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms); + using TransformType = glm::mat4; #endif + void updateClusterBuffer(const std::vector& clusterTransforms, const std::vector& cauterizedClusterTransforms); + void updateTransformForCauterizedMesh(const Transform& renderTransform); void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 606e1f0351..cf6aebc952 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -117,11 +117,16 @@ void CauterizedModel::updateClusterMatrices() { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); -#ifdef SKIN_COMP - // AJT: TODO: optimize +#if defined(SKIN_COMP) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + AnimPose p(m); state.clusterTransforms[j] = Model::TransformComponents(m); +#elif defined(SKIN_DQ) + 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]); #endif @@ -149,11 +154,16 @@ void CauterizedModel::updateClusterMatrices() { jointMatrix = cauterizeMatrix; } -#ifdef SKIN_COMP - // AJT: TODO: optimize +#if defined(SKIN_COMP) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + AnimPose p(m); state.clusterTransforms[j] = Model::TransformComponents(m); +#elif defined(SKIN_DQ) + 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]); #endif @@ -224,7 +234,7 @@ void CauterizedModel::updateRenderItems() { Transform renderTransform = modelTransform; if (clusterTransforms.size() == 1) { -#ifdef SKIN_COMP +#if defined(SKIN_COMP) || defined(SKIN_DQ) renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); @@ -234,7 +244,7 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform; if (clusterTransformsCauterized.size() == 1) { -#ifdef SKIN_COMP +#if defined(SKIN_COMP) || defined(SKIN_DQ) renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix())); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 3056dbc728..a303c0b0d8 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -331,7 +331,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in updateTransform(transform, offsetTransform); Transform renderTransform = transform; if (state.clusterTransforms.size() == 1) { -#ifdef SKIN_COMP +#if defined(SKIN_COMP) || defined(SKIN_DQ) renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix())); #else renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0])); @@ -366,26 +366,11 @@ void ModelMeshPartPayload::notifyLocationChanged() { } -#ifdef SKIN_COMP -void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms) { +void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms) { // Once computed the cluster matrices, update the buffer(s) if (clusterTransforms.size() > 1) { if (!_clusterBuffer) { - _clusterBuffer = std::make_shared(clusterTransforms.size() * sizeof(Model::TransformComponents), - (const gpu::Byte*) clusterTransforms.data()); - } - else { - _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(Model::TransformComponents), - (const gpu::Byte*) clusterTransforms.data()); - } - } -} -#else -void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clusterTransforms) { - // Once computed the cluster matrices, update the buffer(s) - if (clusterTransforms.size() > 1) { - if (!_clusterBuffer) { - _clusterBuffer = std::make_shared(clusterTransforms.size() * sizeof(glm::mat4), + _clusterBuffer = std::make_shared(clusterTransforms.size() * sizeof(TransformType), (const gpu::Byte*) clusterTransforms.data()); } else { @@ -394,8 +379,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clu } } } -#endif - void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) { _transform = renderTransform; @@ -561,15 +544,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) { args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } -#ifdef SKIN_COMP -void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { -#else -void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { -#endif + +void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { _adjustedLocalBound = _localBound; if (clusterTransforms.size() > 0) { -#ifdef SKIN_COMP - // AJT: TODO: optimize +#if defined(SKIN_COMP) || defined(SKIN_DQ) _adjustedLocalBound.transform(clusterTransforms[0].getMatrix()); #else _adjustedLocalBound.transform(clusterTransforms[0]); @@ -577,8 +556,7 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms); + +#if defined(SKIN_COMP) + using TransformType = Model::TransformComponents; +#elif defined(SKIN_DQ) + using TransformType = Model::TransformDualQuaternion; #else - void updateClusterBuffer(const std::vector& clusterTransforms); + using TransformType = glm::mat4; #endif + + void updateClusterBuffer(const std::vector& clusterTransforms); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); // Render Item interface @@ -108,11 +113,7 @@ public: void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; -#ifdef SKIN_COMP - void computeAdjustedLocalBound(const std::vector& clusterTransforms); -#else - void computeAdjustedLocalBound(const std::vector& clusterMatrices); -#endif + void computeAdjustedLocalBound(const std::vector& clusterTransforms); gpu::BufferPointer _clusterBuffer; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0f014032a3..6eb9662c46 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -276,7 +276,7 @@ void Model::updateRenderItems() { Transform renderTransform = modelTransform; if (clusterTransforms.size() == 1) { -#ifdef SKIN_COMP +#if defined(SKIN_COMP) || defined(SKIN_DQ) renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); @@ -1183,11 +1183,14 @@ void Model::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); -#ifdef SKIN_COMP - // AJT: TODO: optimize +#if defined(SKIN_COMP) glm::mat4 mat; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat); state.clusterTransforms[j] = TransformComponents(mat); +#elif defined(SKIN_DQ) + glm::mat4 mat; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat); + state.clusterTransforms[j] = TransformDualQuaternion(mat); #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e8f11a421b..f869634dd2 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "GeometryCache.h" #include "TextureCache.h" @@ -43,7 +44,7 @@ } \ } while(false) -#define SKIN_COMP +#define SKIN_DQ class AbstractViewStateInterface; class QScriptEngine; @@ -255,6 +256,7 @@ public: int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } +#if defined(SKIN_COMP) class TransformComponents { public: TransformComponents() {} @@ -290,15 +292,43 @@ public: glm::vec4 _trans { 0.0f, 0.0f, 0.0f, 0.0f }; glm::vec4 _padding { 0.0f, 0.0f, 0.0f, 0.0f }; }; +#elif defined(SKIN_DQ) + class TransformDualQuaternion { + public: + TransformDualQuaternion() {} + TransformDualQuaternion(const glm::mat4& m) { + AnimPose p(m); + _scale.x = p.scale().x; + _scale.y = p.scale().y; + _scale.z = p.scale().z; + _dq = DualQuaternion(p.rot(), p.trans()); + } + TransformDualQuaternion(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) { + _scale.x = scale.x; + _scale.y = scale.y; + _scale.z = scale.z; + _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()); }; + protected: + glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f }; + DualQuaternion _dq; + glm::vec4 _padding; + }; +#endif class MeshState { public: -#ifdef SKIN_COMP +#if defined(SKIN_COMP) std::vector clusterTransforms; +#elif defined(SKIN_DQ) + std::vector clusterTransforms; #else std::vector clusterTransforms; #endif - }; const MeshState& getMeshState(int index) { return _meshStates.at(index); } diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 63bb6ba46e..17c3a26079 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -38,6 +38,181 @@ void dqMul(vec4 lhsReal, vec4 lhsImag, vec4 rhsReal, vec4 rhsImag, out vec4 real imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal); } +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); + vec4 iAccum = 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 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); + vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); + vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + + sAccum += scale * clusterWeight; + rAccum += real * clusterWeight; + iAccum += imag * clusterWeight; + } + + 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); + + skinnedPosition = m * (vec4(sAccum, 1) * inPosition); +} + +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); + vec4 iAccum = 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 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); + vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); + vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + + sAccum += scale * clusterWeight; + rAccum += real * clusterWeight; + iAccum += imag * clusterWeight; + } + + 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); + + skinnedPosition = m * (vec4(sAccum, 1) * inPosition); + skinnedNormal = vec3(m * vec4(inNormal, 0)); +} + +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); + vec4 iAccum = 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 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); + vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); + vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + + sAccum += scale * clusterWeight; + rAccum += real * clusterWeight; + iAccum += imag * clusterWeight; + } + + 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); + + skinnedPosition = m * (vec4(sAccum, 1) * inPosition); + skinnedNormal = vec3(m * vec4(inNormal, 0)); + skinnedTangent = vec3(m * vec4(inTangent, 0)); +} + +// SKIN_COMP +/* 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); @@ -125,6 +300,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v skinnedNormal = rotateByQuat(rAccum, inNormal); skinnedTangent = rotateByQuat(rAccum, inTangent); } +*/ /* // ORIGINAL diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 8fa609b241..7b76f89184 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -58,11 +58,14 @@ void SoftAttachmentModel::updateClusterMatrices() { } else { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } -#ifdef SKIN_COMP - // AJT: TODO: Optimize +#if defined(SKIN_COMP) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); state.clusterTransforms[j] = Model::TransformComponents(m); +#elif defined(SKIN_DQ) + glm::mat4 m; + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); + state.clusterTransforms[j] = Model::TransformDualQuaternion(m); #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index 3b5aaf6d6d..e9b1a65635 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -12,6 +12,9 @@ #include "GLMHelpers.h" // delegating constructor +DualQuaternion::DualQuaternion() : _real(1.0f, 0.0f, 0.0f, 0.0), _imag(0.0f, 0.0f, 0.0f, 0.0f) { +} + DualQuaternion::DualQuaternion(const glm::mat4& m) : DualQuaternion(glmExtractRotation(m), extractTranslation(m)) { } diff --git a/libraries/shared/src/DualQuaternion.h b/libraries/shared/src/DualQuaternion.h index ed8cdf54ff..061317bde9 100644 --- a/libraries/shared/src/DualQuaternion.h +++ b/libraries/shared/src/DualQuaternion.h @@ -19,6 +19,7 @@ class DualQuaternion { public: + DualQuaternion(); explicit DualQuaternion(const glm::mat4& m); DualQuaternion(const glm::quat& real, const glm::quat& imag); DualQuaternion(const glm::quat& rotation, const glm::vec3& translation); From 5bb0b06061a97633f052e5368b2c218b2f0c342f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 21 Dec 2017 18:15:30 -0800 Subject: [PATCH 08/43] WIP: Dual Quaternion compensation for spinning the right way. --- .../render-utils/src/CauterizedModel.cpp | 51 ++++++++++++++++++- libraries/render-utils/src/Model.h | 2 +- libraries/render-utils/src/Skinning.slh | 42 ++++++++++++--- libraries/shared/src/DualQuaternion.cpp | 17 +++++-- libraries/shared/src/DualQuaternion.h | 3 ++ 5 files changed, 104 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index cf6aebc952..5be93304ab 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -113,7 +113,12 @@ void CauterizedModel::updateClusterMatrices() { for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); +#if defined(SKIN_DQ) + // HACK: FOR DQ go thru reverse order! + for (int j = mesh.clusters.size() - 1; j >= 0; j--) { +#else for (int j = 0; j < mesh.clusters.size(); j++) { +#endif const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -127,6 +132,25 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + + // AJT: HACK n^2!!!! fix me, find parent clusterTransform. + int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); + int parentClusterIndex = -1; + // scan for parent! + for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { + if (mesh.clusters[ii].jointIndex == parentIndex) { + parentClusterIndex = ii; + break; + } + } + + // ensure that we have the same polarity as our parent! + if (parentClusterIndex >= 0) { + //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { + if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { + state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; + } + } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif @@ -146,7 +170,13 @@ void CauterizedModel::updateClusterMatrices() { for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); - for (int j = 0; j < mesh.clusters.size(); j++) { + +#if defined(SKIN_DQ) + // HACK: FOR DQ go thru reverse order! + for (int j = mesh.clusters.size() - 1; j >= 0; j--) { +#else + for (int j = 0; j < mesh.clusters.size(); j++) { +#endif const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -164,6 +194,25 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + + // AJT: HACK n^2!!!! fix me, find parent clusterTransform. + int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); + int parentClusterIndex = -1; + // scan for parent! + for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { + if (mesh.clusters[ii].jointIndex == parentIndex) { + parentClusterIndex = ii; + break; + } + } + + // ensure that we have the same polarity as our parent! + if (parentClusterIndex >= 0) { + //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { + if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { + state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; + } + } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f869634dd2..cb211a1011 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -313,7 +313,7 @@ public: glm::quat getRot() const { return _dq.getRotation(); } glm::vec3 getTrans() const { return _dq.getTranslation(); } glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRot(), getTrans()); }; - protected: + public: // AJT: TODO FIX ME. glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f }; DualQuaternion _dq; glm::vec4 _padding; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 17c3a26079..bdba724d43 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -43,6 +43,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio 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 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -52,9 +53,18 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); @@ -100,6 +110,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP 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 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -109,9 +120,18 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); @@ -158,6 +178,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v 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 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -167,9 +188,18 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index e9b1a65635..44d7356463 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -59,26 +59,37 @@ glm::vec3 DualQuaternion::getTranslation() const { return glm::vec3(result.x, result.y, result.z); } - glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const { return _real * rhs; } +// AJT: UNTESTED DualQuaternion DualQuaternion::inverse() const { glm::quat invReal = glm::inverse(_real); return DualQuaternion(invReal, - invReal * _imag * invReal); } +// AJT: UNTESTED DualQuaternion DualQuaternion::conjugate() const { return DualQuaternion(glm::conjugate(_real), glm::conjugate(_imag)); } +// AJT: UNTESTED float DualQuaternion::length() const { - DualQuaternion result = *this * conjugate(); - return sqrtf(result._real.w); + float dot = this->dot(*this); + return sqrtf(dot); } DualQuaternion DualQuaternion::normalize() const { float invLen = 1.0f / length(); return *this * invLen; } + +float DualQuaternion::dot(const DualQuaternion& rhs) const { + DualQuaternion result = *this * conjugate(); + return result._real.w; +} + +DualQuaternion DualQuaternion::operator-() const { + return DualQuaternion(-_real, -_imag); +} diff --git a/libraries/shared/src/DualQuaternion.h b/libraries/shared/src/DualQuaternion.h index 061317bde9..508570a930 100644 --- a/libraries/shared/src/DualQuaternion.h +++ b/libraries/shared/src/DualQuaternion.h @@ -44,6 +44,8 @@ public: DualQuaternion conjugate() const; float length() const; DualQuaternion normalize() const; + float dot(const DualQuaternion& rhs) const; + DualQuaternion operator-() const; protected: friend QDebug operator<<(QDebug debug, const DualQuaternion& pose); @@ -51,6 +53,7 @@ protected: glm::quat _imag; }; + inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) { debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), imag = (" << dq._imag.x << dq._imag.y << dq._imag.z << dq._imag.w << ")"; return debug; From b69edceb4f9fbfdfba8f1ef6f3e34e3366610056 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 22 Dec 2017 10:54:48 -0800 Subject: [PATCH 09/43] Fixed rotation polarity and weights are now 16 bit. --- libraries/fbx/src/FBX.h | 2 +- libraries/fbx/src/FBXReader.cpp | 4 +- libraries/fbx/src/FBXReader_Mesh.cpp | 4 +- .../render-utils/src/CauterizedModel.cpp | 50 +------------------ libraries/render-utils/src/Skinning.slh | 18 +++---- 5 files changed, 12 insertions(+), 66 deletions(-) diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 7d3328a2dd..2ec847104c 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -224,7 +224,7 @@ public: QVector texCoords; QVector texCoords1; QVector clusterIndices; - QVector clusterWeights; + QVector clusterWeights; QVector originalIndices; QVector clusters; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index e4fea00a34..b1db5992e7 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1727,9 +1727,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } if (totalWeight > 0.0f) { const float ALMOST_HALF = 0.499f; - float weightScalingFactor = (float)(UINT8_MAX) / totalWeight; + float weightScalingFactor = (float)(UINT16_MAX) / totalWeight; for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { - extracted.mesh.clusterWeights[k] = (uint8_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF); + extracted.mesh.clusterWeights[k] = (uint16_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF); } } } diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index c64cbcc90d..f76435c216 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -583,7 +583,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { // we need 16 bits instead of just 8 for clusterIndices clusterIndicesSize *= 2; } - int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t); + int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint16_t); int normalsOffset = 0; int tangentsOffset = normalsOffset + normalsSize; @@ -662,7 +662,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { if (clusterWeightsSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, - gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::XYZW))); + gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW))); } diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 5be93304ab..7bac720b86 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -113,12 +113,7 @@ void CauterizedModel::updateClusterMatrices() { for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); -#if defined(SKIN_DQ) - // HACK: FOR DQ go thru reverse order! - for (int j = mesh.clusters.size() - 1; j >= 0; j--) { -#else for (int j = 0; j < mesh.clusters.size(); j++) { -#endif const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -132,25 +127,6 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); - - // AJT: HACK n^2!!!! fix me, find parent clusterTransform. - int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); - int parentClusterIndex = -1; - // scan for parent! - for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { - if (mesh.clusters[ii].jointIndex == parentIndex) { - parentClusterIndex = ii; - break; - } - } - - // ensure that we have the same polarity as our parent! - if (parentClusterIndex >= 0) { - //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { - if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { - state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; - } - } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif @@ -171,12 +147,7 @@ void CauterizedModel::updateClusterMatrices() { Model::MeshState& state = _cauterizeMeshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); -#if defined(SKIN_DQ) - // HACK: FOR DQ go thru reverse order! - for (int j = mesh.clusters.size() - 1; j >= 0; j--) { -#else - for (int j = 0; j < mesh.clusters.size(); j++) { -#endif + for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -194,25 +165,6 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); - - // AJT: HACK n^2!!!! fix me, find parent clusterTransform. - int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); - int parentClusterIndex = -1; - // scan for parent! - for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { - if (mesh.clusters[ii].jointIndex == parentIndex) { - parentClusterIndex = ii; - break; - } - } - - // ensure that we have the same polarity as our parent! - if (parentClusterIndex >= 0) { - //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { - if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { - state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; - } - } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index bdba724d43..c11455a575 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -56,10 +56,8 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio float dqClusterWeight = clusterWeight; if (i == 0) { prevR = real; - } else { - if (dot(prevR, real) < 0) { - dqClusterWeight = -clusterWeight; - } + } else if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; } sAccum += scale * clusterWeight; @@ -123,10 +121,8 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP float dqClusterWeight = clusterWeight; if (i == 0) { prevR = real; - } else { - if (dot(prevR, real) < 0) { - dqClusterWeight = -clusterWeight; - } + } else if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; } sAccum += scale * clusterWeight; @@ -191,10 +187,8 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v float dqClusterWeight = clusterWeight; if (i == 0) { prevR = real; - } else { - if (dot(prevR, real) < 0) { - dqClusterWeight = -clusterWeight; - } + } else if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; } sAccum += scale * clusterWeight; From e86fd4f9929b51d64db1e767f1fa8406a750e4da Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 22 Dec 2017 12:23:17 -0800 Subject: [PATCH 10/43] Removed SKIN_COMP define, re-enabled cauterization --- interface/src/avatar/MyAvatar.cpp | 7 +- .../src/CauterizedMeshPartPayload.h | 4 +- .../render-utils/src/CauterizedModel.cpp | 30 ++----- .../render-utils/src/MeshPartPayload.cpp | 6 +- libraries/render-utils/src/MeshPartPayload.h | 4 +- libraries/render-utils/src/Model.cpp | 8 +- libraries/render-utils/src/Model.h | 43 +-------- libraries/render-utils/src/Skinning.slh | 89 ++++--------------- .../render-utils/src/SoftAttachmentModel.cpp | 6 +- libraries/shared/src/DualQuaternion.cpp | 3 - 10 files changed, 38 insertions(+), 162 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0fd7f7f012..02a1959a95 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1820,8 +1820,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) { initHeadBones(); - // AJT HACK DISABLE CAUTERIZE - //_skeletonModel->setCauterizeBoneSet(_headBoneSet); + _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); _isAnimatingScale = true; @@ -1913,9 +1912,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { // toggle using the cauterizedBones depending on where the camera is and the rendering pass type. const bool shouldDrawHead = shouldRenderHead(renderArgs); if (shouldDrawHead != _prevShouldDrawHead) { - // AJT: DISABLE CAUTER - // _skeletonModel->setEnableCauterization(!shouldDrawHead); - _skeletonModel->setEnableCauterization(false); + _skeletonModel->setEnableCauterization(!shouldDrawHead); for (int i = 0; i < _attachmentData.size(); i++) { if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 || diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 5dceb3debd..2337632047 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -15,9 +15,7 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { public: CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); -#if defined(SKIN_COMP) - using TransformType = Model::TransformComponents; -#elif defined(SKIN_DQ) +#if defined(SKIN_DQ) using TransformType = Model::TransformDualQuaternion; #else using TransformType = glm::mat4; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 7bac720b86..3ffacb8836 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -104,12 +104,6 @@ void CauterizedModel::updateClusterMatrices() { _needsUpdateClusterMatrices = false; const FBXGeometry& geometry = getFBXGeometry(); - bool debug = false; - - if (debug) { - qDebug() << "AJT: CauterizedModel::updateClusterMatrices(), url =" << _url; - } - for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -117,12 +111,7 @@ void CauterizedModel::updateClusterMatrices() { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); -#if defined(SKIN_COMP) - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - AnimPose p(m); - state.clusterTransforms[j] = Model::TransformComponents(m); -#elif defined(SKIN_DQ) +#if defined(SKIN_DQ) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); @@ -137,9 +126,9 @@ void CauterizedModel::updateClusterMatrices() { if (!_cauterizeBoneSet.empty()) { static const glm::mat4 zeroScale( - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale; @@ -155,12 +144,7 @@ void CauterizedModel::updateClusterMatrices() { jointMatrix = cauterizeMatrix; } -#if defined(SKIN_COMP) - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - AnimPose p(m); - state.clusterTransforms[j] = Model::TransformComponents(m); -#elif defined(SKIN_DQ) +#if defined(SKIN_DQ) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); @@ -235,7 +219,7 @@ void CauterizedModel::updateRenderItems() { Transform renderTransform = modelTransform; if (clusterTransforms.size() == 1) { -#if defined(SKIN_COMP) || defined(SKIN_DQ) +#if defined(SKIN_DQ) renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); @@ -245,7 +229,7 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform; if (clusterTransformsCauterized.size() == 1) { -#if defined(SKIN_COMP) || defined(SKIN_DQ) +#if defined(SKIN_DQ) renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix())); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a303c0b0d8..481d4574ab 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -331,7 +331,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in updateTransform(transform, offsetTransform); Transform renderTransform = transform; if (state.clusterTransforms.size() == 1) { -#if defined(SKIN_COMP) || defined(SKIN_DQ) +#if defined(SKIN_DQ) renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix())); #else renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0])); @@ -548,7 +548,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterTransforms) { _adjustedLocalBound = _localBound; if (clusterTransforms.size() > 0) { -#if defined(SKIN_COMP) || defined(SKIN_DQ) +#if defined(SKIN_DQ) _adjustedLocalBound.transform(clusterTransforms[0].getMatrix()); #else _adjustedLocalBound.transform(clusterTransforms[0]); @@ -556,7 +556,7 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector clusterTransforms; -#elif defined(SKIN_DQ) +#if defined(SKIN_DQ) std::vector clusterTransforms; #else std::vector clusterTransforms; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index c11455a575..b90db26d9f 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -43,20 +43,19 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio 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 prevR = vec4(0.0, 0.0, 0.0, 1.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]; - vec3 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + vec3 scale = vec3(clusterMatrix[0]); + vec4 real = clusterMatrix[1]; + vec4 imag = clusterMatrix[2]; + // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (i == 0) { - prevR = real; - } else if (dot(prevR, real) < 0) { + if (dot(real, polarityReference) < 0) { dqClusterWeight = -clusterWeight; } @@ -108,20 +107,19 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP 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 prevR = vec4(0.0, 0.0, 0.0, 1.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]; - vec3 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + vec3 scale = vec3(clusterMatrix[0]); + vec4 real = clusterMatrix[1]; + vec4 imag = clusterMatrix[2]; + // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (i == 0) { - prevR = real; - } else if (dot(prevR, real) < 0) { + if (dot(real, polarityReference) < 0) { dqClusterWeight = -clusterWeight; } @@ -174,20 +172,19 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v 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 prevR = vec4(0.0, 0.0, 0.0, 1.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]; - vec3 scale = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + vec3 scale = vec3(clusterMatrix[0]); + vec4 real = clusterMatrix[1]; + vec4 imag = clusterMatrix[2]; + // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (i == 0) { - prevR = real; - } else if (dot(prevR, real) < 0) { + if (dot(real, polarityReference) < 0) { dqClusterWeight = -clusterWeight; } @@ -326,54 +323,4 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v } */ -/* -// ORIGINAL -void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { - 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; - } - - skinnedPosition = newPosition; -} - -void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, - out vec4 skinnedPosition, out vec3 skinnedNormal) { - 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - } - - 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) { - 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]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; - } - - skinnedPosition = newPosition; - skinnedNormal = newNormal.xyz; - skinnedTangent = newTangent.xyz; -} -*/ - <@endif@> diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 7b76f89184..58b5eea222 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -58,11 +58,7 @@ void SoftAttachmentModel::updateClusterMatrices() { } else { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } -#if defined(SKIN_COMP) - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - state.clusterTransforms[j] = Model::TransformComponents(m); -#elif defined(SKIN_DQ) +#if defined(SKIN_DQ) glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index 44d7356463..e2a9dc9bb2 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -63,18 +63,15 @@ glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const { return _real * rhs; } -// AJT: UNTESTED DualQuaternion DualQuaternion::inverse() const { glm::quat invReal = glm::inverse(_real); return DualQuaternion(invReal, - invReal * _imag * invReal); } -// AJT: UNTESTED DualQuaternion DualQuaternion::conjugate() const { return DualQuaternion(glm::conjugate(_real), glm::conjugate(_imag)); } -// AJT: UNTESTED float DualQuaternion::length() const { float dot = this->dot(*this); return sqrtf(dot); From bcd813ac62342712c6b3d4f16661317f44b58910 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 22 Dec 2017 15:24:54 -0800 Subject: [PATCH 11/43] Optimizations and cleanup --- .../render-utils/src/CauterizedModel.cpp | 14 +- .../render-utils/src/MeshPartPayload.cpp | 15 +- libraries/render-utils/src/Model.cpp | 6 +- libraries/render-utils/src/Model.h | 16 +- libraries/render-utils/src/Skinning.slh | 242 +++++------------- .../render-utils/src/SoftAttachmentModel.cpp | 11 +- libraries/shared/src/Transform.h | 2 +- 7 files changed, 113 insertions(+), 193 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 3ffacb8836..86deff095b 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -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 diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 481d4574ab..e3bbfc1c03 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -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 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 <@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 diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 58b5eea222..fe74dc3c87 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -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 } diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 7a39314f4d..90bfc1aaa6 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -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); From aacf2d489fabd4e2186052caec26afc29f21d115 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 3 Jan 2018 13:21:47 -0800 Subject: [PATCH 12/43] removed comments --- libraries/render-utils/src/CauterizedModel.cpp | 2 -- libraries/render-utils/src/Model.cpp | 2 +- libraries/render-utils/src/SoftAttachmentModel.cpp | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 86deff095b..b8596af07f 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -112,7 +112,6 @@ 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); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); @@ -145,7 +144,6 @@ void CauterizedModel::updateClusterMatrices() { } #if defined(SKIN_DQ) - // AJT: TODO: optimize glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 5ca9fc2bc4..b2459d27e3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1178,6 +1178,7 @@ void Model::updateClusterMatrices() { if (!_needsUpdateClusterMatrices || !isLoaded()) { return; } + _needsUpdateClusterMatrices = false; const FBXGeometry& geometry = getFBXGeometry(); for (int i = 0; i < (int) _meshStates.size(); i++) { @@ -1187,7 +1188,6 @@ 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); diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index fe74dc3c87..0d0db7cbe3 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -60,7 +60,6 @@ void SoftAttachmentModel::updateClusterMatrices() { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } - // AJT: TODO: OPTIMIZE glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); From b8c88fca3b0e28be59dab4a3f26fb8294465120c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 4 Jan 2018 13:36:15 -0800 Subject: [PATCH 13/43] Dual Quaternion skinning optimization Reduce expensive conversion from quat -> matrix -> quat, by keeping the inverseBindPose in a Transform instance instead of a mat4. --- libraries/fbx/src/FBX.h | 1 + libraries/fbx/src/FBXReader.cpp | 1 + .../render-utils/src/CauterizedModel.cpp | 37 +++++++++++-------- libraries/render-utils/src/Model.cpp | 9 +++-- libraries/render-utils/src/Model.h | 4 ++ 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 2ec847104c..6f771a702a 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -115,6 +115,7 @@ public: int jointIndex; glm::mat4 inverseBindMatrix; + Transform inverseBindTransform; }; const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index b1db5992e7..c52647802e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1613,6 +1613,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS fbxCluster.jointIndex = 0; } fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform; + fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix); extracted.mesh.clusters.append(fbxCluster); // override the bind rotation with the transform link diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index b8596af07f..e3f26a43d8 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -109,13 +109,14 @@ void CauterizedModel::updateClusterMatrices() { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); #if defined(SKIN_DQ) - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + auto jointPose = _rig.getJointPose(cluster.jointIndex); + Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); + state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); #else + auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } @@ -123,14 +124,17 @@ void CauterizedModel::updateClusterMatrices() { // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. if (!_cauterizeBoneSet.empty()) { - +#if defined(SKIN_DQ) + AnimPose cauterizePose = _rig.getJointPose(geometry.neckJointIndex); + cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f); +#else static const glm::mat4 zeroScale( glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale; - +#endif for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -138,18 +142,19 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); - if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { - jointMatrix = cauterizeMatrix; - } - + if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) { + // not cauterized so just copy the value from the non-cauterized version. + state.clusterTransforms[j] = _meshStates[i].clusterTransforms[j]; + } else { #if defined(SKIN_DQ) - glm::mat4 m; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); + state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); #else - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); + glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif + } } } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b2459d27e3..2fc4a778d9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1188,10 +1188,13 @@ void Model::updateClusterMatrices() { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); #if defined(SKIN_DQ) - glm::mat4 mat; - glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, mat); - state.clusterTransforms[j] = TransformDualQuaternion(mat); + auto jointPose = _rig.getJointPose(cluster.jointIndex); + Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform); + state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform); #else + auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 1461213c6f..d13a76847a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -268,6 +268,10 @@ public: _scale.z = scale.z; _dq = DualQuaternion(rot, trans); } + TransformDualQuaternion(const Transform& transform) { + _scale = glm::vec4(transform.getScale(), 0.0f); + _dq = DualQuaternion(transform.getRotation(), transform.getTranslation()); + } glm::vec3 getScale() const { return glm::vec3(_scale); } glm::quat getRotation() const { return _dq.getRotation(); } glm::vec3 getTranslation() const { return _dq.getTranslation(); } From fac0982c67ddcc5089cec483bbaf93cdd489e589 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 4 Jan 2018 16:37:12 -0800 Subject: [PATCH 14/43] need to use sizeof(TransformType), not sizeof(mat4) --- libraries/render-utils/src/MeshPartPayload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e3bbfc1c03..1907be9b42 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -377,7 +377,7 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector& (const gpu::Byte*) clusterTransforms.data()); } else { - _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(glm::mat4), + _clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(TransformType), (const gpu::Byte*) clusterTransforms.data()); } } From 51ab38f48415c1001b48c122ae4127232fe26940 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 4 Jan 2018 17:32:22 -0800 Subject: [PATCH 15/43] warning fix --- libraries/render-utils/src/Model.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 2fc4a778d9..31e23f7660 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1186,7 +1186,6 @@ void Model::updateClusterMatrices() { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); #if defined(SKIN_DQ) auto jointPose = _rig.getJointPose(cluster.jointIndex); Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); From d08f94a74d09368bb19a7b4f5fe56f88d74f5e98 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 8 Jan 2018 13:19:54 -0800 Subject: [PATCH 16/43] Code review feedback * Removed AnimPose::fuzzyEqual * Fixed DualQuaternion ctor --- libraries/animation/src/AnimPose.cpp | 21 --------------------- libraries/animation/src/AnimPose.h | 2 -- libraries/shared/src/DualQuaternion.cpp | 2 +- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 29c4c46d6e..a0b8fba1da 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -69,27 +69,6 @@ AnimPose AnimPose::mirror() const { return AnimPose(_scale, glm::quat(_rot.w, _rot.x, -_rot.y, -_rot.z), glm::vec3(-_trans.x, _trans.y, _trans.z)); } -bool AnimPose::fuzzyEqual(const AnimPose& rhs) const { - const float SCALE_EPSILON = 0.00001f; - const float ROT_EPSILON = 0.00001f; - const float TRANS_EPSILON = 0.001f; - if ((fabsf(rhs._scale.x - _scale.x) < SCALE_EPSILON) && - (fabsf(rhs._scale.y - _scale.y) < SCALE_EPSILON) && - (fabsf(rhs._scale.z - _scale.z) < SCALE_EPSILON)) { - if ((fabsf(rhs._rot.x - _rot.x) < ROT_EPSILON) && - (fabsf(rhs._rot.y - _rot.y) < ROT_EPSILON) && - (fabsf(rhs._rot.z - _rot.z) < ROT_EPSILON) && - (fabsf(rhs._rot.w - _rot.w) < ROT_EPSILON)) { - if ((fabsf(rhs._trans.x - _trans.x) < TRANS_EPSILON) && - (fabsf(rhs._trans.y - _trans.y) < TRANS_EPSILON) && - (fabsf(rhs._trans.z - _trans.z) < TRANS_EPSILON)) { - return true; - } - } - } - return false; -} - AnimPose::operator glm::mat4() const { glm::vec3 xAxis = _rot * glm::vec3(_scale.x, 0.0f, 0.0f); glm::vec3 yAxis = _rot * glm::vec3(0.0f, _scale.y, 0.0f); diff --git a/libraries/animation/src/AnimPose.h b/libraries/animation/src/AnimPose.h index 0f29bac7ce..2df3d1f2e4 100644 --- a/libraries/animation/src/AnimPose.h +++ b/libraries/animation/src/AnimPose.h @@ -46,8 +46,6 @@ public: const glm::vec3& trans() const { return _trans; } glm::vec3& trans() { return _trans; } - bool fuzzyEqual(const AnimPose& rhs) const; - private: friend QDebug operator<<(QDebug debug, const AnimPose& pose); glm::vec3 _scale { 1.0f }; diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index e2a9dc9bb2..03628f8aba 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -28,7 +28,7 @@ DualQuaternion::DualQuaternion(const glm::vec4& real, const glm::vec4& imag) : DualQuaternion::DualQuaternion(const glm::quat& rotation, const glm::vec3& translation) { _real = rotation; - _imag = glm::quat(0, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation; + _imag = glm::quat(0.0f, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation; } DualQuaternion DualQuaternion::operator*(const DualQuaternion& rhs) const { From fbea22e0f0a00a99e0db008e3823aadebebbd083 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 8 Jan 2018 18:21:23 -0800 Subject: [PATCH 17/43] Renamed imag component to dual, using the correct nomenclature Also removed incomplete test from unit tests. --- libraries/render-utils/src/Skinning.slh | 38 ++++++++++++------------ libraries/shared/src/DualQuaternion.cpp | 28 ++++++++--------- libraries/shared/src/DualQuaternion.h | 8 ++--- tests/shared/src/DualQuaternionTests.cpp | 38 ++---------------------- tests/shared/src/DualQuaternionTests.h | 1 - 5 files changed, 40 insertions(+), 73 deletions(-) diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index ddcdd2c71f..49d0df3d2c 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -24,7 +24,7 @@ layout(std140) uniform skinClusterBuffer { <@if SKIN_DQ@> -mat4 dualQuatToMat4(vec4 real, vec4 imag) { +mat4 dualQuatToMat4(vec4 real, vec4 dual) { float twoRealXSq = 2.0 * real.x * real.x; float twoRealYSq = 2.0 * real.y * real.y; float twoRealZSq = 2.0 * real.z * real.z; @@ -46,9 +46,9 @@ mat4 dualQuatToMat4(vec4 real, vec4 imag) { 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), + vec4 col3 = vec4(2.0 * (-dual.w * real.x + dual.x * real.w - dual.y * real.z + dual.z * real.y), + 2.0 * (-dual.w * real.y + dual.x * real.z + dual.y * real.w - dual.z * real.x), + 2.0 * (-dual.w * real.z - dual.x * real.y + dual.y * real.x + dual.z * real.w), 1.0); return mat4(col0, col1, col2, col3); @@ -60,7 +60,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio // 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 dAccum = 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])]; @@ -68,7 +68,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio vec3 scale = vec3(clusterMatrix[0]); vec4 real = clusterMatrix[1]; - vec4 imag = clusterMatrix[2]; + vec4 dual = clusterMatrix[2]; // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; @@ -78,16 +78,16 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio sAccum += scale * clusterWeight; rAccum += real * dqClusterWeight; - iAccum += imag * dqClusterWeight; + dAccum += dual * dqClusterWeight; } // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; - iAccum /= norm; + dAccum /= norm; // conversion from dual quaternion to 4x4 matrix. - mat4 m = dualQuatToMat4(rAccum, iAccum); + mat4 m = dualQuatToMat4(rAccum, dAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); } @@ -97,7 +97,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP // 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 dAccum = vec4(0.0, 0.0, 0.0, 0.0); vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1]; for (int i = 0; i < INDICES_PER_VERTEX; i++) { @@ -106,7 +106,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP vec3 scale = vec3(clusterMatrix[0]); vec4 real = clusterMatrix[1]; - vec4 imag = clusterMatrix[2]; + vec4 dual = clusterMatrix[2]; // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; @@ -116,16 +116,16 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP sAccum += scale * clusterWeight; rAccum += real * dqClusterWeight; - iAccum += imag * dqClusterWeight; + dAccum += dual * dqClusterWeight; } // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; - iAccum /= norm; + dAccum /= norm; // conversion from dual quaternion to 4x4 matrix. - mat4 m = dualQuatToMat4(rAccum, iAccum); + mat4 m = dualQuatToMat4(rAccum, dAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); skinnedNormal = vec3(m * vec4(inNormal, 0)); } @@ -136,7 +136,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v // 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 dAccum = vec4(0.0, 0.0, 0.0, 0.0); vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1]; for (int i = 0; i < INDICES_PER_VERTEX; i++) { @@ -145,7 +145,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v vec3 scale = vec3(clusterMatrix[0]); vec4 real = clusterMatrix[1]; - vec4 imag = clusterMatrix[2]; + vec4 dual = clusterMatrix[2]; // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; @@ -155,16 +155,16 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v sAccum += scale * clusterWeight; rAccum += real * dqClusterWeight; - iAccum += imag * dqClusterWeight; + dAccum += dual * dqClusterWeight; } // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; - iAccum /= norm; + dAccum /= norm; // conversion from dual quaternion to 4x4 matrix. - mat4 m = dualQuatToMat4(rAccum, iAccum); + mat4 m = dualQuatToMat4(rAccum, dAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); skinnedNormal = vec3(m * vec4(inNormal, 0)); skinnedTangent = vec3(m * vec4(inTangent, 0)); diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index 03628f8aba..2accbed2a9 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -12,42 +12,42 @@ #include "GLMHelpers.h" // delegating constructor -DualQuaternion::DualQuaternion() : _real(1.0f, 0.0f, 0.0f, 0.0), _imag(0.0f, 0.0f, 0.0f, 0.0f) { +DualQuaternion::DualQuaternion() : _real(1.0f, 0.0f, 0.0f, 0.0), _dual(0.0f, 0.0f, 0.0f, 0.0f) { } DualQuaternion::DualQuaternion(const glm::mat4& m) : DualQuaternion(glmExtractRotation(m), extractTranslation(m)) { } -DualQuaternion::DualQuaternion(const glm::quat& real, const glm::quat& imag) : _real(real), _imag(imag) { +DualQuaternion::DualQuaternion(const glm::quat& real, const glm::quat& dual) : _real(real), _dual(dual) { } -DualQuaternion::DualQuaternion(const glm::vec4& real, const glm::vec4& imag) : +DualQuaternion::DualQuaternion(const glm::vec4& real, const glm::vec4& dual) : _real(real.w, real.x, real.y, real.z), - _imag(imag.w, imag.x, imag.y, imag.z) { + _dual(dual.w, dual.x, dual.y, dual.z) { } DualQuaternion::DualQuaternion(const glm::quat& rotation, const glm::vec3& translation) { _real = rotation; - _imag = glm::quat(0.0f, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation; + _dual = glm::quat(0.0f, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation; } DualQuaternion DualQuaternion::operator*(const DualQuaternion& rhs) const { - return DualQuaternion(_real * rhs._real, _real * rhs._imag + _imag * rhs._real); + return DualQuaternion(_real * rhs._real, _real * rhs._dual + _dual * rhs._real); } DualQuaternion DualQuaternion::operator*(float scalar) const { - return DualQuaternion(_real * scalar, _imag * scalar); + return DualQuaternion(_real * scalar, _dual * scalar); } DualQuaternion DualQuaternion::operator+(const DualQuaternion& rhs) const { - return DualQuaternion(_real + rhs._real, _imag + rhs._imag); + return DualQuaternion(_real + rhs._real, _dual + rhs._dual); } glm::vec3 DualQuaternion::xformPoint(const glm::vec3& rhs) const { DualQuaternion v(glm::quat(), glm::quat(0.0f, rhs.x, rhs.y, rhs.z)); - DualQuaternion dualConj(glm::conjugate(_real), -glm::conjugate(_imag)); + DualQuaternion dualConj(glm::conjugate(_real), -glm::conjugate(_dual)); DualQuaternion result = *this * v * dualConj; - return vec3(result._imag.x, result._imag.y, result._imag.z); + return vec3(result._dual.x, result._dual.y, result._dual.z); } glm::quat DualQuaternion::getRotation() const { @@ -55,7 +55,7 @@ glm::quat DualQuaternion::getRotation() const { } glm::vec3 DualQuaternion::getTranslation() const { - glm::quat result = 2.0f * (_imag * glm::inverse(_real)); + glm::quat result = 2.0f * (_dual * glm::inverse(_real)); return glm::vec3(result.x, result.y, result.z); } @@ -65,11 +65,11 @@ glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const { DualQuaternion DualQuaternion::inverse() const { glm::quat invReal = glm::inverse(_real); - return DualQuaternion(invReal, - invReal * _imag * invReal); + return DualQuaternion(invReal, - invReal * _dual * invReal); } DualQuaternion DualQuaternion::conjugate() const { - return DualQuaternion(glm::conjugate(_real), glm::conjugate(_imag)); + return DualQuaternion(glm::conjugate(_real), glm::conjugate(_dual)); } float DualQuaternion::length() const { @@ -88,5 +88,5 @@ float DualQuaternion::dot(const DualQuaternion& rhs) const { } DualQuaternion DualQuaternion::operator-() const { - return DualQuaternion(-_real, -_imag); + return DualQuaternion(-_real, -_dual); } diff --git a/libraries/shared/src/DualQuaternion.h b/libraries/shared/src/DualQuaternion.h index 508570a930..709c089fdc 100644 --- a/libraries/shared/src/DualQuaternion.h +++ b/libraries/shared/src/DualQuaternion.h @@ -31,8 +31,8 @@ public: const glm::quat& real() const { return _real; } glm::quat& real() { return _real; } - const glm::quat& imag() const { return _imag; } - glm::quat& imag() { return _imag; } + const glm::quat& dual() const { return _dual; } + glm::quat& dual() { return _dual; } glm::quat getRotation() const; glm::vec3 getTranslation() const; @@ -50,12 +50,12 @@ public: protected: friend QDebug operator<<(QDebug debug, const DualQuaternion& pose); glm::quat _real; - glm::quat _imag; + glm::quat _dual; }; inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) { - debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), imag = (" << dq._imag.x << dq._imag.y << dq._imag.z << dq._imag.w << ")"; + debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), dual = (" << dq._dual.x << dq._dual.y << dq._dual.z << dq._dual.w << ")"; return debug; } diff --git a/tests/shared/src/DualQuaternionTests.cpp b/tests/shared/src/DualQuaternionTests.cpp index 1c34bfbee7..fe14d9d166 100644 --- a/tests/shared/src/DualQuaternionTests.cpp +++ b/tests/shared/src/DualQuaternionTests.cpp @@ -31,11 +31,11 @@ static void quatComp(const glm::quat& q1, const glm::quat& q2) { void DualQuaternionTests::ctor() { glm::quat real = angleAxis(PI / 2.0f, Vectors::UNIT_Y); - glm::quat imag(0.0f, 1.0f, 2.0f, 3.0f); + glm::quat dual(0.0f, 1.0f, 2.0f, 3.0f); - DualQuaternion dq(real, imag); + DualQuaternion dq(real, dual); quatComp(real, dq.real()); - quatComp(imag, dq.imag()); + quatComp(dual, dq.dual()); glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X); glm::vec3 translation(1.0, 2.0f, 3.0f); @@ -113,35 +113,3 @@ void DualQuaternionTests::trans() { QCOMPARE_WITH_ABS_ERROR(t2, dq2.getTranslation(), 0.001f); QCOMPARE_WITH_ABS_ERROR(t3, dq3.getTranslation(), 0.001f); } - -// Dual Quaternion Linear Blending test -void DualQuaternionTests::dlb() { - DualQuaternion dq1(Quaternions::IDENTITY, glm::vec3()); - DualQuaternion dq2(angleAxis(PI / 2.0f, Vectors::UNIT_X), glm::vec3(0.0f, 1.0f, 0.0f)); - DualQuaternion dq2Alt(-angleAxis(PI / 2.0f, Vectors::UNIT_X), glm::vec3(0.0f, 1.0f, 0.0f)); - - qDebug() << "dq1 =" << dq1; - qDebug() << "dq2 =" << dq2; - - // linear blend between dq1 and dq2 - DualQuaternion dq3 = dq1 * 0.5f + dq2 * 0.5f; - - // alternate linear blend between dq1 and dq2 - DualQuaternion dq4 = dq1 * 0.5 + dq2Alt * 0.5f; - - qDebug() << "dq3 =" << dq3; - qDebug() << "dq4 =" << dq4; - - glm::vec3 p1(0.0f, 0.5f, -0.5f); - glm::vec3 p2(0.0f, 0.5f, 0.5f); - - glm::vec3 p3 = dq3.xformPoint(p1); - glm::vec3 p4 = dq3.xformPoint(p2); - glm::vec3 p5 = dq4.xformPoint(p1); - glm::vec3 p6 = dq4.xformPoint(p2); - - qDebug() << "p3 =" << p3; - qDebug() << "p4 =" << p4; - qDebug() << "p5 =" << p5; - qDebug() << "p6 =" << p6; -} diff --git a/tests/shared/src/DualQuaternionTests.h b/tests/shared/src/DualQuaternionTests.h index 988973b689..aa4b40cfd6 100644 --- a/tests/shared/src/DualQuaternionTests.h +++ b/tests/shared/src/DualQuaternionTests.h @@ -20,7 +20,6 @@ private slots: void mult(); void xform(); void trans(); - void dlb(); }; #endif // hifi_DualQuaternionTests_h From ad2a0310608816b7e0de13c1ae69f9bdc8a5f08d Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 9 Jan 2018 16:44:48 -0800 Subject: [PATCH 18/43] Fix bug in audio-mixer audio packet parsing. Codec string was being read as channel flag. --- assignment-client/src/audio/AudioMixerClientData.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 49453c6fc6..b7974c88fc 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -275,9 +275,13 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { if (micStreamIt == _audioStreams.end()) { // we don't have a mic stream yet, so add it - // read the channel flag to see if our stream is stereo or not + // hop past the sequence number that leads the packet message.seek(sizeof(quint16)); + // pull the codec string from the packet + auto codecString = message.readString(); + + // read the channel flag to see if our stream is stereo or not quint8 channelFlag; message.readPrimitive(&channelFlag); @@ -285,7 +289,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames()); avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); - qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName << "channels:" << (channelFlag + 1); connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); From c363a9281e3e1e373a3dff9bfa2765b0bcf4d81e Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 9 Jan 2018 16:54:14 -0800 Subject: [PATCH 19/43] Fix another bug in audio-mixer audio packet parsing. For SilentAudioFrame packets, numSamples was being read as channel flag. --- .../src/audio/AudioMixerClientData.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b7974c88fc..394224b8f4 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -281,15 +281,21 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // pull the codec string from the packet auto codecString = message.readString(); - // read the channel flag to see if our stream is stereo or not - quint8 channelFlag; - message.readPrimitive(&channelFlag); - - bool isStereo = channelFlag == 1; + // determine if the stream is stereo or not + bool isStereo; + if (packetType == PacketType::SilentAudioFrame) { + quint16 numSilentSamples; + message.readPrimitive(&numSilentSamples); + isStereo = numSilentSamples == AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; + } else { + quint8 channelFlag; + message.readPrimitive(&channelFlag); + isStereo = channelFlag == 1; + } auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames()); avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); - qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName << "channels:" << (channelFlag + 1); + qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName << "channels:" << (isStereo ? 2 : 1); connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); From 660032d8fb848322798b0fb8aeacd21c132be48b Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 10 Jan 2018 06:54:27 -0800 Subject: [PATCH 20/43] Fix bug in how emitAudioPacket() determines mono/stereo. Compressed bytes were counted as if audio samples. --- assignment-client/src/Agent.cpp | 2 +- libraries/audio-client/src/AudioClient.cpp | 2 +- libraries/audio/src/AbstractAudioInterface.cpp | 8 +++----- libraries/audio/src/AbstractAudioInterface.h | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2fc905c6fd..d1c2c6597b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -439,7 +439,7 @@ void Agent::executeScript() { encodedBuffer = audio; } - AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, + AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, false, audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0), packetType, _selectedCodecName); }); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index af86499101..e688b69266 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1079,7 +1079,7 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) { encodedBuffer = audioBuffer; } - emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, + emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput, audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, packetType, _selectedCodecName); _stats.sentPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.cpp b/libraries/audio/src/AbstractAudioInterface.cpp index 4def97596f..376ecddd34 100644 --- a/libraries/audio/src/AbstractAudioInterface.cpp +++ b/libraries/audio/src/AbstractAudioInterface.cpp @@ -19,7 +19,7 @@ #include "AudioConstants.h" -void AbstractAudioInterface::emitAudioPacket(const void* audioData, size_t bytes, quint16& sequenceNumber, +void AbstractAudioInterface::emitAudioPacket(const void* audioData, size_t bytes, quint16& sequenceNumber, bool isStereo, const Transform& transform, glm::vec3 avatarBoundingBoxCorner, glm::vec3 avatarBoundingBoxScale, PacketType packetType, QString codecName) { static std::mutex _mutex; @@ -30,9 +30,6 @@ void AbstractAudioInterface::emitAudioPacket(const void* audioData, size_t bytes Locker lock(_mutex); auto audioPacket = NLPacket::create(packetType); - // FIXME - this is not a good way to determine stereoness with codecs.... - quint8 isStereo = bytes == AudioConstants::NETWORK_FRAME_BYTES_STEREO ? 1 : 0; - // write sequence number auto sequence = sequenceNumber++; audioPacket->writePrimitive(sequence); @@ -48,7 +45,8 @@ void AbstractAudioInterface::emitAudioPacket(const void* audioData, size_t bytes audioPacket->writePrimitive(numSilentSamples); } else { // set the mono/stereo byte - audioPacket->writePrimitive(isStereo); + quint8 channelFlag = isStereo ? 1 : 0; + audioPacket->writePrimitive(channelFlag); } // pack the three float positions diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 8b48b55206..37731c31f7 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -29,7 +29,7 @@ class AbstractAudioInterface : public QObject { public: AbstractAudioInterface(QObject* parent = 0) : QObject(parent) {}; - static void emitAudioPacket(const void* audioData, size_t bytes, quint16& sequenceNumber, + static void emitAudioPacket(const void* audioData, size_t bytes, quint16& sequenceNumber, bool isStereo, const Transform& transform, glm::vec3 avatarBoundingBoxCorner, glm::vec3 avatarBoundingBoxScale, PacketType packetType, QString codecName = QString("")); From 6a2e3cc27250e01eacdcc06bfe45c1f4451d38ca Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 10 Jan 2018 15:14:18 -0800 Subject: [PATCH 21/43] Enable stereo codecs for AvatarAudioStream --- assignment-client/src/audio/AudioMixerClientData.cpp | 11 ++++++----- libraries/audio-client/src/AudioClient.cpp | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 394224b8f4..f6298ce1b9 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -283,7 +283,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // determine if the stream is stereo or not bool isStereo; - if (packetType == PacketType::SilentAudioFrame) { + if (packetType == PacketType::SilentAudioFrame + || packetType == PacketType::ReplicatedSilentAudioFrame) { quint16 numSilentSamples; message.readPrimitive(&numSilentSamples); isStereo = numSilentSamples == AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; @@ -294,8 +295,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { } auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames()); - avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); - qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName << "channels:" << (isStereo ? 2 : 1); + avatarAudioStream->setupCodec(_codec, _selectedCodecName, isStereo ? AudioConstants::STEREO : AudioConstants::MONO); + qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName << "isStereo:" << isStereo; connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); @@ -334,7 +335,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { #if INJECTORS_SUPPORT_CODECS injectorStream->setupCodec(_codec, _selectedCodecName, isStereo ? AudioConstants::STEREO : AudioConstants::MONO); - qCDebug(audio) << "creating new injectorStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new injectorStream... codec:" << _selectedCodecName << "isStereo:" << isStereo; #endif auto emplaced = _audioStreams.emplace( @@ -577,7 +578,7 @@ void AudioMixerClientData::setupCodec(CodecPluginPointer codec, const QString& c auto avatarAudioStream = getAvatarAudioStream(); if (avatarAudioStream) { - avatarAudioStream->setupCodec(codec, codecName, AudioConstants::MONO); + avatarAudioStream->setupCodec(codec, codecName, avatarAudioStream->isStereo() ? AudioConstants::STEREO : AudioConstants::MONO); } #if INJECTORS_SUPPORT_CODECS diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index e688b69266..2e347f88df 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -782,7 +782,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { _selectedCodecName = selectedCodecName; - qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName; + qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput; // release any old codec encoder/decoder first... if (_codec && _encoder) { @@ -797,7 +797,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { if (_selectedCodecName == plugin->getName()) { _codec = plugin; _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); - _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); + _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, _isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO); qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get(); break; } From c39771d995bee4180cf639b74976566ab8294219 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 11 Jan 2018 11:50:23 -0800 Subject: [PATCH 22/43] do not delete wallet file when things go wrong, and remove obsolete reset machinery --- .../qml/hifi/commerce/wallet/Help.qml | 32 ------------------- interface/src/commerce/Ledger.cpp | 7 ---- interface/src/commerce/Ledger.h | 1 - interface/src/commerce/QmlCommerce.cpp | 12 ------- interface/src/commerce/QmlCommerce.h | 2 -- interface/src/commerce/Wallet.cpp | 26 ++++----------- interface/src/commerce/Wallet.h | 2 -- 7 files changed, 7 insertions(+), 75 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 409833df98..f0f123f6c0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -25,7 +25,6 @@ Item { id: root; property string keyFilePath; - property bool showDebugButtons: true; Connections { target: Commerce; @@ -55,37 +54,6 @@ Item { // Style color: hifi.colors.blueHighlight; } - HifiControlsUit.Button { - id: clearCachedPassphraseButton; - visible: root.showDebugButtons; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.left: helpTitleText.right; - anchors.leftMargin: 20; - height: 40; - width: 150; - text: "DBG: Clear Pass"; - onClicked: { - Commerce.setPassphrase(""); - sendSignalToWallet({method: 'passphraseReset'}); - } - } - HifiControlsUit.Button { - id: resetButton; - visible: root.showDebugButtons; - color: hifi.buttons.red; - colorScheme: hifi.colorSchemes.dark; - anchors.top: clearCachedPassphraseButton.top; - anchors.left: clearCachedPassphraseButton.right; - height: 40; - width: 150; - text: "DBG: RST Wallet"; - onClicked: { - Commerce.reset(); - sendSignalToWallet({method: 'walletReset'}); - } - } ListModel { id: helpModel; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 51658ddef8..15830636f0 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -189,13 +189,6 @@ void Ledger::history(const QStringList& keys, const int& pageNumber) { keysQuery("history", "historySuccess", "historyFailure", params); } -// The api/failResponse is called just for the side effect of logging. -void Ledger::resetSuccess(QNetworkReply& reply) { apiResponse("reset", reply); } -void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply); } -void Ledger::reset() { - send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, QJsonObject()); -} - void Ledger::accountSuccess(QNetworkReply& reply) { // lets set the appropriate stuff in the wallet now auto wallet = DependencyManager::get(); diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 5d90aa0808..19699a69d6 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -31,7 +31,6 @@ public: void inventory(const QStringList& keys); void history(const QStringList& keys, const int& pageNumber); void account(); - void reset(); void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 320c7e041c..58548eb3ef 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -128,18 +128,6 @@ void QmlCommerce::generateKeyPair() { getWalletAuthenticatedStatus(); } -void QmlCommerce::reset() { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - ledger->reset(); - wallet->reset(); -} - -void QmlCommerce::resetLocalWalletOnly() { - auto wallet = DependencyManager::get(); - wallet->reset(); -} - void QmlCommerce::account() { auto ledger = DependencyManager::get(); ledger->account(); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index f2e6c82021..c04ede86c4 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -62,8 +62,6 @@ protected: Q_INVOKABLE void inventory(); Q_INVOKABLE void history(const int& pageNumber); Q_INVOKABLE void generateKeyPair(); - Q_INVOKABLE void reset(); - Q_INVOKABLE void resetLocalWalletOnly(); Q_INVOKABLE void account(); Q_INVOKABLE void certificateInfo(const QString& certificateId); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index c3c91e82a8..8b73042ada 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -144,15 +144,13 @@ bool writeKeys(const char* filename, EC_KEY* keys) { if ((fp = fopen(filename, "wt"))) { if (!PEM_write_EC_PUBKEY(fp, keys)) { fclose(fp); - qCDebug(commerce) << "failed to write public key"; - QFile(QString(filename)).remove(); + qCCritical(commerce) << "failed to write public key"; return retval; } if (!PEM_write_ECPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { fclose(fp); - qCDebug(commerce) << "failed to write private key"; - QFile(QString(filename)).remove(); + qCCritical(commerce) << "failed to write private key"; return retval; } @@ -168,7 +166,8 @@ bool writeKeys(const char* filename, EC_KEY* keys) { QPair generateECKeypair() { EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1); - QPair retval; + QPair retval{}; + EC_KEY_set_asn1_flag(keyPair, OPENSSL_EC_NAMED_CURVE); if (!EC_KEY_generate_key(keyPair)) { qCDebug(commerce) << "Error generating EC Keypair -" << ERR_get_error(); @@ -517,6 +516,9 @@ bool Wallet::generateKeyPair() { qCInfo(commerce) << "Generating keypair."; auto keyPair = generateECKeypair(); + if (!keyPair.first) { + return false; + } writeBackupInstructions(); @@ -653,20 +655,6 @@ QString Wallet::getKeyFilePath() { } } -void Wallet::reset() { - _publicKeys.clear(); - - delete _securityImage; - _securityImage = nullptr; - - // tell the provider we got nothing - updateImageProvider(); - _passphrase->clear(); - - - QFile keyFile(keyFilePath()); - keyFile.remove(); -} bool Wallet::writeWallet(const QString& newPassphrase) { EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str()); if (keys) { diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index ed145df451..fe3a9f1d5f 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -49,8 +49,6 @@ public: bool walletIsAuthenticatedWithPassphrase(); bool changePassphrase(const QString& newPassphrase); - void reset(); - void getWalletStatus(); enum WalletStatus { WALLET_STATUS_NOT_LOGGED_IN = 0, From d225f803d0c2bc70abd4939b9efa474318053081 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 11 Jan 2018 12:28:44 -0800 Subject: [PATCH 23/43] Corrected default values. --- libraries/entities/src/EntityItemProperties.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index d0dabbf5b6..e334e5f669 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -185,9 +185,9 @@ public: DEFINE_PROPERTY_REF(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE); DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString, ENTITY_ITEM_DEFAULT_NAME); - DEFINE_PROPERTY_REF_ENUM(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t, (uint32_t)COMPONENT_MODE_ENABLED); - DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_ENABLED); - DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_ENABLED); + DEFINE_PROPERTY_REF_ENUM(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); // This is the default mode for zone creation DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); From 2987d21f661db6d1852c22ddc4329e8dad915d3e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 11 Jan 2018 13:15:34 -0800 Subject: [PATCH 24/43] remove some more --- interface/src/commerce/Ledger.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 19699a69d6..318006b645 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -65,8 +65,6 @@ public slots: void inventoryFailure(QNetworkReply& reply); void historySuccess(QNetworkReply& reply); void historyFailure(QNetworkReply& reply); - void resetSuccess(QNetworkReply& reply); - void resetFailure(QNetworkReply& reply); void accountSuccess(QNetworkReply& reply); void accountFailure(QNetworkReply& reply); void updateLocationSuccess(QNetworkReply& reply); From 4bd09fd9afbd7e45d216cd0f182dfc51a73cc2ea Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 11 Jan 2018 14:53:58 -0800 Subject: [PATCH 25/43] Corrected default values - for reading legacy content. --- libraries/entities/src/EntityTree.cpp | 38 +++++++++----------- libraries/networking/src/udt/PacketHeaders.h | 2 +- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ae243623f6..50455ae6be 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -39,11 +39,9 @@ #include "EntityEditFilters.h" #include "EntityDynamicFactoryInterface.h" - static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour - // combines the ray cast arguments into a single object class RayArgs { public: @@ -2281,28 +2279,25 @@ bool EntityTree::readFromMap(QVariantMap& map) { properties.setOwningAvatarID(myNodeID); } - // TEMPORARY fix for older content not containing these fields in the zones - if (properties.getType() == EntityTypes::EntityType::Zone) { - if (!entityMap.contains("keyLightMode")) { - properties.setKeyLightMode(COMPONENT_MODE_ENABLED); + // Fix for older content not containing these fields in the zones + int contentVersion = map["Version"].toInt(); + bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); + if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) { + // The background should be enabled if the mode is skybox + // Note that if the values are default then they are not stored in the JSON file + if (entityMap.contains("backgroundMode") && (entityMap["backgroundMode"].toString() == "skybox")) { + properties.setSkyboxMode(COMPONENT_MODE_ENABLED); + } else { + properties.setSkyboxMode(COMPONENT_MODE_INHERIT); } - if (!entityMap.contains("skyboxMode")) { - if (entityMap.contains("backgroundMode") && (entityMap["backgroundMode"].toString() == "nothing")) { - properties.setSkyboxMode(COMPONENT_MODE_INHERIT); - } else { - // Either the background mode field is missing (shouldn't happen) or the background mode is "skybox" - properties.setSkyboxMode(COMPONENT_MODE_ENABLED); + // The legacy version had no keylight/ambient modes - these are always on + properties.setKeyLightMode(COMPONENT_MODE_ENABLED); + properties.setAmbientLightMode(COMPONENT_MODE_ENABLED); - // Copy the skybox URL if the ambient URL is empty, as this is the legacy behaviour - if (properties.getAmbientLight().getAmbientURL() == "") { - properties.getAmbientLight().setAmbientURL(properties.getSkybox().getURL()); - } - } - } - - if (!entityMap.contains("ambientLightMode")) { - properties.setAmbientLightMode(COMPONENT_MODE_ENABLED); + // Copy the skybox URL if the ambient URL is empty, as this is the legacy behaviour + if (properties.getAmbientLight().getAmbientURL() == "") { + properties.getAmbientLight().setAmbientURL(properties.getSkybox().getURL()); } } @@ -2312,6 +2307,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { success = false; } } + return success; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7eafbbccf5..deddeb4153 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -202,7 +202,7 @@ enum class EntityVersion : PacketVersion { HazeEffect, StaticCertJsonVersionOne, OwnershipChallengeFix, - ZoneLightInheritModes, + ZoneLightInheritModes = 82, ZoneStageRemoved }; From 311e95e0d0bbfed4d84324aa30d505c245f4ff06 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 11 Jan 2018 14:57:22 -0800 Subject: [PATCH 26/43] Corrected default values - for reading legacy content. --- libraries/entities/src/EntityItemProperties.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index e334e5f669..c3d04dc7ad 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -188,8 +188,6 @@ public: DEFINE_PROPERTY_REF_ENUM(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); - - // This is the default mode for zone creation DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); From 467a7eaf2dbc47245daf49299a014f8d5a68fda0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 11 Jan 2018 15:40:53 -0800 Subject: [PATCH 27/43] Fix for elbow glitches The pole vector constraint calculation within the IK system would sometimes compute the incorrect rotations. This would be visible as an instantaneous snap of the elbow joint as the bicep was curled. When applying pole vector constraints, there needs to be two methods of determining the current orientation of the elbow joint. One for when the arm/elbow joint is bent, and one for when the arm/elbow is straight. Previously, the way we would switch between these two solutions could cause a large rotation delta to accur between very small angles. Now we use the more accurate method (1) more often, and we smoothly blend between the solutions as the joint gets straighter. --- .../animation/src/AnimInverseKinematics.cpp | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index d17fbebf3a..15c7cfbb57 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -591,19 +591,31 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const glm::vec3 d = basePose.trans() - topPose.trans(); float dLen = glm::length(d); if (dLen > EPSILON) { + glm::vec3 dUnit = d / dLen; glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); + + // if mid joint is straight use the reference vector to compute eProj, otherwise use reference vector. + // however if mid joint angle is in between the two blend between both solutions. + vec3 u = normalize(basePose.trans() - midPose.trans()); + vec3 v = normalize(topPose.trans() - midPose.trans()); + + const float LERP_THRESHOLD = 3.05433f; // 175 deg + const float BENT_THRESHOLD = 2.96706f; // 170 deg + + float jointAngle = acos(dot(u, v)); + if (jointAngle < BENT_THRESHOLD) { + glm::vec3 midPoint = topPose.trans() + d * 0.5f; + e = normalize(midPose.trans() - midPoint); + } else if (jointAngle < LERP_THRESHOLD) { + glm::vec3 midPoint = topPose.trans() + d * 0.5f; + float alpha = (jointAngle - LERP_THRESHOLD) / (BENT_THRESHOLD - LERP_THRESHOLD); + e = lerp(e, normalize(midPose.trans() - midPoint), alpha); + } + glm::vec3 eProj = e - glm::dot(e, dUnit) * dUnit; float eProjLen = glm::length(eProj); - const float MIN_EPROJ_LEN = 0.5f; - if (eProjLen < MIN_EPROJ_LEN) { - glm::vec3 midPoint = topPose.trans() + d * 0.5f; - e = midPose.trans() - midPoint; - eProj = e - glm::dot(e, dUnit) * dUnit; - eProjLen = glm::length(eProj); - } - glm::vec3 p = target.getPoleVector(); glm::vec3 pProj = p - glm::dot(p, dUnit) * dUnit; float pProjLen = glm::length(pProj); @@ -636,15 +648,31 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const glm::vec3 dUnit = d / dLen; glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); + + + // if mid joint is straight use the reference vector to compute eProj, otherwise use reference vector. + // however if mid joint angle is in between the two blend between both solutions. + vec3 u = normalize(basePose.trans() - midPose.trans()); + vec3 v = normalize(topPose.trans() - midPose.trans()); + + const float LERP_THRESHOLD = 3.05433f; // 175 deg + const float BENT_THRESHOLD = 2.96706f; // 170 deg + + float jointAngle = acos(dot(u, v)); + glm::vec4 eColor = RED; + if (jointAngle < BENT_THRESHOLD) { + glm::vec3 midPoint = topPose.trans() + d * 0.5f; + e = normalize(midPose.trans() - midPoint); + eColor = GREEN; + } else if (jointAngle < LERP_THRESHOLD) { + glm::vec3 midPoint = topPose.trans() + d * 0.5f; + float alpha = (jointAngle - LERP_THRESHOLD) / (BENT_THRESHOLD - LERP_THRESHOLD); + e = lerp(e, normalize(midPose.trans() - midPoint), alpha); + eColor = YELLOW; + } + glm::vec3 eProj = e - glm::dot(e, dUnit) * dUnit; float eProjLen = glm::length(eProj); - const float MIN_EPROJ_LEN = 0.5f; - if (eProjLen < MIN_EPROJ_LEN) { - glm::vec3 midPoint = topPose.trans() + d * 0.5f; - e = midPose.trans() - midPoint; - eProj = e - glm::dot(e, dUnit) * dUnit; - eProjLen = glm::length(eProj); - } glm::vec3 p = target.getPoleVector(); const float PROJ_VECTOR_LEN = 10.0f; @@ -655,7 +683,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const YELLOW); DebugDraw::getInstance().drawRay(geomToWorldPose.xformPoint(midPoint), geomToWorldPose.xformPoint(midPoint + PROJ_VECTOR_LEN * glm::normalize(e)), - RED); + eColor); DebugDraw::getInstance().drawRay(geomToWorldPose.xformPoint(midPoint), geomToWorldPose.xformPoint(midPoint + POLE_VECTOR_LEN * glm::normalize(p)), BLUE); From 7c5085bd24d470f8f8f3f9d03091dc875d4aeb0e Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Jan 2018 16:10:50 -0800 Subject: [PATCH 28/43] Handle stereo changes while active, by restarting the codec on both ends --- assignment-client/src/audio/AudioMixerClientData.cpp | 1 + assignment-client/src/audio/AvatarAudioStream.cpp | 10 ++++++++++ libraries/audio-client/src/AudioClient.cpp | 11 ++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index f6298ce1b9..2560f43337 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -579,6 +579,7 @@ void AudioMixerClientData::setupCodec(CodecPluginPointer codec, const QString& c auto avatarAudioStream = getAvatarAudioStream(); if (avatarAudioStream) { avatarAudioStream->setupCodec(codec, codecName, avatarAudioStream->isStereo() ? AudioConstants::STEREO : AudioConstants::MONO); + qCDebug(audio) << "setting AvatarAudioStream... codec:" << _selectedCodecName << "isStereo:" << avatarAudioStream->isStereo(); } #if INJECTORS_SUPPORT_CODECS diff --git a/assignment-client/src/audio/AvatarAudioStream.cpp b/assignment-client/src/audio/AvatarAudioStream.cpp index 1e0c3ed9e6..42495b4dd0 100644 --- a/assignment-client/src/audio/AvatarAudioStream.cpp +++ b/assignment-client/src/audio/AvatarAudioStream.cpp @@ -11,6 +11,7 @@ #include +#include "AudioLogging.h" #include "AvatarAudioStream.h" AvatarAudioStream::AvatarAudioStream(bool isStereo, int numStaticJitterFrames) : @@ -41,6 +42,15 @@ int AvatarAudioStream::parseStreamProperties(PacketType type, const QByteArray& _ringBuffer.resizeForFrameSize(isStereo ? AudioConstants::NETWORK_FRAME_SAMPLES_STEREO : AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + // restart the codec + if (_codec) { + if (_decoder) { + _codec->releaseDecoder(_decoder); + } + _decoder = _codec->createDecoder(AudioConstants::SAMPLE_RATE, isStereo ? AudioConstants::STEREO : AudioConstants::MONO); + } + qCDebug(audio) << "resetting AvatarAudioStream... codec:" << _selectedCodecName << "isStereo:" << isStereo; + _isStereo = isStereo; } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 2e347f88df..c274f53dca 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1382,7 +1382,16 @@ void AudioClient::setIsStereoInput(bool isStereoInput) { _desiredInputFormat.setChannelCount(1); } - // change in channel count for desired input format, restart the input device + // restart the codec + if (_codec) { + if (_encoder) { + _codec->releaseEncoder(_encoder); + } + _encoder = _codec->createEncoder(AudioConstants::SAMPLE_RATE, _isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO); + } + qCDebug(audioclient) << "Reset Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput; + + // restart the input device switchInputToAudioDevice(_inputDeviceInfo); } } From 86cfeac95c4561ebfef13462ba79082771ace832 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 11 Jan 2018 16:39:44 -0800 Subject: [PATCH 29/43] Moved variable setting to outside of loop. --- libraries/entities/src/EntityTree.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 50455ae6be..b39d88bd46 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2235,6 +2235,10 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer } bool EntityTree::readFromMap(QVariantMap& map) { + // These are needed to deal with older content (before adding inheritance modes) + int contentVersion = map["Version"].toInt(); + bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); + // map will have a top-level list keyed as "Entities". This will be extracted // and iterated over. Each member of this list is converted to a QVariantMap, then // to a QScriptValue, and then to EntityItemProperties. These properties are used @@ -2280,8 +2284,6 @@ bool EntityTree::readFromMap(QVariantMap& map) { } // Fix for older content not containing these fields in the zones - int contentVersion = map["Version"].toInt(); - bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) { // The background should be enabled if the mode is skybox // Note that if the values are default then they are not stored in the JSON file From 983e1fe0759e914de44f1d18f99f658b04afb249 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 11 Jan 2018 17:57:58 -0800 Subject: [PATCH 30/43] warning fixes: removed unused variable. --- libraries/animation/src/AnimInverseKinematics.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 15c7cfbb57..7bf250a32c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -649,7 +649,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const glm::vec3 dUnit = d / dLen; glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); - // if mid joint is straight use the reference vector to compute eProj, otherwise use reference vector. // however if mid joint angle is in between the two blend between both solutions. vec3 u = normalize(basePose.trans() - midPose.trans()); @@ -671,9 +670,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const eColor = YELLOW; } - glm::vec3 eProj = e - glm::dot(e, dUnit) * dUnit; - float eProjLen = glm::length(eProj); - glm::vec3 p = target.getPoleVector(); const float PROJ_VECTOR_LEN = 10.0f; const float POLE_VECTOR_LEN = 100.0f; From f22429d0982526a1fbd0e9f2ce4ad3bbe57d0b1a Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 11 Jan 2018 18:03:11 -0800 Subject: [PATCH 31/43] Working on the shaders --- libraries/networking/src/udt/PacketHeaders.h | 2 +- libraries/render-utils/src/forward_model.slf | 8 ++-- .../src/forward_model_normal_map.slf | 44 +++++++++++++++---- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7eafbbccf5..deddeb4153 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -202,7 +202,7 @@ enum class EntityVersion : PacketVersion { HazeEffect, StaticCertJsonVersionOne, OwnershipChallengeFix, - ZoneLightInheritModes, + ZoneLightInheritModes = 82, ZoneStageRemoved }; diff --git a/libraries/render-utils/src/forward_model.slf b/libraries/render-utils/src/forward_model.slf index 7b708a1d24..8931c605da 100644 --- a/libraries/render-utils/src/forward_model.slf +++ b/libraries/render-utils/src/forward_model.slf @@ -68,7 +68,7 @@ void main(void) { vec3 fragNormal; <$transformEyeToWorldDir(cam, _normal, fragNormal)$> - /* vec4 color = vec4(evalSkyboxGlobalColor( + vec4 color = vec4(evalSkyboxGlobalColor( cam._viewInverse, 1.0, 1.0, @@ -81,8 +81,6 @@ void main(void) { opacity); color.rgb += emissive * isEmissiveEnabled(); - */ - - _fragColor = vec4(albedo, opacity); - +// _fragColor = vec4(albedo, opacity); + _fragColor = color; } diff --git a/libraries/render-utils/src/forward_model_normal_map.slf b/libraries/render-utils/src/forward_model_normal_map.slf index a199483b9f..c86c0731b5 100644 --- a/libraries/render-utils/src/forward_model_normal_map.slf +++ b/libraries/render-utils/src/forward_model_normal_map.slf @@ -12,10 +12,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include ForwardBufferWrite.slh@> + !> + +<@include ForwardGlobalLight.slh@> +<$declareEvalSkyboxGlobalColor()$> <@include model/Material.slh@> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include MaterialTextures.slh@> <$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION, SCATTERING)$> @@ -26,6 +32,8 @@ in vec3 _normal; in vec3 _tangent; in vec3 _color; +out vec4 _fragColor; + void main(void) { Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -40,6 +48,15 @@ void main(void) { <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + float roughness = getMaterialRoughness(mat); <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; @@ -52,13 +69,22 @@ void main(void) { float scattering = getMaterialScattering(mat); <$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>; - packForwardFragment( - viewNormal, - opacity, + vec3 fragPosition = _position.xyz; + + vec4 color = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + viewNormal, albedo, - roughness, - getMaterialMetallic(mat), - emissive, - occlusionTex, - scattering); + fresnel, + metallic, + roughness), + opacity); + + color.rgb += emissive * isEmissiveEnabled(); + +// _fragColor = vec4(albedo, opacity); + _fragColor = color; } From db6e70cb249351833591773ee7a457558bfcd8bb Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Jan 2018 18:14:16 -0800 Subject: [PATCH 32/43] Fix bug when calling switchInputToAudioDevice() with the active device. Pass QAudioDeviceInfo by value to avoid getting clobbered. --- libraries/audio-client/src/AudioClient.cpp | 2 +- libraries/audio-client/src/AudioClient.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c274f53dca..513ccb00e9 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1427,7 +1427,7 @@ void AudioClient::outputFormatChanged() { _receivedAudioStream.outputFormatChanged(_outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT); } -bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo, bool isShutdownRequest) { +bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) { qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() << "]"; bool supportedFormat = false; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 0ceb9c4dc3..c8db742ca2 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -378,7 +378,7 @@ private: void handleLocalEchoAndReverb(QByteArray& inputByteArray); - bool switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo, bool isShutdownRequest = false); + bool switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest = false); bool switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo, bool isShutdownRequest = false); // Callback acceleration dependent calculations From dfc8c86571397146c3dd53db06ed7fe9586f8bc2 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Jan 2018 18:22:34 -0800 Subject: [PATCH 33/43] Fix bug when calling switchOutputToAudioDevice() with the active device. Pass QAudioDeviceInfo by value to avoid getting clobbered. --- libraries/audio-client/src/AudioClient.cpp | 2 +- libraries/audio-client/src/AudioClient.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 513ccb00e9..579910d9f7 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1610,7 +1610,7 @@ void AudioClient::outputNotify() { } } -bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo, bool isShutdownRequest) { +bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) { qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]"; bool supportedFormat = false; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index c8db742ca2..0643b8e52a 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -379,7 +379,7 @@ private: void handleLocalEchoAndReverb(QByteArray& inputByteArray); bool switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest = false); - bool switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo, bool isShutdownRequest = false); + bool switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest = false); // Callback acceleration dependent calculations int calculateNumberOfInputCallbackBytes(const QAudioFormat& format) const; From a1f25bf49c3f60b41fa91095250f4310ed1f137c Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Thu, 11 Jan 2018 19:35:13 -0800 Subject: [PATCH 34/43] Moved variable setting to outside of loop. Added copy of ambient URL. --- libraries/entities/src/EntityTree.cpp | 15 +++++++++------ libraries/networking/src/udt/PacketHeaders.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b39d88bd46..b7b560290e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2285,22 +2285,25 @@ bool EntityTree::readFromMap(QVariantMap& map) { // Fix for older content not containing these fields in the zones if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) { + // The ambient URL has been moved from "keyLight" to "ambientLight" + properties.getAmbientLight().setAmbientURL(entityMap["ambientURL"].toString()); + // The background should be enabled if the mode is skybox // Note that if the values are default then they are not stored in the JSON file if (entityMap.contains("backgroundMode") && (entityMap["backgroundMode"].toString() == "skybox")) { properties.setSkyboxMode(COMPONENT_MODE_ENABLED); - } else { + + // Copy the skybox URL if the ambient URL is empty, as this is the legacy behaviour + if (properties.getAmbientLight().getAmbientURL() == "") { + properties.getAmbientLight().setAmbientURL(properties.getSkybox().getURL()); + } + } else { properties.setSkyboxMode(COMPONENT_MODE_INHERIT); } // The legacy version had no keylight/ambient modes - these are always on properties.setKeyLightMode(COMPONENT_MODE_ENABLED); properties.setAmbientLightMode(COMPONENT_MODE_ENABLED); - - // Copy the skybox URL if the ambient URL is empty, as this is the legacy behaviour - if (properties.getAmbientLight().getAmbientURL() == "") { - properties.getAmbientLight().setAmbientURL(properties.getSkybox().getURL()); - } } EntityItemPointer entity = addEntity(entityItemID, properties); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index deddeb4153..acc1ff01db 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -196,6 +196,8 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debuggin uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); +// Due to the different legacy behaviour, we need special processing for domains that were created before +// the zone inheritance modes were added. These have version numbers up to 80 enum class EntityVersion : PacketVersion { StrokeColorProperty = 0, HasDynamicOwnershipTests, From 8142b207aff1389ecc00ae80fe6ef400ec45b8d5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 11 Jan 2018 19:56:08 -0800 Subject: [PATCH 35/43] Making the forward model normal lighted --- libraries/render-utils/src/forward_model_normal_map.slf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render-utils/src/forward_model_normal_map.slf b/libraries/render-utils/src/forward_model_normal_map.slf index c86c0731b5..bc044d97ea 100644 --- a/libraries/render-utils/src/forward_model_normal_map.slf +++ b/libraries/render-utils/src/forward_model_normal_map.slf @@ -71,6 +71,8 @@ void main(void) { vec3 fragPosition = _position.xyz; + TransformCamera cam = getTransformCamera(); + vec4 color = vec4(evalSkyboxGlobalColor( cam._viewInverse, 1.0, From e3faec838cf934326d4ae33124c45b43d96a593c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 11 Jan 2018 23:22:51 -0800 Subject: [PATCH 36/43] Adding colors to the world --- libraries/networking/src/udt/PacketHeaders.h | 2 +- .../render-utils/src/RenderForwardTask.cpp | 148 +++++++++++------- .../render-utils/src/RenderForwardTask.h | 41 ++--- 3 files changed, 107 insertions(+), 84 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index deddeb4153..7eafbbccf5 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -202,7 +202,7 @@ enum class EntityVersion : PacketVersion { HazeEffect, StaticCertJsonVersionOne, OwnershipChallengeFix, - ZoneLightInheritModes = 82, + ZoneLightInheritModes, ZoneStageRemoved }; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index b833fb47b8..fb400246c5 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -26,6 +26,7 @@ #include "FramebufferCache.h" #include "TextureCache.h" #include "RenderCommonTask.h" +#include "LightStage.h" #include "nop_frag.h" @@ -63,17 +64,21 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend // GPU jobs: Start preparing the main framebuffer const auto framebuffer = task.addJob("PrepareFramebuffer"); + task.addJob("PrepareForward", lightingModel); + // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", framebuffer); // Draw opaques forward - task.addJob("DrawOpaques", opaques, shapePlumber); + const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying(); + task.addJob("DrawOpaques", opaqueInputs, shapePlumber); // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job task.addJob("DrawBackgroundDeferred", lightingModel); // Draw transparent objects forward - task.addJob("DrawTransparents", transparents, shapePlumber); + const auto transparentInputs = DrawForward::Inputs(transparents, lightingModel).asVarying(); + task.addJob("DrawTransparents", transparentInputs, shapePlumber); { // Debug the bounds of the rendered items, still look at the zbuffer @@ -131,12 +136,79 @@ void PrepareFramebuffer::run(const RenderContextPointer& renderContext, gpu::Fra framebuffer = _framebuffer; } -void Draw::run(const RenderContextPointer& renderContext, const Inputs& items) { +enum ForwardShader_MapSlot { + DEFERRED_BUFFER_COLOR_UNIT = 0, + DEFERRED_BUFFER_NORMAL_UNIT = 1, + DEFERRED_BUFFER_EMISSIVE_UNIT = 2, + DEFERRED_BUFFER_DEPTH_UNIT = 3, + DEFERRED_BUFFER_OBSCURANCE_UNIT = 4, + SHADOW_MAP_UNIT = 5, + SKYBOX_MAP_UNIT = SHADOW_MAP_UNIT + 4, + DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, + DEFERRED_BUFFER_CURVATURE_UNIT, + DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, + SCATTERING_LUT_UNIT, + SCATTERING_SPECULAR_UNIT, +}; +enum ForwardShader_BufferSlot { + DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0, + CAMERA_CORRECTION_BUFFER_SLOT, + SCATTERING_PARAMETERS_BUFFER_SLOT, + LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL, + LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, + LIGHT_AMBIENT_SLOT = render::ShapePipeline::Slot::LIGHT_AMBIENT_BUFFER, + HAZE_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::HAZE_MODEL, + LIGHT_INDEX_GPU_SLOT, + LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, + LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, + LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, +}; + +void PrepareForward::run(const RenderContextPointer& renderContext, const Inputs& inputs) { RenderArgs* args = renderContext->args; + const auto& lightingModel = inputs; + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + model::LightPointer keySunLight; + auto lightStage = args->_scene->getStage(); + if (lightStage) { + keySunLight = lightStage->getCurrentKeyLight(); + } + + model::LightPointer keyAmbiLight; + if (lightStage) { + keyAmbiLight = lightStage->getCurrentAmbientLight(); + } + + if (keySunLight) { + if (LIGHT_GPU_SLOT >= 0) { + batch.setUniformBuffer(LIGHT_GPU_SLOT, keySunLight->getLightSchemaBuffer()); + } + } + + if (keyAmbiLight) { + if (LIGHT_AMBIENT_SLOT >= 0) { + batch.setUniformBuffer(LIGHT_AMBIENT_SLOT, keyAmbiLight->getAmbientSchemaBuffer()); + } + + if (keyAmbiLight->getAmbientMap() && (SKYBOX_MAP_UNIT >= 0)) { + batch.setResourceTexture(SKYBOX_MAP_UNIT, keyAmbiLight->getAmbientMap()); + } + } + }); +} + +void DrawForward::run(const RenderContextPointer& renderContext, const Inputs& inputs) { + RenderArgs* args = renderContext->args; + + const auto& inItems = inputs.get0(); + const auto& lightingModel = inputs.get1(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + // Setup projection glm::mat4 projMat; Transform viewMat; @@ -146,63 +218,23 @@ void Draw::run(const RenderContextPointer& renderContext, const Inputs& items) { batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); + // Setup lighting model for all items; + batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); + + // From the lighting model define a global shapeKey ORED with individiual keys + ShapeKey::Builder keyBuilder; + if (lightingModel->isWireframeEnabled()) { + keyBuilder.withWireframe(); + } + ShapeKey globalKey = keyBuilder.build(); + args->_globalShapeKey = globalKey._flags.to_ulong(); + // Render items - renderStateSortShapes(renderContext, _shapePlumber, items, -1); + renderStateSortShapes(renderContext, _shapePlumber, inItems, -1, globalKey); + + args->_batch = nullptr; + args->_globalShapeKey = 0; }); - args->_batch = nullptr; } -const gpu::PipelinePointer Stencil::getPipeline() { - if (!_stencilPipeline) { - auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(nop_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::makeProgram(*program); - auto state = std::make_shared(); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - PrepareStencil::drawBackground(*state); - - _stencilPipeline = gpu::Pipeline::create(program, state); - } - return _stencilPipeline; -} - -void Stencil::run(const RenderContextPointer& renderContext) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - batch.setPipeline(getPipeline()); - batch.draw(gpu::TRIANGLE_STRIP, 4); - }); - args->_batch = nullptr; -} - -void DrawBackground::run(const RenderContextPointer& renderContext, const Inputs& background) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - batch.enableSkybox(true); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - // Setup projection - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - renderItems(renderContext, background); - }); - args->_batch = nullptr; -} \ No newline at end of file diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 63d087b3c5..22e75d4bdc 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -38,37 +38,28 @@ private: gpu::FramebufferPointer _framebuffer; }; -class Draw { +class PrepareForward { public: - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; + using Inputs = LightingModelPointer; + using JobModel = render::Job::ModelI; - Draw(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {} void run(const render::RenderContextPointer& renderContext, - const Inputs& items); + const Inputs& inputs); + +private: +}; + +class DrawForward{ +public: + using Inputs = render::VaryingSet2; + using JobModel = render::Job::ModelI; + + DrawForward(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {} + void run(const render::RenderContextPointer& renderContext, + const Inputs& inputs); private: render::ShapePlumberPointer _shapePlumber; }; -class Stencil { -public: - using JobModel = render::Job::Model; - - void run(const render::RenderContextPointer& renderContext); - -private: - const gpu::PipelinePointer getPipeline(); - gpu::PipelinePointer _stencilPipeline; -}; - -class DrawBackground { -public: - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; - - void run(const render::RenderContextPointer& renderContext, - const Inputs& background); -}; - #endif // hifi_RenderForwardTask_h From 50a030b68b8d8f06a42be7e4f5ca91cb478febe6 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Fri, 12 Jan 2018 00:22:06 -0800 Subject: [PATCH 37/43] Corrected copy of ambient URL. --- libraries/entities/src/EntityTree.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b7b560290e..907426c922 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2242,7 +2242,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { // map will have a top-level list keyed as "Entities". This will be extracted // and iterated over. Each member of this list is converted to a QVariantMap, then // to a QScriptValue, and then to EntityItemProperties. These properties are used - // to add the new entity to the EnitytTree. + // to add the new entity to the EntityTree. QVariantList entitiesQList = map["Entities"].toList(); QScriptEngine scriptEngine; @@ -2286,7 +2286,10 @@ bool EntityTree::readFromMap(QVariantMap& map) { // Fix for older content not containing these fields in the zones if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) { // The ambient URL has been moved from "keyLight" to "ambientLight" - properties.getAmbientLight().setAmbientURL(entityMap["ambientURL"].toString()); + if (entityMap.contains("keyLight")) { + QVariantMap keyLightObject = entityMap["keyLight"].toMap(); + properties.getAmbientLight().setAmbientURL(keyLightObject["ambientURL"].toString()); + } // The background should be enabled if the mode is skybox // Note that if the values are default then they are not stored in the JSON file From bfd18e3696678e71f97dedd62ca4724ac9baa351 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 12 Jan 2018 09:07:50 -0800 Subject: [PATCH 38/43] unused variable warning fix --- libraries/animation/src/AnimInverseKinematics.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 7bf250a32c..c8388c3b12 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -646,7 +646,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const AnimPose geomToWorldPose = AnimPose(context.getRigToWorldMatrix() * context.getGeometryToRigMatrix()); - glm::vec3 dUnit = d / dLen; glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); // if mid joint is straight use the reference vector to compute eProj, otherwise use reference vector. From 6920e576137e8f03e0a1b4b1ad57e581aac37c54 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 12 Jan 2018 13:31:58 -0800 Subject: [PATCH 39/43] Fix 'Browse Avatars' button from Avatar Settings --- .../qml/dialogs/preferences/AvatarBrowser.qml | 85 -------------- .../dialogs/preferences/AvatarPreference.qml | 18 +-- .../preferences/TabletAvatarBrowser.qml | 111 ------------------ interface/src/Application.cpp | 9 ++ interface/src/Application.h | 1 + 5 files changed, 11 insertions(+), 213 deletions(-) delete mode 100644 interface/resources/qml/dialogs/preferences/AvatarBrowser.qml delete mode 100644 interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletAvatarBrowser.qml diff --git a/interface/resources/qml/dialogs/preferences/AvatarBrowser.qml b/interface/resources/qml/dialogs/preferences/AvatarBrowser.qml deleted file mode 100644 index 5949adffca..0000000000 --- a/interface/resources/qml/dialogs/preferences/AvatarBrowser.qml +++ /dev/null @@ -1,85 +0,0 @@ -// -// AvatarBrowser.qml -// -// Created by Bradley Austin Davis on 30 Aug 2015 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtWebChannel 1.0 -import QtWebEngine 1.2 - -import "../../windows" -import "../../controls-uit" -import "../../styles-uit" - -Window { - id: root - HifiConstants { id: hifi } - width: 900; height: 700 - resizable: true - modality: Qt.ApplicationModal - - Item { - anchors.fill: parent - - property bool keyboardEnabled: false - property bool keyboardRaised: true - property bool punctuationMode: false - - BaseWebView { - id: webview - url: Account.metaverseServerURL + "/marketplace?category=avatars" - focus: true - - anchors { - top: parent.top - left: parent.left - right: parent.right - bottom: keyboard.top - } - - // Create a global EventBridge object for raiseAndLowerKeyboard. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // Detect when may want to raise and lower keyboard. - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ] - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - } - } - - Keyboard { - id: keyboard - raised: parent.keyboardEnabled && parent.keyboardRaised - numeric: parent.punctuationMode - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - } - } - - Component.onCompleted: { - keyboardEnabled = HMD.active; - } - } -} diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index b27827d9d7..0efc3776b3 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml @@ -99,25 +99,9 @@ Preference { leftMargin: dataTextField.acceptableInput ? hifi.dimensions.contentSpacing.x : 0 } onClicked: { - if (typeof desktop !== "undefined") { - // Load dialog via OffscreenUi so that JavaScript EventBridge is available. - root.browser = OffscreenUi.load("dialogs/preferences/AvatarBrowser.qml"); - root.browser.windowDestroyed.connect(function(){ - root.browser = null; - }); - } else { - root.browser = tabletAvatarBrowserBuilder.createObject(tabletRoot); - - // Make dialog modal. - tabletRoot.openModal = root.browser; - } + ApplicationInterface.loadAvatarBrowser(); } } - Component { - id: tabletAvatarBrowserBuilder; - TabletAvatarBrowser { } - } - } } diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletAvatarBrowser.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletAvatarBrowser.qml deleted file mode 100644 index 2ea12f1d3d..0000000000 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletAvatarBrowser.qml +++ /dev/null @@ -1,111 +0,0 @@ -// -// TabletAvatarBrowser.qml -// -// Created by David Rowe on 14 Mar 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtWebChannel 1.0 -import QtWebEngine 1.2 - -import "../../../../windows" -import "../../../../controls-uit" -import "../../../../styles-uit" - -Item { - id: root - objectName: "ModelBrowserDialog" - - property string title: "Attachment Model" - - property bool keyboardEnabled: false - property bool keyboardRaised: false - property bool punctuationMode: false - - anchors.fill: parent - - BaseWebView { - id: webview - url: (Account.metaverseServerURL + "/marketplace?category=avatars") - focus: true - - anchors { - top: parent.top - left: parent.left - right: parent.right - bottom: footer.top - } - - // Create a global EventBridge object for raiseAndLowerKeyboard. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // Detect when may want to raise and lower keyboard. - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ] - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - } - } - - Rectangle { - id: footer - height: 40 - - anchors { - left: parent.left - right: parent.right - bottom: keyboard.top - } - - color: hifi.colors.baseGray - - Row { - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: hifi.dimensions.contentMargin.x - } - - Button { - text: "Cancel" - color: hifi.buttons.white - onClicked: root.destroy(); - } - } - } - - Keyboard { - id: keyboard - - raised: parent.keyboardEnabled && parent.keyboardRaised - numeric: parent.punctuationMode - - anchors { - left: parent.left - right: parent.right - bottom: parent.bottom - } - } - - Component.onCompleted: { - keyboardEnabled = HMD.active; - } -} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f9a994124b..e081e80360 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6807,6 +6807,15 @@ void Application::loadAddAvatarBookmarkDialog() const { avatarBookmarks->addBookmark(); } +void Application::loadAvatarBrowser() const { + auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); + // construct the url to the marketplace item + QString url = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace?category=avatars"; + QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; + tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); + DependencyManager::get()->openTablet(); +} + void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) { postLambdaEvent([notify, includeAnimated, aspectRatio, this] { // Get a screenshot and save it diff --git a/interface/src/Application.h b/interface/src/Application.h index b01e998a21..effb35caee 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -309,6 +309,7 @@ public slots: void toggleEntityScriptServerLogDialog(); Q_INVOKABLE void showAssetServerWidget(QString filePath = ""); Q_INVOKABLE void loadAddAvatarBookmarkDialog() const; + Q_INVOKABLE void loadAvatarBrowser() const; Q_INVOKABLE SharedSoundPointer getSampleSound() const; void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const; From 522007af9dbd93511375e9d32aa16d607ee40258 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 12 Jan 2018 14:58:14 -0800 Subject: [PATCH 40/43] Fix social media sharing buttons on Snapshot app --- interface/resources/qml/controls/TabletWebScreen.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/controls/TabletWebScreen.qml b/interface/resources/qml/controls/TabletWebScreen.qml index 501e321f0d..bb037ad478 100644 --- a/interface/resources/qml/controls/TabletWebScreen.qml +++ b/interface/resources/qml/controls/TabletWebScreen.qml @@ -41,9 +41,9 @@ Item { onNewViewRequestedCallback: { // desktop is not defined for web-entities or tablet if (typeof desktop !== "undefined") { - desktop.openBrowserWindow(request, profile); + desktop.openBrowserWindow(request, webViewCoreProfile); } else { - tabletRoot.openBrowserWindow(request, profile); + tabletRoot.openBrowserWindow(request, webViewCoreProfile); } } From 331a8f3094b4de91d565d861191e437b31ad7c5a Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sat, 13 Jan 2018 01:00:10 -0800 Subject: [PATCH 41/43] fixing the stencil not clearing correctly and shaders not compiled correctly in main thread --- interface/src/Application.cpp | 5 ++++- .../gpu-gles/src/gpu/gl/GLBackendOutput.cpp | 15 +++++++++++++-- libraries/gpu/src/gpu/Batch.h | 7 +++++-- libraries/model/src/model/Skybox.cpp | 12 +++++++----- libraries/render-utils/src/GeometryCache.cpp | 18 ++++++++++++++---- .../render-utils/src/MaterialTextures.slh | 8 +++++--- .../render-utils/src/RenderForwardTask.cpp | 2 +- 7 files changed, 49 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 70b5001f06..390d5716f8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1132,7 +1132,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateHeartbeat(); // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. - DependencyManager::get()->initializeShapePipelines(); + // DependencyManager::get()->initializeShapePipelines(); // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. @@ -2254,6 +2254,9 @@ void Application::initializeGL() { _renderEngine->load(); _renderEngine->registerScene(_main3DScene); + // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. + DependencyManager::get()->initializeShapePipelines(); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->setObjectName("MainThreadContext"); _offscreenContext->create(_glWidget->qglContext()); diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp index 6fddb810ee..5b19399f83 100644 --- a/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp @@ -63,11 +63,17 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { int useScissor = batch._params[paramOffset + 0]._int; GLuint glmask = 0; + bool restoreStencilMask = false; + uint8_t cacheStencilMask = 0xFF; if (masks & Framebuffer::BUFFER_STENCIL) { glClearStencil(stencil); glmask |= GL_STENCIL_BUFFER_BIT; - // TODO: we will probably need to also check the write mask of stencil like we do - // for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it" + + cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront(); + if (cacheStencilMask != 0xFF) { + restoreStencilMask = true; + glStencilMask(0xFF); + } } bool restoreDepthMask = false; @@ -122,6 +128,11 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { glDisable(GL_SCISSOR_TEST); } + // Restore Stencil write mask + if (restoreStencilMask) { + glStencilMask(cacheStencilMask); + } + // Restore write mask meaning turn back off if (restoreDepthMask) { glDepthMask(GL_FALSE); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index fca220c224..79f08ea5cc 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -269,6 +269,10 @@ public: void _glColor4f(float red, float green, float blue, float alpha); + // Maybe useful but shoudln't be public. Please convince me otherwise + // Well porting to gles i need it... + void runLambda(std::function f); + enum Command { COMMAND_draw = 0, COMMAND_drawIndexed, @@ -497,8 +501,7 @@ protected: void startNamedCall(const std::string& name); void stopNamedCall(); - // Maybe useful but shoudln't be public. Please convince me otherwise - void runLambda(std::function f); + void captureDrawCallInfoImpl(); }; diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index fd3061afa5..b87d30c9d1 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -89,12 +89,14 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky auto skyFS = gpu::Shader::createPixel(std::string(skybox_frag)); auto skyShader = gpu::Shader::createProgram(skyVS, skyFS); - gpu::Shader::BindingSet bindings; - bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), SKYBOX_SKYMAP_SLOT)); - bindings.insert(gpu::Shader::Binding(std::string("skyboxBuffer"), SKYBOX_CONSTANTS_SLOT)); - if (!gpu::Shader::makeProgram(*skyShader, bindings)) { + batch.runLambda([skyShader] { + gpu::Shader::BindingSet bindings; + bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), SKYBOX_SKYMAP_SLOT)); + bindings.insert(gpu::Shader::Binding(std::string("skyboxBuffer"), SKYBOX_CONSTANTS_SLOT)); + if (!gpu::Shader::makeProgram(*skyShader, bindings)) { - } + } + }); auto skyState = std::make_shared(); // Must match PrepareStencil::STENCIL_BACKGROUND diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2616d08600..8332726429 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -715,6 +715,10 @@ void GeometryCache::initializeShapePipelines() { _simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false); _simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false); _simpleWirePipeline = getShapePipeline(false, false, true, true); + + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); + auto program = gpu::Shader::createProgram(vs, ps); } } @@ -2001,11 +2005,11 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const } void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { - if (!_standardDrawPipeline) { + static std::once_flag once; + std::call_once(once, [&]() { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); auto program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::makeProgram((*program)); auto state = std::make_shared(); @@ -2021,9 +2025,15 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); - gpu::Shader::makeProgram((*programNoBlend)); + _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); - } + + batch.runLambda([program, programNoBlend] { + gpu::Shader::makeProgram((*program)); + gpu::Shader::makeProgram((*programNoBlend)); + }); + }); + if (noBlend) { batch.setPipeline(_standardDrawPipelineNoBlend); } else { diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 6c77fc4a91..40709b3668 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -17,7 +17,9 @@ const int MAX_TEXCOORDS = 2; struct TexMapArray { - mat4 _texcoordTransforms[MAX_TEXCOORDS]; +// mat4 _texcoordTransforms[MAX_TEXCOORDS]; + mat4 _texcoordTransforms0; + mat4 _texcoordTransforms1; vec4 _lightmapParams; }; @@ -31,13 +33,13 @@ TexMapArray getTexMapArray() { <@func evalTexMapArrayTexcoord0(texMapArray, inTexcoord0, outTexcoord0)@> { - <$outTexcoord0$> = (<$texMapArray$>._texcoordTransforms[0] * vec4(<$inTexcoord0$>.st, 0.0, 1.0)).st; + <$outTexcoord0$> = (<$texMapArray$>._texcoordTransforms0 * vec4(<$inTexcoord0$>.st, 0.0, 1.0)).st; } <@endfunc@> <@func evalTexMapArrayTexcoord1(texMapArray, inTexcoord1, outTexcoord1)@> { - <$outTexcoord1$> = (<$texMapArray$>._texcoordTransforms[1] * vec4(<$inTexcoord1$>.st, 0.0, 1.0)).st; + <$outTexcoord1$> = (<$texMapArray$>._texcoordTransforms1 * vec4(<$inTexcoord1$>.st, 0.0, 1.0)).st; } <@endfunc@> diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index fb400246c5..d9845f3e80 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -130,7 +130,7 @@ void PrepareFramebuffer::run(const RenderContextPointer& renderContext, gpu::Fra batch.setFramebuffer(_framebuffer); batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH | gpu::Framebuffer::BUFFER_STENCIL, - vec4(vec3(0), 1), 1.0, 0, true); + vec4(vec3(0, 1.0, 0.0), 0), 1.0, 0, true); }); framebuffer = _framebuffer; From 57f1ba2412002ecc9e6989f8c27f18b6b73d2b7c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sat, 13 Jan 2018 02:00:34 -0800 Subject: [PATCH 42/43] Merging with master to be able connect to dev domains and it works. fixing shaders for gles compile errors and disabling material textures by default --- .../gpu-gles/src/gpu/gl/GLBackendPipeline.cpp | 4 ++ libraries/render-utils/src/LightingModel.h | 4 +- libraries/render-utils/src/Skinning.slh | 10 ++--- .../src/forward_model_normal_specular_map.slf | 43 +++++++++++++++---- .../src/forward_model_specular_map.slf | 43 +++++++++++++++++-- 5 files changed, 85 insertions(+), 19 deletions(-) diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp index 73a597e89a..978c47c7f8 100644 --- a/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp @@ -150,6 +150,10 @@ void GLBackend::resetUniformStage() { void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 3]._uint; + if (slot >(GLuint)MAX_NUM_UNIFORM_BUFFERS) { + qCDebug(gpugllogging) << "GLBackend::do_setUniformBuffer: Trying to set a uniform Buffer at slot #" << slot << " which doesn't exist. MaxNumUniformBuffers = " << getMaxNumUniformBuffers(); + return; + } BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); GLintptr rangeStart = batch._params[paramOffset + 1]._uint; GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index e058b10921..d7d2f2bba1 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -96,7 +96,7 @@ protected: float enableObscurance{ 1.0f }; - float enableMaterialTexturing { 1.0f }; + float enableMaterialTexturing { 0.0f }; float enableWireframe { 0.0f }; // false by default Parameters() {} @@ -148,7 +148,7 @@ public: bool enableSpecular{ true }; bool enableAlbedo{ true }; - bool enableMaterialTexturing { true }; + bool enableMaterialTexturing { false }; bool enableAmbientLight{ true }; bool enableDirectionalLight{ true }; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 49d0df3d2c..a7edfb14a6 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -39,12 +39,12 @@ mat4 dualQuatToMat4(vec4 real, vec4 dual) { twoRealXZ - twoRealYW, 0.0); vec4 col1 = vec4(twoRealXY - twoRealZW, - 1 - twoRealXSq - twoRealZSq, + 1.0 - twoRealXSq - twoRealZSq, twoRealYZ + twoRealXW, 0.0); vec4 col2 = vec4(twoRealXZ + twoRealYW, twoRealYZ - twoRealXW, - 1 - twoRealXSq - twoRealYSq, + 1.0 - twoRealXSq - twoRealYSq, 0.0); vec4 col3 = vec4(2.0 * (-dual.w * real.x + dual.x * real.w - dual.y * real.z + dual.z * real.y), 2.0 * (-dual.w * real.y + dual.x * real.z + dual.y * real.w - dual.z * real.x), @@ -72,7 +72,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (dot(real, polarityReference) < 0) { + if (dot(real, polarityReference) < 0.0) { dqClusterWeight = -clusterWeight; } @@ -110,7 +110,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (dot(real, polarityReference) < 0) { + if (dot(real, polarityReference) < 0.0) { dqClusterWeight = -clusterWeight; } @@ -149,7 +149,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity. float dqClusterWeight = clusterWeight; - if (dot(real, polarityReference) < 0) { + if (dot(real, polarityReference) < 0.0) { dqClusterWeight = -clusterWeight; } diff --git a/libraries/render-utils/src/forward_model_normal_specular_map.slf b/libraries/render-utils/src/forward_model_normal_specular_map.slf index ca6bbec3da..02a9242f72 100644 --- a/libraries/render-utils/src/forward_model_normal_specular_map.slf +++ b/libraries/render-utils/src/forward_model_normal_specular_map.slf @@ -12,10 +12,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include ForwardBufferWrite.slh@> + + !> + +<@include ForwardGlobalLight.slh@> +<$declareEvalSkyboxGlobalColor()$> <@include model/Material.slh@> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include MaterialTextures.slh@> <$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC, EMISSIVE, OCCLUSION)$> @@ -26,6 +33,8 @@ in vec3 _normal; in vec3 _tangent; in vec3 _color; +out vec4 _fragColor; + void main(void) { Material mat = getMaterial(); int matKey = getMaterialKey(mat); @@ -51,16 +60,32 @@ void main(void) { float metallic = getMaterialMetallic(mat); <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } + else { + fresnel = albedo; + metallic = 1.0; + } + vec3 fragPosition = _position.xyz; - float scattering = getMaterialScattering(mat); + TransformCamera cam = getTransformCamera(); - packForwardFragment( - normalize(viewNormal.xyz), - opacity, + vec4 color = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + viewNormal, albedo, - roughness, + fresnel, metallic, - emissive, - occlusionTex, - scattering); + roughness), + opacity); + + color.rgb += emissive * isEmissiveEnabled(); + + // _fragColor = vec4(albedo, opacity); + _fragColor = color; } diff --git a/libraries/render-utils/src/forward_model_specular_map.slf b/libraries/render-utils/src/forward_model_specular_map.slf index d2fdd18794..6618c67ff1 100644 --- a/libraries/render-utils/src/forward_model_specular_map.slf +++ b/libraries/render-utils/src/forward_model_specular_map.slf @@ -12,10 +12,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include ForwardBufferWrite.slh@> + + !> + +<@include ForwardGlobalLight.slh@> +<$declareEvalSkyboxGlobalColor()$> <@include model/Material.slh@> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include MaterialTextures.slh@> <$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC, EMISSIVE, OCCLUSION)$> @@ -25,12 +32,13 @@ in vec2 _texCoord1; in vec3 _normal; in vec3 _color; +out vec4 _fragColor; void main(void) { Material mat = getMaterial(); int matKey = getMaterialKey(mat); <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex)$> - <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + !> float opacity = 1.0; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; @@ -48,7 +56,14 @@ void main(void) { float metallic = getMaterialMetallic(mat); <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; - + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } + else { + fresnel = albedo; + metallic = 1.0; + }/* float scattering = getMaterialScattering(mat); packForwardFragment( @@ -60,4 +75,26 @@ void main(void) { emissive, occlusionTex, scattering); + */ + vec3 fragPosition = _position.xyz; + + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, _normal, fragNormal)$> + + vec4 color = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + fragNormal, + albedo, + fresnel, + metallic, + roughness), + opacity); + color.rgb += emissive * isEmissiveEnabled(); + + // _fragColor = vec4(albedo, opacity); + _fragColor = color; } From d6e771f01d7c56e63d1964a04abcfde2cea89568 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sat, 13 Jan 2018 10:02:53 -0800 Subject: [PATCH 43/43] Adding the batch as aprameter to the custom pipeline register to be able to make program through a call to runLamda in order to perform the make call in the present thread where the gl context is valid --- .../RenderableParticleEffectEntityItem.cpp | 11 ++++++---- .../src/RenderablePolyLineEntityItem.cpp | 22 ++++++++++++------- .../src/RenderablePolyVoxEntityItem.cpp | 7 ++++-- libraries/render-utils/src/GeometryCache.cpp | 6 +---- libraries/render-utils/src/GeometryCache.h | 2 +- libraries/render/src/render/ShapePipeline.cpp | 2 +- libraries/render/src/render/ShapePipeline.h | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a3e6cd4341..2059487426 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -26,7 +26,7 @@ static std::weak_ptr _texturedPipeline; // FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 11 to avoid collisions static int32_t PARTICLE_UNIFORM_SLOT { 11 }; -static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key) { +static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) { auto texturedPipeline = _texturedPipeline.lock(); if (!texturedPipeline) { auto state = std::make_shared(); @@ -40,10 +40,13 @@ static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, co auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag)); auto program = gpu::Shader::createProgram(vertShader, fragShader); - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("particleBuffer"), PARTICLE_UNIFORM_SLOT)); - gpu::Shader::makeProgram(*program, slotBindings); _texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state); + + batch.runLambda([program] { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("particleBuffer"), PARTICLE_UNIFORM_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + }); } return std::make_shared(texturedPipeline, nullptr, nullptr, nullptr); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index b362721cde..4d223669b4 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -46,7 +46,7 @@ struct PolyLineUniforms { glm::vec3 color; }; -static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) { +static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) { if (!polylinePipeline) { auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert)); auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag)); @@ -56,15 +56,21 @@ static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlum auto fadePS = gpu::Shader::createPixel(std::string(paintStroke_fade_frag)); gpu::ShaderPointer fadeProgram = gpu::Shader::createProgram(fadeVS, fadePS); #endif - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), PAINTSTROKE_TEXTURE_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("polyLineBuffer"), PAINTSTROKE_UNIFORM_SLOT)); - gpu::Shader::makeProgram(*program, slotBindings); + batch.runLambda([program #ifdef POLYLINE_ENTITY_USE_FADE_EFFECT - slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), PAINTSTROKE_TEXTURE_SLOT + 1)); - slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), PAINTSTROKE_UNIFORM_SLOT + 1)); - gpu::Shader::makeProgram(*fadeProgram, slotBindings); + , fadeProgram #endif + ] { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), PAINTSTROKE_TEXTURE_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("polyLineBuffer"), PAINTSTROKE_UNIFORM_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); +#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT + slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), PAINTSTROKE_TEXTURE_SLOT + 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), PAINTSTROKE_UNIFORM_SLOT + 1)); + gpu::Shader::makeProgram(*fadeProgram, slotBindings); +#endif + }); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMask(*state); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index ad0202457e..b693ea007d 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1457,7 +1457,7 @@ static gpu::PipelinePointer _pipelines[2]; static gpu::PipelinePointer _wireframePipelines[2]; static gpu::Stream::FormatPointer _vertexFormat; -ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key) { +ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) { if (!_pipelines[0]) { gpu::ShaderPointer vertexShaders[2] = { gpu::Shader::createVertex(std::string(polyvox_vert)), gpu::Shader::createVertex(std::string(polyvox_fade_vert)) }; gpu::ShaderPointer pixelShaders[2] = { gpu::Shader::createPixel(std::string(polyvox_frag)), gpu::Shader::createPixel(std::string(polyvox_fade_frag)) }; @@ -1485,7 +1485,10 @@ ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const Sha // Two sets of pipelines: normal and fading for (auto i = 0; i < 2; i++) { gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShaders[i], pixelShaders[i]); - gpu::Shader::makeProgram(*program, slotBindings); + + batch.runLambda([program, slotBindings] { + gpu::Shader::makeProgram(*program, slotBindings); + }); _pipelines[i] = gpu::Pipeline::create(program, state); _wireframePipelines[i] = gpu::Pipeline::create(program, wireframeState); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 8332726429..d5a3a92f8f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -639,7 +639,7 @@ render::ShapePipelinePointer GeometryCache::_simpleWirePipeline; uint8_t GeometryCache::CUSTOM_PIPELINE_NUMBER = 0; -render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) { +render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) { initializeShapePipelines(); if (key.isWireframe()) { @@ -715,10 +715,6 @@ void GeometryCache::initializeShapePipelines() { _simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false); _simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false); _simpleWirePipeline = getShapePipeline(false, false, true, true); - - auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); - auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); - auto program = gpu::Shader::createProgram(vs, ps); } } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 0585cc9e55..a84a80fe74 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -158,7 +158,7 @@ public: static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector &outPointList); static uint8_t CUSTOM_PIPELINE_NUMBER; - static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key); + static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch); static void registerShapePipeline() { if (!CUSTOM_PIPELINE_NUMBER) { CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory); diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 4254280fa1..b010657049 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -131,7 +131,7 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke auto factoryIt = ShapePipeline::_globalCustomFactoryMap.find(key.getCustom()); if ((factoryIt != ShapePipeline::_globalCustomFactoryMap.end()) && (factoryIt)->second) { // found a factory for the custom key, can now generate a shape pipeline for this case: - addPipelineHelper(Filter(key), key, 0, (factoryIt)->second(*this, key)); + addPipelineHelper(Filter(key), key, 0, (factoryIt)->second(*this, key, *(args->_batch))); return pickPipeline(args, key); } else { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index be77e2f95e..9e05cfb81b 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -301,7 +301,7 @@ protected: ItemSetter _itemSetter; public: using CustomKey = uint8_t; - using CustomFactory = std::function (const ShapePlumber& plumber, const ShapeKey& key)>; + using CustomFactory = std::function (const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch)>; using CustomFactoryMap = std::map; static CustomFactoryMap _globalCustomFactoryMap;