159 lines · 5.0 KB · C++
RawDownload
////  Transform.cpp//  shared/src/gpu////  Created by Sam Gateau on 11/4/2014.//  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 "Transform.h" #include <QtCore/QJsonValue>#include <QtCore/QJsonObject>#include <QtCore/QJsonArray> #include "NumericalConstants.h"#include "shared/JSONHelpers.h" void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix) {    const float ACCURACY_THREASHOLD = 0.00001f;     // Following technique taken from:    // http://callumhay.blogspot.com/2010/10/decomposing-affine-transforms.html    // Extract the rotation component - this is done using polar decompostion, where    // we successively average the matrix with its inverse transpose until there is    // no/a very small difference between successive averages    float norm;    int count = 0;    Mat3 rotationMat = rotationScaleMatrix;    do {        Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat));                Mat3 nextRotation = 0.5f * (rotationMat + currInvTranspose);         norm = 0.0;        for (int i = 0; i < 3; i++) {            float n = static_cast<float>(                         fabs(rotationMat[0][i] - nextRotation[0][i]) +                         fabs(rotationMat[1][i] - nextRotation[1][i]) +                         fabs(rotationMat[2][i] - nextRotation[2][i]));            norm = (norm > n ? norm : n);        }        rotationMat = nextRotation;    } while (count++ < 100 && norm > ACCURACY_THREASHOLD);      // extract scale of the matrix as the length of each axis    Mat3 scaleMat = glm::inverse(rotationMat) * rotationScaleMatrix;     scale = Vec3(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2]);     // Let's work on a local matrix containing rotation only    Mat3 matRot(        rotationScaleMatrix[0] / scale.x,        rotationScaleMatrix[1] / scale.y,        rotationScaleMatrix[2] / scale.z);     // Beware!!! needs to detect for the case there is a negative scale    // Based on the determinant sign we just can flip the scale sign of one component: we choose X axis    float determinant = glm::determinant(matRot);    if (determinant < 0.0f) {        scale.x = -scale.x;        matRot[0] *= -1.0f;    }     // Beware: even though the matRot is supposed to be normalized at that point,    // glm::quat_cast doesn't always return a normalized quaternion...   // rotation = glm::normalize(glm::quat_cast(matRot));    rotation = (glm::quat_cast(matRot));} Transform Transform::relativeTransform(const Transform& worldTransform) const {    if (isIdentity()) {        return worldTransform;    }     if (*this == worldTransform) {        return Transform();    }     Transform result;    inverseMult(result, *this, worldTransform);    return result;} Transform Transform::worldTransform(const Transform& relativeTransform) const {    if (relativeTransform.isIdentity()) {        return *this;    }     if (isIdentity()) {        return relativeTransform;    }     Transform result;    mult(result, *this, relativeTransform);    return result;}  static const QString JSON_TRANSLATION = QStringLiteral("translation");static const QString JSON_ROTATION = QStringLiteral("rotation");static const QString JSON_SCALE = QStringLiteral("scale"); Transform Transform::fromJson(const QJsonValue& json) {    if (!json.isObject()) {        return Transform();    }    QJsonObject obj = json.toObject();    Transform result;    if (obj.contains(JSON_ROTATION)) {        result.setRotation(quatFromJsonValue(obj[JSON_ROTATION]));    }    if (obj.contains(JSON_TRANSLATION)) {        result.setTranslation(vec3FromJsonValue(obj[JSON_TRANSLATION]));    }    if (obj.contains(JSON_SCALE)) {        result.setScale(vec3FromJsonValue(obj[JSON_SCALE]));    }    return result;} QJsonObject Transform::toJson(const Transform& transform) {    if (transform.isIdentity()) {        return QJsonObject();    }     QJsonObject result;    if (transform.getTranslation() != vec3()) {        auto json = toJsonValue(transform.getTranslation());        if (!json.isNull()) {            result[JSON_TRANSLATION] = json;        }    }     if (transform.getRotation() != quat()) {        auto json = toJsonValue(transform.getRotation());        if (!json.isNull()) {            result[JSON_ROTATION] = json;        }    }     if (transform.getScale() != vec3(1.0f)) {        auto json = toJsonValue(transform.getScale());        if (!json.isNull()) {            result[JSON_SCALE] = json;        }    }    return result;} QDebug& operator<<(QDebug& debug, const Transform& transform) {    debug << "Transform, trans = (" << transform._translation.x << transform._translation.y << transform._translation.z << "), rot = ("          << transform._rotation.x << transform._rotation.y << transform._rotation.z << transform._rotation.w << "), scale = ("          << transform._scale.x << transform._scale.y << transform._scale.z << ")";    return debug;}