mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge pull request #12397 from hyperlogic/bug-fix/entity-mat-avatar-dual-quaternions
Bug fix/entity mat avatar dual quaternions
This commit is contained in:
commit
7d450daaa1
28 changed files with 675 additions and 179 deletions
|
@ -31,6 +31,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
|||
_defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_headClipDistance(DEFAULT_NEAR_CLIP)
|
||||
{
|
||||
// SkeletonModels, and by extention Avatars, use Dual Quaternion skinning.
|
||||
_useDualQuaternionSkinning = true;
|
||||
assert(_owningAvatar);
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,9 @@ void RenderableModelEntityItem::doInitialModelSimulation() {
|
|||
model->setRotation(getWorldOrientation());
|
||||
model->setTranslation(getWorldPosition());
|
||||
|
||||
glm::vec3 scale = model->getScale();
|
||||
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
|
||||
|
||||
if (_needsInitialSimulation) {
|
||||
model->simulate(0.0f);
|
||||
_needsInitialSimulation = false;
|
||||
|
@ -243,6 +246,8 @@ void RenderableModelEntityItem::updateModelBounds() {
|
|||
}
|
||||
|
||||
if (updateRenderItems) {
|
||||
glm::vec3 scale = model->getScale();
|
||||
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
|
||||
model->updateRenderItems();
|
||||
}
|
||||
}
|
||||
|
@ -1504,4 +1509,4 @@ void ModelEntityRenderer::processMaterials() {
|
|||
material.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,16 +20,32 @@ 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<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms) {
|
||||
ModelMeshPartPayload::updateClusterBuffer(clusterTransforms);
|
||||
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
const std::vector<glm::mat4>& cauterizedClusterMatrices) {
|
||||
ModelMeshPartPayload::updateClusterBuffer(clusterMatrices);
|
||||
|
||||
if (cauterizedClusterTransforms.size() > 1) {
|
||||
if (cauterizedClusterMatrices.size() > 1) {
|
||||
if (!_cauterizedClusterBuffer) {
|
||||
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterTransforms.size() * sizeof(TransformType),
|
||||
(const gpu::Byte*) cauterizedClusterTransforms.data());
|
||||
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterMatrices.size() * sizeof(glm::mat4),
|
||||
(const gpu::Byte*) cauterizedClusterMatrices.data());
|
||||
} else {
|
||||
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(TransformType),
|
||||
(const gpu::Byte*) cauterizedClusterTransforms.data());
|
||||
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4),
|
||||
(const gpu::Byte*) cauterizedClusterMatrices.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
|
||||
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterDualQuaternions) {
|
||||
ModelMeshPartPayload::updateClusterBuffer(clusterDualQuaternions);
|
||||
|
||||
if (cauterizedClusterDualQuaternions.size() > 1) {
|
||||
if (!_cauterizedClusterBuffer) {
|
||||
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
|
||||
(const gpu::Byte*) cauterizedClusterDualQuaternions.data());
|
||||
} else {
|
||||
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
|
||||
(const gpu::Byte*) cauterizedClusterDualQuaternions.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
|||
public:
|
||||
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||
|
||||
#if defined(SKIN_DQ)
|
||||
using TransformType = Model::TransformDualQuaternion;
|
||||
#else
|
||||
using TransformType = glm::mat4;
|
||||
#endif
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
const std::vector<glm::mat4>& cauterizedClusterMatrices);
|
||||
|
||||
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms);
|
||||
// dual quaternion skinning
|
||||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
|
||||
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterQuaternions);
|
||||
|
||||
void updateTransformForCauterizedMesh(const Transform& renderTransform);
|
||||
|
||||
|
|
|
@ -35,8 +35,13 @@ bool CauterizedModel::updateGeometry() {
|
|||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||
Model::MeshState state;
|
||||
state.clusterTransforms.resize(mesh.clusters.size());
|
||||
_cauterizeMeshStates.append(state);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
_cauterizeMeshStates.append(state);
|
||||
} else {
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
_cauterizeMeshStates.append(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return needsFullUpdate;
|
||||
|
@ -109,33 +114,33 @@ 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);
|
||||
#if defined(SKIN_DQ)
|
||||
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);
|
||||
state.clusterTransforms[j].setCauterizationParameters(0.0f, jointPose.trans());
|
||||
#else
|
||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
||||
#endif
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||
state.clusterDualQuaternions[j].setCauterizationParameters(0.0f, jointPose.trans());
|
||||
} else {
|
||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -143,19 +148,24 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
|
||||
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];
|
||||
if (_useDualQuaternionSkinning) {
|
||||
if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
|
||||
// not cauterized so just copy the value from the non-cauterized version.
|
||||
state.clusterDualQuaternions[j] = _meshStates[i].clusterDualQuaternions[j];
|
||||
} else {
|
||||
Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||
state.clusterDualQuaternions[j].setCauterizationParameters(1.0f, cauterizePose.trans());
|
||||
}
|
||||
} else {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||
state.clusterTransforms[j].setCauterizationParameters(1.0f, cauterizePose.trans());
|
||||
#else
|
||||
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
||||
#endif
|
||||
if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
|
||||
// not cauterized so just copy the value from the non-cauterized version.
|
||||
state.clusterMatrices[j] = _meshStates[i].clusterMatrices[j];
|
||||
} else {
|
||||
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,45 +224,59 @@ void CauterizedModel::updateRenderItems() {
|
|||
|
||||
auto itemID = self->_modelMeshRenderItemIDs[i];
|
||||
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
|
||||
auto clusterTransformsCauterized(self->getCauterizeMeshState(meshIndex).clusterTransforms);
|
||||
|
||||
const auto& meshState = self->getMeshState(meshIndex);
|
||||
const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex);
|
||||
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterTransforms, clusterTransformsCauterized, invalidatePayloadShapeKey,
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
|
||||
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) {
|
||||
data.updateClusterBuffer(clusterTransforms, clusterTransformsCauterized);
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions,
|
||||
cauterizedMeshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices,
|
||||
cauterizedMeshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
if (clusterTransforms.size() == 1) {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform transform(clusterTransforms[0].getRotation(),
|
||||
clusterTransforms[0].getScale(),
|
||||
clusterTransforms[0].getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(transform);
|
||||
#else
|
||||
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
|
||||
#endif
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(transform);
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
renderTransform = modelTransform;
|
||||
if (clusterTransformsCauterized.size() == 1) {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform transform(clusterTransformsCauterized[0].getRotation(),
|
||||
clusterTransformsCauterized[0].getScale(),
|
||||
clusterTransformsCauterized[0].getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
#else
|
||||
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
|
||||
#endif
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (cauterizedMeshState.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = cauterizedMeshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (cauterizedMeshState.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -226,25 +226,35 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
_shapeID(shapeIndex) {
|
||||
|
||||
assert(model && model->isLoaded());
|
||||
|
||||
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
|
||||
|
||||
_blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex];
|
||||
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
|
||||
const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||
|
||||
updateMeshPart(modelMesh, partIndex);
|
||||
computeAdjustedLocalBound(state.clusterTransforms);
|
||||
|
||||
if (useDualQuaternionSkinning) {
|
||||
computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
|
||||
updateTransform(transform, offsetTransform);
|
||||
Transform renderTransform = transform;
|
||||
if (state.clusterTransforms.size() == 1) {
|
||||
#if defined(SKIN_DQ)
|
||||
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
|
||||
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (state.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = state.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = transform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (state.clusterMatrices.size() == 1) {
|
||||
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
updateTransformForSkinnedMesh(renderTransform, transform);
|
||||
|
||||
|
@ -274,16 +284,44 @@ void ModelMeshPartPayload::notifyLocationChanged() {
|
|||
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<TransformType>& clusterTransforms) {
|
||||
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
|
||||
// reset cluster buffer if we change the cluster buffer type
|
||||
if (_clusterBufferType != ClusterBufferType::Matrices) {
|
||||
_clusterBuffer.reset();
|
||||
}
|
||||
_clusterBufferType = ClusterBufferType::Matrices;
|
||||
|
||||
// Once computed the cluster matrices, update the buffer(s)
|
||||
if (clusterTransforms.size() > 1) {
|
||||
if (clusterMatrices.size() > 1) {
|
||||
if (!_clusterBuffer) {
|
||||
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterTransforms.size() * sizeof(TransformType),
|
||||
(const gpu::Byte*) clusterTransforms.data());
|
||||
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterMatrices.size() * sizeof(glm::mat4),
|
||||
(const gpu::Byte*) clusterMatrices.data());
|
||||
}
|
||||
else {
|
||||
_clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(TransformType),
|
||||
(const gpu::Byte*) clusterTransforms.data());
|
||||
_clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4),
|
||||
(const gpu::Byte*) clusterMatrices.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
|
||||
// reset cluster buffer if we change the cluster buffer type
|
||||
if (_clusterBufferType != ClusterBufferType::DualQuaternions) {
|
||||
_clusterBuffer.reset();
|
||||
}
|
||||
_clusterBufferType = ClusterBufferType::DualQuaternions;
|
||||
|
||||
// Once computed the cluster matrices, update the buffer(s)
|
||||
if (clusterDualQuaternions.size() > 1) {
|
||||
if (!_clusterBuffer) {
|
||||
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
|
||||
(const gpu::Byte*) clusterDualQuaternions.data());
|
||||
}
|
||||
else {
|
||||
_clusterBuffer->setSubData(0, clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion),
|
||||
(const gpu::Byte*) clusterDualQuaternions.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +383,7 @@ int ModelMeshPartPayload::getLayer() const {
|
|||
return _layer;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe) {
|
||||
void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) {
|
||||
if (invalidateShapeKey) {
|
||||
_shapeKey = ShapeKey::Builder::invalid();
|
||||
return;
|
||||
|
@ -392,6 +430,10 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
|
|||
if (isWireframe) {
|
||||
builder.withWireframe();
|
||||
}
|
||||
if (isSkinned && useDualQuaternionSkinning) {
|
||||
builder.withDualQuatSkinned();
|
||||
}
|
||||
|
||||
_shapeKey = builder.build();
|
||||
}
|
||||
|
||||
|
@ -447,29 +489,33 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms) {
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterTransforms.size() > 0) {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform rootTransform(clusterTransforms[0].getRotation(),
|
||||
clusterTransforms[0].getScale(),
|
||||
clusterTransforms[0].getTranslation());
|
||||
_adjustedLocalBound.transform(rootTransform);
|
||||
#else
|
||||
_adjustedLocalBound.transform(clusterTransforms[0]);
|
||||
#endif
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_adjustedLocalBound.transform(clusterMatrices[0]);
|
||||
|
||||
for (int i = 1; i < (int)clusterTransforms.size(); ++i) {
|
||||
for (int i = 1; i < (int)clusterMatrices.size(); ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
#if defined(SKIN_DQ)
|
||||
Transform transform(clusterTransforms[i].getRotation(),
|
||||
clusterTransforms[i].getScale(),
|
||||
clusterTransforms[i].getTranslation());
|
||||
clusterBound.transform(transform);
|
||||
#else
|
||||
clusterBound.transform(clusterTransforms[i]);
|
||||
#endif
|
||||
clusterBound.transform(clusterMatrices[i]);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterDualQuaternions.size() > 0) {
|
||||
Transform rootTransform(clusterDualQuaternions[0].getRotation(),
|
||||
clusterDualQuaternions[0].getScale(),
|
||||
clusterDualQuaternions[0].getTranslation());
|
||||
_adjustedLocalBound.transform(rootTransform);
|
||||
|
||||
for (int i = 1; i < (int)clusterDualQuaternions.size(); ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
Transform transform(clusterDualQuaternions[i].getRotation(),
|
||||
clusterDualQuaternions[i].getScale(),
|
||||
clusterDualQuaternions[i].getTranslation());
|
||||
clusterBound.transform(transform);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,14 +92,14 @@ public:
|
|||
|
||||
void notifyLocationChanged() override;
|
||||
|
||||
#if defined(SKIN_DQ)
|
||||
using TransformType = Model::TransformDualQuaternion;
|
||||
#else
|
||||
using TransformType = glm::mat4;
|
||||
#endif
|
||||
|
||||
void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override;
|
||||
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
|
||||
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// dual quaternion skinning
|
||||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
|
||||
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
|
||||
|
||||
// Render Item interface
|
||||
|
@ -108,16 +108,23 @@ public:
|
|||
void render(RenderArgs* args) override;
|
||||
|
||||
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
|
||||
void setShapeKey(bool invalidateShapeKey, bool isWireframe);
|
||||
void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning);
|
||||
|
||||
// ModelMeshPartPayload functions to perform render
|
||||
void bindMesh(gpu::Batch& batch) override;
|
||||
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms);
|
||||
// matrix palette skinning
|
||||
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// dual quaternion skinning
|
||||
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
|
||||
enum class ClusterBufferType { Matrices, DualQuaternions };
|
||||
ClusterBufferType _clusterBufferType { ClusterBufferType::Matrices };
|
||||
|
||||
int _meshIndex;
|
||||
int _shapeID;
|
||||
|
||||
|
|
|
@ -280,32 +280,42 @@ void Model::updateRenderItems() {
|
|||
|
||||
auto itemID = self->_modelMeshRenderItemIDs[i];
|
||||
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
|
||||
|
||||
const auto& meshState = self->getMeshState(meshIndex);
|
||||
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms,
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
|
||||
invalidatePayloadShapeKey, isWireframe, isVisible,
|
||||
canCastShadow, viewTagBits, isLayeredInFront,
|
||||
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
|
||||
data.updateClusterBuffer(clusterTransforms);
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
if (clusterTransforms.size() == 1) {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform transform(clusterTransforms[0].getRotation(),
|
||||
clusterTransforms[0].getScale(),
|
||||
clusterTransforms[0].getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
#else
|
||||
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
|
||||
#endif
|
||||
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -380,7 +390,8 @@ bool Model::updateGeometry() {
|
|||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||
MeshState state;
|
||||
state.clusterTransforms.resize(mesh.clusters.size());
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
state.clusterMatrices.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
|
||||
|
@ -1257,6 +1268,10 @@ void Model::snapToRegistrationPoint() {
|
|||
_snappedToRegistrationPoint = true;
|
||||
}
|
||||
|
||||
void Model::setUseDualQuaternionSkinning(bool value) {
|
||||
_useDualQuaternionSkinning = value;
|
||||
}
|
||||
|
||||
void Model::simulate(float deltaTime, bool fullUpdate) {
|
||||
DETAILED_PROFILE_RANGE(simulation_detail, __FUNCTION__);
|
||||
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|
||||
|
@ -1290,7 +1305,11 @@ 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.clusterTransforms);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
part->computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
part->computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1309,16 +1328,16 @@ 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);
|
||||
#if defined(SKIN_DQ)
|
||||
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
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||
} else {
|
||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1589,12 +1608,13 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
|
|||
bool wireframe = isWireframe();
|
||||
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
|
||||
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) {
|
||||
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
|
||||
data.addMaterial(material);
|
||||
// if the material changed, we might need to update our item key or shape key
|
||||
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1615,12 +1635,13 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
|
|||
bool wireframe = isWireframe();
|
||||
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow,
|
||||
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) {
|
||||
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
|
||||
data.removeMaterial(material);
|
||||
// if the material changed, we might need to update our item key or shape key
|
||||
data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -260,8 +260,6 @@ public:
|
|||
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
|
||||
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
|
||||
|
||||
|
||||
#if defined(SKIN_DQ)
|
||||
class TransformDualQuaternion {
|
||||
public:
|
||||
TransformDualQuaternion() {}
|
||||
|
@ -299,15 +297,11 @@ public:
|
|||
DualQuaternion _dq;
|
||||
glm::vec4 _cauterizedPosition { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
};
|
||||
#endif
|
||||
|
||||
class MeshState {
|
||||
public:
|
||||
#if defined(SKIN_DQ)
|
||||
std::vector<TransformDualQuaternion> clusterTransforms;
|
||||
#else
|
||||
std::vector<glm::mat4> clusterTransforms;
|
||||
#endif
|
||||
std::vector<TransformDualQuaternion> clusterDualQuaternions;
|
||||
std::vector<glm::mat4> clusterMatrices;
|
||||
};
|
||||
|
||||
const MeshState& getMeshState(int index) { return _meshStates.at(index); }
|
||||
|
@ -323,6 +317,8 @@ public:
|
|||
Q_INVOKABLE MeshProxyList getMeshes() const;
|
||||
|
||||
void scaleToFit();
|
||||
bool getUseDualQuaternionSkinning() const { return _useDualQuaternionSkinning; }
|
||||
void setUseDualQuaternionSkinning(bool value);
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
|
@ -431,6 +427,7 @@ protected:
|
|||
virtual void createCollisionRenderItemSet();
|
||||
|
||||
bool _isWireframe;
|
||||
bool _useDualQuaternionSkinning { false };
|
||||
|
||||
// debug rendering support
|
||||
int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "model_lightmap_normal_map_vert.h"
|
||||
#include "skin_model_vert.h"
|
||||
#include "skin_model_normal_map_vert.h"
|
||||
#include "skin_model_dq_vert.h"
|
||||
#include "skin_model_normal_map_dq_vert.h"
|
||||
|
||||
#include "model_lightmap_fade_vert.h"
|
||||
#include "model_lightmap_normal_map_fade_vert.h"
|
||||
|
@ -33,6 +35,8 @@
|
|||
#include "model_translucent_normal_map_vert.h"
|
||||
#include "skin_model_fade_vert.h"
|
||||
#include "skin_model_normal_map_fade_vert.h"
|
||||
#include "skin_model_fade_dq_vert.h"
|
||||
#include "skin_model_normal_map_fade_dq_vert.h"
|
||||
|
||||
#include "simple_vert.h"
|
||||
#include "simple_textured_frag.h"
|
||||
|
@ -95,6 +99,7 @@
|
|||
|
||||
#include "model_shadow_vert.h"
|
||||
#include "skin_model_shadow_vert.h"
|
||||
#include "skin_model_shadow_dq_vert.h"
|
||||
|
||||
#include "model_shadow_frag.h"
|
||||
#include "skin_model_shadow_frag.h"
|
||||
|
@ -195,16 +200,28 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
auto modelTranslucentVertex = model_translucent_vert::getShader();
|
||||
auto modelTranslucentNormalMapVertex = model_translucent_normal_map_vert::getShader();
|
||||
auto modelShadowVertex = model_shadow_vert::getShader();
|
||||
|
||||
auto modelLightmapFadeVertex = model_lightmap_fade_vert::getShader();
|
||||
auto modelLightmapNormalMapFadeVertex = model_lightmap_normal_map_fade_vert::getShader();
|
||||
|
||||
// matrix palette skinned
|
||||
auto skinModelVertex = skin_model_vert::getShader();
|
||||
auto skinModelNormalMapVertex = skin_model_normal_map_vert::getShader();
|
||||
auto skinModelShadowVertex = skin_model_shadow_vert::getShader();
|
||||
auto modelLightmapFadeVertex = model_lightmap_fade_vert::getShader();
|
||||
auto modelLightmapNormalMapFadeVertex = model_lightmap_normal_map_fade_vert::getShader();
|
||||
auto skinModelFadeVertex = skin_model_fade_vert::getShader();
|
||||
auto skinModelNormalMapFadeVertex = skin_model_normal_map_fade_vert::getShader();
|
||||
auto skinModelTranslucentVertex = skinModelFadeVertex; // We use the same because it ouputs world position per vertex
|
||||
auto skinModelNormalMapTranslucentVertex = skinModelNormalMapFadeVertex; // We use the same because it ouputs world position per vertex
|
||||
|
||||
// dual quaternion skinned
|
||||
auto skinModelDualQuatVertex = skin_model_dq_vert::getShader();
|
||||
auto skinModelNormalMapDualQuatVertex = skin_model_normal_map_dq_vert::getShader();
|
||||
auto skinModelShadowDualQuatVertex = skin_model_shadow_dq_vert::getShader();
|
||||
auto skinModelFadeDualQuatVertex = skin_model_fade_dq_vert::getShader();
|
||||
auto skinModelNormalMapFadeDualQuatVertex = skin_model_normal_map_fade_dq_vert::getShader();
|
||||
auto skinModelTranslucentDualQuatVertex = skinModelFadeDualQuatVertex; // We use the same because it ouputs world position per vertex
|
||||
auto skinModelNormalMapTranslucentDualQuatVertex = skinModelNormalMapFadeDualQuatVertex; // We use the same because it ouputs world position per vertex
|
||||
|
||||
auto modelFadeVertex = model_fade_vert::getShader();
|
||||
auto modelNormalMapFadeVertex = model_normal_map_fade_vert::getShader();
|
||||
auto simpleFadeVertex = simple_fade_vert::getShader();
|
||||
|
@ -376,7 +393,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
Key::Builder().withMaterial().withLightmap().withTangents().withSpecular().withFade(),
|
||||
modelLightmapNormalMapFadeVertex, modelLightmapNormalSpecularMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// Skinned
|
||||
// matrix palette skinned
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned(),
|
||||
skinModelVertex, modelPixel, nullptr, nullptr);
|
||||
|
@ -403,7 +420,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
Key::Builder().withMaterial().withSkinned().withTangents().withSpecular().withFade(),
|
||||
skinModelNormalMapFadeVertex, modelNormalSpecularMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// Skinned and Translucent
|
||||
// matrix palette skinned and translucent
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent(),
|
||||
skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
|
@ -430,6 +447,60 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
|
||||
skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// dual quaternion skinned
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned(),
|
||||
skinModelDualQuatVertex, modelPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTangents(),
|
||||
skinModelNormalMapDualQuatVertex, modelNormalMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withSpecular(),
|
||||
skinModelDualQuatVertex, modelSpecularMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTangents().withSpecular(),
|
||||
skinModelNormalMapDualQuatVertex, modelNormalSpecularMapPixel, nullptr, nullptr);
|
||||
// Same thing but with Fade on
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withFade(),
|
||||
skinModelFadeDualQuatVertex, modelFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTangents().withFade(),
|
||||
skinModelNormalMapFadeDualQuatVertex, modelNormalMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withSpecular().withFade(),
|
||||
skinModelFadeDualQuatVertex, modelSpecularMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTangents().withSpecular().withFade(),
|
||||
skinModelNormalMapFadeDualQuatVertex, modelNormalSpecularMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// dual quaternion skinned and translucent
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent(),
|
||||
skinModelTranslucentDualQuatVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withTangents(),
|
||||
skinModelNormalMapTranslucentDualQuatVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withSpecular(),
|
||||
skinModelTranslucentDualQuatVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withTangents().withSpecular(),
|
||||
skinModelNormalMapTranslucentDualQuatVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
// Same thing but with Fade on
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withFade(),
|
||||
skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withTangents().withFade(),
|
||||
skinModelNormalMapFadeDualQuatVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withSpecular().withFade(),
|
||||
skinModelFadeDualQuatVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withDualQuatSkinned().withTranslucent().withTangents().withSpecular().withFade(),
|
||||
skinModelNormalMapFadeDualQuatVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// Depth-only
|
||||
addPipeline(
|
||||
Key::Builder().withDepthOnly(),
|
||||
|
|
|
@ -11,18 +11,16 @@
|
|||
<@if not SKINNING_SLH@>
|
||||
<@def SKINNING_SLH@>
|
||||
|
||||
// Use dual quaternion skinning
|
||||
// Must match #define SKIN_DQ in Model.h
|
||||
<@def SKIN_DQ@>
|
||||
|
||||
const int MAX_CLUSTERS = 128;
|
||||
const int INDICES_PER_VERTEX = 4;
|
||||
|
||||
<@func declareUseDualQuaternionSkinning(USE_DUAL_QUATERNION_SKINNING)@>
|
||||
|
||||
layout(std140) uniform skinClusterBuffer {
|
||||
mat4 clusterMatrices[MAX_CLUSTERS];
|
||||
};
|
||||
|
||||
<@if SKIN_DQ@>
|
||||
<@if USE_DUAL_QUATERNION_SKINNING@>
|
||||
|
||||
mat4 dualQuatToMat4(vec4 real, vec4 dual) {
|
||||
float twoRealXSq = 2.0 * real.x * real.x;
|
||||
|
@ -211,7 +209,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
|
|||
skinnedTangent = vec3(m * vec4(inTangent, 0));
|
||||
}
|
||||
|
||||
<@else@> // SKIN_DQ
|
||||
<@else@> // USE_DUAL_QUATERNION_SKINNING
|
||||
|
||||
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
|
||||
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
@ -260,6 +258,8 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
|
|||
skinnedTangent = newTangent.xyz;
|
||||
}
|
||||
|
||||
<@endif@> // if SKIN_DQ
|
||||
<@endif@> // if USE_DUAL_QUATERNION_SKINNING
|
||||
|
||||
<@endfunc@> // func declareUseDualQuaternionSkinning(USE_DUAL_QUATERNION_SKINNING)
|
||||
|
||||
<@endif@> // if not SKINNING_SLH
|
||||
|
|
|
@ -52,27 +52,27 @@ 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 (_useDualQuaternionSkinning) {
|
||||
glm::mat4 jointMatrix;
|
||||
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
|
||||
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
|
||||
} else {
|
||||
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
}
|
||||
|
||||
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);
|
||||
glm::mat4 m;
|
||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
|
||||
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(m);
|
||||
} else {
|
||||
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
}
|
||||
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
|
||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
|
52
libraries/render-utils/src/skin_model_dq.slv
Normal file
52
libraries/render-utils/src/skin_model_dq.slv
Normal file
|
@ -0,0 +1,52 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/14/13.
|
||||
// Copyright 2013 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec2 _texCoord0;
|
||||
out vec2 _texCoord1;
|
||||
out vec3 _normal;
|
||||
out vec3 _color;
|
||||
out float _alpha;
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal);
|
||||
|
||||
// pass along the color
|
||||
_color = colorToLinearRGB(inColor.rgb);
|
||||
_alpha = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, _normal.xyz)$>
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
|
54
libraries/render-utils/src/skin_model_fade_dq.slv
Normal file
54
libraries/render-utils/src/skin_model_fade_dq.slv
Normal file
|
@ -0,0 +1,54 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model_fade.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Olivier Prat on 06/045/17.
|
||||
// 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec2 _texCoord0;
|
||||
out vec2 _texCoord1;
|
||||
out vec3 _normal;
|
||||
out vec3 _color;
|
||||
out float _alpha;
|
||||
out vec4 _worldPosition;
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal);
|
||||
|
||||
// pass along the color
|
||||
_color = colorToLinearRGB(inColor.rgb);
|
||||
_alpha = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
|
||||
<$transformModelToWorldPos(obj, position, _worldPosition)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, _normal.xyz)$>
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
|
61
libraries/render-utils/src/skin_model_normal_map_dq.slv
Normal file
61
libraries/render-utils/src/skin_model_normal_map_dq.slv
Normal file
|
@ -0,0 +1,61 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model_normal_map.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/29/13.
|
||||
// Copyright 2013 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec2 _texCoord0;
|
||||
out vec2 _texCoord1;
|
||||
out vec3 _normal;
|
||||
out vec3 _tangent;
|
||||
out vec3 _color;
|
||||
out float _alpha;
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz);
|
||||
|
||||
// pass along the color
|
||||
_color = colorToLinearRGB(inColor.rgb);
|
||||
_alpha = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||
|
||||
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
|
||||
interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$>
|
||||
|
||||
_normal = interpolatedNormal.xyz;
|
||||
_tangent = interpolatedTangent.xyz;
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
|
61
libraries/render-utils/src/skin_model_normal_map_fade_dq.slv
Normal file
61
libraries/render-utils/src/skin_model_normal_map_fade_dq.slv
Normal file
|
@ -0,0 +1,61 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model_normal_map.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/29/13.
|
||||
// Copyright 2013 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTexMapArrayBuffer()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec2 _texCoord0;
|
||||
out vec2 _texCoord1;
|
||||
out vec3 _normal;
|
||||
out vec3 _tangent;
|
||||
out vec3 _color;
|
||||
out float _alpha;
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz);
|
||||
|
||||
// pass along the color
|
||||
_color = colorToLinearRGB(inColor.rgb);
|
||||
_alpha = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
|
||||
|
||||
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
|
||||
interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$>
|
||||
<$transformModelToWorldDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$>
|
||||
|
||||
_normal = interpolatedNormal.xyz;
|
||||
_tangent = interpolatedTangent.xyz;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
|
30
libraries/render-utils/src/skin_model_shadow_dq.slv
Normal file
30
libraries/render-utils/src/skin_model_shadow_dq.slv
Normal file
|
@ -0,0 +1,30 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model_shadow.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 3/24/14.
|
||||
// Copyright 2014 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, position, gl_Position)$>
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning()$>
|
||||
|
||||
out vec4 _worldPosition;
|
||||
|
||||
|
|
33
libraries/render-utils/src/skin_model_shadow_fade_dq.slv
Normal file
33
libraries/render-utils/src/skin_model_shadow_fade_dq.slv
Normal file
|
@ -0,0 +1,33 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// skin_model_shadow_fade.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Olivier Prat on 06/045/17.
|
||||
// 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 gpu/Inputs.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include Skinning.slh@>
|
||||
<$declareUseDualQuaternionSkinning(1)$>
|
||||
|
||||
out vec4 _worldPosition;
|
||||
|
||||
void main(void) {
|
||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position);
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, position, gl_Position)$>
|
||||
<$transformModelToWorldPos(obj, position, _worldPosition)$>
|
||||
}
|
|
@ -32,6 +32,7 @@ public:
|
|||
SPECULAR,
|
||||
UNLIT,
|
||||
SKINNED,
|
||||
DUAL_QUAT_SKINNED,
|
||||
DEPTH_ONLY,
|
||||
DEPTH_BIAS,
|
||||
WIREFRAME,
|
||||
|
@ -80,6 +81,7 @@ public:
|
|||
Builder& withSpecular() { _flags.set(SPECULAR); return (*this); }
|
||||
Builder& withUnlit() { _flags.set(UNLIT); return (*this); }
|
||||
Builder& withSkinned() { _flags.set(SKINNED); return (*this); }
|
||||
Builder& withDualQuatSkinned() { _flags.set(DUAL_QUAT_SKINNED); return (*this); }
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
|
||||
Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); }
|
||||
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
|
||||
|
@ -133,6 +135,9 @@ public:
|
|||
Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
|
||||
Builder& withDualQuatSkinned() { _flags.set(DUAL_QUAT_SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
Builder& withoutDualQuatSkinned() { _flags.reset(DUAL_QUAT_SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||
Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ protected:
|
|||
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) {
|
||||
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 << ")";
|
||||
debug << "DualQuaternion, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -601,3 +601,6 @@ glm::vec3 randVector() {
|
|||
return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.0f;
|
||||
}
|
||||
|
||||
bool isNonUniformScale(const glm::vec3& scale) {
|
||||
return fabsf(scale.x - scale.y) > EPSILON || fabsf(scale.y - scale.z) > EPSILON || fabsf(scale.z - scale.x) > EPSILON;
|
||||
}
|
||||
|
|
|
@ -260,6 +260,8 @@ glm::mat4 orthoInverse(const glm::mat4& m);
|
|||
// Return a random vector of average length 1
|
||||
glm::vec3 randVector();
|
||||
|
||||
bool isNonUniformScale(const glm::vec3& scale);
|
||||
|
||||
//
|
||||
// Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue