Skip to content

Commit

Permalink
Support orientation xform with globe anchors
Browse files Browse the repository at this point in the history
  • Loading branch information
lilleyse committed Feb 22, 2024
1 parent 36b7ba9 commit 826be31
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 26 deletions.
4 changes: 4 additions & 0 deletions src/core/include/cesium/omniverse/MathUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ glm::dmat4 composeEuler(
const glm::dvec3& rotation,
const glm::dvec3& scale,
EulerAngleOrder eulerAngleOrder);

glm::dmat4 compose(const glm::dvec3& translation, const glm::dquat& rotation, const glm::dvec3& scale);

bool equal(const CesiumGeospatial::Cartographic& a, const CesiumGeospatial::Cartographic& b);
bool epsilonEqual(const CesiumGeospatial::Cartographic& a, const CesiumGeospatial::Cartographic& b, double epsilon);
bool epsilonEqual(const glm::dmat4& a, const glm::dmat4& b, double epsilon);
bool epsilonEqual(const glm::dvec3& a, const glm::dvec3& b, double epsilon);
bool epsilonEqual(const glm::dquat& a, const glm::dquat& b, double epsilon);

glm::dvec3 getCorner(const std::array<glm::dvec3, 2>& extent, uint64_t index);

Expand Down
3 changes: 3 additions & 0 deletions src/core/include/cesium/omniverse/OmniGlobeAnchor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <CesiumGeospatial/Cartographic.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <pxr/usd/sdf/path.h>

namespace CesiumGeospatial {
Expand Down Expand Up @@ -41,6 +42,7 @@ class OmniGlobeAnchor {
[[nodiscard]] CesiumGeospatial::Cartographic getGeographicCoordinates() const;
[[nodiscard]] glm::dvec3 getPrimLocalTranslation() const;
[[nodiscard]] glm::dvec3 getPrimLocalRotation() const;
[[nodiscard]] glm::dquat getPrimLocalOrientation() const;
[[nodiscard]] glm::dvec3 getPrimLocalScale() const;

void savePrimLocalToEcefTranslation();
Expand All @@ -58,6 +60,7 @@ class OmniGlobeAnchor {
CesiumGeospatial::Cartographic _cachedGeographicCoordinates{0.0, 0.0, 0.0};
glm::dvec3 _cachedPrimLocalTranslation{0.0};
glm::dvec3 _cachedPrimLocalRotation{0.0, 0.0, 0.0};
glm::dquat _cachedPrimLocalOrientation{1.0, 0.0, 0.0, 0.0};
glm::dvec3 _cachedPrimLocalScale{1.0};
};

Expand Down
6 changes: 5 additions & 1 deletion src/core/include/cesium/omniverse/UsdUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ namespace cesium::omniverse::UsdUtil {
glm::dvec3 usdToGlmVector(const pxr::GfVec3d& vector);
glm::fvec3 usdToGlmVector(const pxr::GfVec3f& vector);
glm::dmat4 usdToGlmMatrix(const pxr::GfMatrix4d& matrix);
glm::dquat usdToGlmQuat(const pxr::GfQuatd& quat);
glm::fquat usdToGlmQuat(const pxr::GfQuatf& quat);
std::array<glm::dvec3, 2> usdToGlmExtent(const pxr::GfRange3d& extent);

pxr::GfVec3d glmToUsdVector(const glm::dvec3& vector);
Expand Down Expand Up @@ -155,14 +157,16 @@ bool isUsdMaterial(const pxr::UsdStageWeakPtr& pStage, const pxr::SdfPath& path)

glm::dvec3 getTranslate(const pxr::UsdGeomXformOp& translateOp);
glm::dvec3 getRotate(const pxr::UsdGeomXformOp& rotateOp);
glm::dquat getOrient(const pxr::UsdGeomXformOp& orientOp);
glm::dvec3 getScale(const pxr::UsdGeomXformOp& scaleOp);
void setTranslate(pxr::UsdGeomXformOp& translateOp, const glm::dvec3& translate);
void setRotate(pxr::UsdGeomXformOp& rotateOp, const glm::dvec3& rotate);
void setOrient(pxr::UsdGeomXformOp& orientOp, const glm::dquat& orient);
void setScale(pxr::UsdGeomXformOp& scaleOp, const glm::dvec3& scale);

struct TranslateRotateScaleOps {
pxr::UsdGeomXformOp translateOp;
pxr::UsdGeomXformOp rotateOp;
pxr::UsdGeomXformOp rotateOrOrientOp;
pxr::UsdGeomXformOp scaleOp;
MathUtil::EulerAngleOrder eulerAngleOrder;
};
Expand Down
4 changes: 2 additions & 2 deletions src/core/src/FabricGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ namespace {
const auto DEFAULT_DOUBLE_SIDED = false;
const auto DEFAULT_EXTENT = std::array<glm::dvec3, 2>{{glm::dvec3(0.0, 0.0, 0.0), glm::dvec3(0.0, 0.0, 0.0)}};
const auto DEFAULT_POSITION = glm::dvec3(0.0, 0.0, 0.0);
const auto DEFAULT_ORIENTATION = glm::dquat(1.0f, 0.0, 0.0, 0.0);
const auto DEFAULT_SCALE = glm::dvec3(1.0f, 1.0f, 1.0f);
const auto DEFAULT_ORIENTATION = glm::dquat(1.0, 0.0, 0.0, 0.0);
const auto DEFAULT_SCALE = glm::dvec3(1.0, 1.0, 1.0);
const auto DEFAULT_MATRIX = glm::dmat4(1.0);
const auto DEFAULT_VISIBILITY = false;

Expand Down
12 changes: 12 additions & 0 deletions src/core/src/MathUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ glm::dmat4 composeEuler(
return translationMatrix * rotationMatrix * scaleMatrix;
}

glm::dmat4 compose(const glm::dvec3& translation, const glm::dquat& rotation, const glm::dvec3& scale) {
const auto translationMatrix = glm::translate(glm::dmat4(1.0), translation);
const auto rotationMatrix = glm::mat4_cast(rotation);
const auto scaleMatrix = glm::scale(glm::dmat4(1.0), scale);

return translationMatrix * rotationMatrix * scaleMatrix;
}

bool equal(const CesiumGeospatial::Cartographic& a, const CesiumGeospatial::Cartographic& b) {
const auto& aVec = *reinterpret_cast<const glm::dvec3*>(&a);
const auto& bVec = *reinterpret_cast<const glm::dvec3*>(&b);
Expand All @@ -129,6 +137,10 @@ bool epsilonEqual(const glm::dvec3& a, const glm::dvec3& b, double epsilon) {
return glm::all(glm::epsilonEqual(a, b, epsilon));
}

bool epsilonEqual(const glm::dquat& a, const glm::dquat& b, double epsilon) {
return glm::all(glm::epsilonEqual(a, b, epsilon));
}

glm::dvec3 getCorner(const std::array<glm::dvec3, 2>& extent, uint64_t index) {
return {
(index & 1) ? extent[1].x : extent[0].x,
Expand Down
89 changes: 69 additions & 20 deletions src/core/src/OmniGlobeAnchor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@ void OmniGlobeAnchor::updateByPrimLocalTransform(bool resetOrientation) {

const auto primLocalTranslation = getPrimLocalTranslation();
const auto primLocalRotation = getPrimLocalRotation();
const auto primLocalOrientation = getPrimLocalOrientation();
const auto primLocalScale = getPrimLocalScale();

const auto tolerance = CesiumUtility::Math::Epsilon4;
if (MathUtil::epsilonEqual(primLocalTranslation, _cachedPrimLocalTranslation, tolerance) &&
MathUtil::epsilonEqual(primLocalRotation, _cachedPrimLocalRotation, tolerance) &&
MathUtil::epsilonEqual(primLocalOrientation, _cachedPrimLocalOrientation, tolerance) &&
MathUtil::epsilonEqual(primLocalScale, _cachedPrimLocalScale, tolerance)) {
// Short circuit if we don't need to do an actual update.
return;
Expand All @@ -169,12 +171,21 @@ void OmniGlobeAnchor::updateByPrimLocalTransform(bool resetOrientation) {
const auto cesiumGlobeAnchor = UsdUtil::getCesiumGlobeAnchor(_pContext->getUsdStage(), _path);
const auto xformable = pxr::UsdGeomXformable(cesiumGlobeAnchor);
const auto xformOps = UsdUtil::getOrCreateTranslateRotateScaleOps(xformable);
const auto eulerAngleOrder = xformOps->eulerAngleOrder;

// xform ops are applied right to left, so xformOp:rotateXYZ actually applies a z-axis, then y-axis, then x-axis
// rotation. To compensate for that, we need to compose euler angles in the reverse order.
const auto primLocalTransform = MathUtil::composeEuler(
primLocalTranslation, primLocalRotation, primLocalScale, getReversedEulerAngleOrder(eulerAngleOrder));
const auto opType = xformOps.value().rotateOrOrientOp.GetOpType();

glm::dmat4 primLocalTransform;

if (opType == pxr::UsdGeomXformOp::TypeOrient) {
primLocalTransform = MathUtil::compose(primLocalTranslation, primLocalOrientation, primLocalScale);
} else {
// xform ops are applied right to left, so xformOp:rotateXYZ actually applies a z-axis, then y-axis, then x-axis
// rotation. To compensate for that, we need to compose euler angles in the reverse order.
primLocalTransform = MathUtil::composeEuler(
primLocalTranslation,
primLocalRotation,
primLocalScale,
getReversedEulerAngleOrder(xformOps->eulerAngleOrder));
}

const auto pGeoreference = _pContext->getAssetRegistry().getGeoreference(getResolvedGeoreferencePath());

Expand Down Expand Up @@ -330,7 +341,32 @@ glm::dvec3 OmniGlobeAnchor::getPrimLocalRotation() const {
}

const auto xformOps = UsdUtil::getOrCreateTranslateRotateScaleOps(xformable);
return glm::radians(UsdUtil::getRotate(xformOps.value().rotateOp));
const auto& rotateOrOrientOp = xformOps.value().rotateOrOrientOp;
const auto opType = rotateOrOrientOp.GetOpType();

if (opType == pxr::UsdGeomXformOp::TypeOrient) {
return {0.0, 0.0, 0.0};
}

return glm::radians(UsdUtil::getRotate(rotateOrOrientOp));
}

glm::dquat OmniGlobeAnchor::getPrimLocalOrientation() const {
const auto cesiumGlobeAnchor = UsdUtil::getCesiumGlobeAnchor(_pContext->getUsdStage(), _path);
const auto xformable = pxr::UsdGeomXformable(cesiumGlobeAnchor);
if (!UsdUtil::isSchemaValid(xformable)) {
return {1.0, 0.0, 0.0, 0.0};
}

const auto xformOps = UsdUtil::getOrCreateTranslateRotateScaleOps(xformable);
const auto& rotateOrOrientOp = xformOps.value().rotateOrOrientOp;
const auto opType = rotateOrOrientOp.GetOpType();

if (opType != pxr::UsdGeomXformOp::TypeOrient) {
return {1.0, 0.0, 0.0, 0.0};
}

return UsdUtil::getOrient(rotateOrOrientOp);
}

glm::dvec3 OmniGlobeAnchor::getPrimLocalScale() const {
Expand Down Expand Up @@ -392,25 +428,38 @@ void OmniGlobeAnchor::savePrimLocalTransform() {

auto xformOps = UsdUtil::getOrCreateTranslateRotateScaleOps(xformable);

auto& [translateOp, rotateOp, scaleOp, eulerAngleOrder] = xformOps.value();
auto& [translateOp, rotateOrOrientOp, scaleOp, eulerAngleOrder] = xformOps.value();
const auto opType = rotateOrOrientOp.GetOpType();

const auto pGeoreference = _pContext->getAssetRegistry().getGeoreference(getResolvedGeoreferencePath());

const auto primLocalToWorldTransform =
_pAnchor->getAnchorToLocalTransform(pGeoreference->getLocalCoordinateSystem());

// xform ops are applied right to left, so xformOp:rotateXYZ actually applies a z-axis, then y-axis, then x-axis
// rotation. To compensate for that, we need to decompose euler angles in the reverse order.
const auto decomposed =
MathUtil::decomposeEuler(primLocalToWorldTransform, getReversedEulerAngleOrder(eulerAngleOrder));

_cachedPrimLocalTranslation = decomposed.translation;
_cachedPrimLocalRotation = decomposed.rotation;
_cachedPrimLocalScale = decomposed.scale;

UsdUtil::setTranslate(translateOp, decomposed.translation);
UsdUtil::setRotate(rotateOp, glm::degrees(decomposed.rotation));
UsdUtil::setScale(scaleOp, decomposed.scale);
if (opType == pxr::UsdGeomXformOp::TypeOrient) {
const auto decomposed = MathUtil::decompose(primLocalToWorldTransform);

_cachedPrimLocalTranslation = decomposed.translation;
_cachedPrimLocalOrientation = decomposed.rotation;
_cachedPrimLocalScale = decomposed.scale;

UsdUtil::setTranslate(translateOp, decomposed.translation);
UsdUtil::setOrient(rotateOrOrientOp, decomposed.rotation);
UsdUtil::setScale(scaleOp, decomposed.scale);
} else {
// xform ops are applied right to left, so xformOp:rotateXYZ actually applies a z-axis, then y-axis, then x-axis
// rotation. To compensate for that, we need to decompose euler angles in the reverse order.
const auto decomposed =
MathUtil::decomposeEuler(primLocalToWorldTransform, getReversedEulerAngleOrder(eulerAngleOrder));

_cachedPrimLocalTranslation = decomposed.translation;
_cachedPrimLocalRotation = decomposed.rotation;
_cachedPrimLocalScale = decomposed.scale;

UsdUtil::setTranslate(translateOp, decomposed.translation);
UsdUtil::setRotate(rotateOrOrientOp, glm::degrees(decomposed.rotation));
UsdUtil::setScale(scaleOp, decomposed.scale);
}
}

} // namespace cesium::omniverse
72 changes: 69 additions & 3 deletions src/core/src/UsdUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ glm::dmat4 usdToGlmMatrix(const pxr::GfMatrix4d& matrix) {
};
}

glm::dquat usdToGlmQuat(const pxr::GfQuatd& quat) {
const auto real = quat.GetReal();
const auto imaginary = usdToGlmVector(quat.GetImaginary());
return {real, imaginary.x, imaginary.y, imaginary.z};
}

glm::fquat usdToGlmQuat(const pxr::GfQuatf& quat) {
const auto real = quat.GetReal();
const auto imaginary = usdToGlmVector(quat.GetImaginary());
return {real, imaginary.x, imaginary.y, imaginary.z};
}

std::array<glm::dvec3, 2> usdToGlmExtent(const pxr::GfRange3d& extent) {
return {{usdToGlmVector(extent.GetMin()), usdToGlmVector(extent.GetMax())}};
}
Expand Down Expand Up @@ -594,6 +606,20 @@ glm::dvec3 getRotate(const pxr::UsdGeomXformOp& rotateOp) {
return glm::dvec3(0.0);
}

glm::dquat getOrient(const pxr::UsdGeomXformOp& orientOp) {
if (orientOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionDouble) {
pxr::GfQuatd orient;
orientOp.Get(&orient);
return UsdUtil::usdToGlmQuat(orient);
} else if (orientOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionFloat) {
pxr::GfQuatf orient;
orientOp.Get(&orient);
return glm::dquat(UsdUtil::usdToGlmQuat(orient));
}

return {1.0, 0.0, 0.0, 0.0};
}

glm::dvec3 getScale(const pxr::UsdGeomXformOp& scaleOp) {
if (scaleOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionDouble) {
pxr::GfVec3d scale;
Expand Down Expand Up @@ -624,6 +650,14 @@ void setRotate(pxr::UsdGeomXformOp& rotateOp, const glm::dvec3& rotate) {
}
}

void setOrient(pxr::UsdGeomXformOp& orientOp, const glm::dquat& orient) {
if (orientOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionDouble) {
orientOp.Set(UsdUtil::glmToUsdQuat(orient));
} else if (orientOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionFloat) {
orientOp.Set(UsdUtil::glmToUsdQuat(glm::fquat(orient)));
}
}

void setScale(pxr::UsdGeomXformOp& scaleOp, const glm::dvec3& scale) {
if (scaleOp.GetPrecision() == pxr::UsdGeomXformOp::PrecisionDouble) {
scaleOp.Set(UsdUtil::glmToUsdVector(scale));
Expand All @@ -635,10 +669,12 @@ void setScale(pxr::UsdGeomXformOp& scaleOp, const glm::dvec3& scale) {
std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const pxr::UsdGeomXformable& xformable) {
pxr::UsdGeomXformOp translateOp;
pxr::UsdGeomXformOp rotateOp;
pxr::UsdGeomXformOp orientOp;
pxr::UsdGeomXformOp scaleOp;

int64_t translateOpIndex = -1;
int64_t rotateOpIndex = -1;
int64_t orientOpIndex = -1;
int64_t scaleOpIndex = -1;

int64_t opCount = 0;
Expand Down Expand Up @@ -698,6 +734,12 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const
rotateOpIndex = opCount;
}
break;
case pxr::UsdGeomXformOp::TypeOrient:
if (orientOpIndex == -1) {
orientOp = xformOp;
orientOpIndex = opCount;
}
break;
case pxr::UsdGeomXformOp::TypeScale:
if (scaleOpIndex == -1) {
scaleOp = xformOp;
Expand All @@ -713,8 +755,13 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const

const auto translateOpDefined = translateOp.IsDefined();
const auto rotateOpDefined = rotateOp.IsDefined();
const auto orientOpDefined = orientOp.IsDefined();
const auto scaleOpDefined = scaleOp.IsDefined();

if (rotateOpDefined && orientOpDefined) {
return std::nullopt;
}

opCount = 0;

if (translateOpDefined && translateOpIndex != opCount++) {
Expand All @@ -725,6 +772,10 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const
return std::nullopt;
}

if (orientOpDefined && orientOpIndex != opCount++) {
return std::nullopt;
}

if (scaleOpDefined && scaleOpIndex != opCount++) {
return std::nullopt;
}
Expand All @@ -741,6 +792,10 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const
return std::nullopt;
}

if (orientOpDefined && !isPrecisionSupported(orientOp.GetPrecision())) {
return std::nullopt;
}

if (scaleOpDefined && !isPrecisionSupported(scaleOp.GetPrecision())) {
return std::nullopt;
}
Expand All @@ -750,7 +805,7 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const
translateOp.Set(UsdUtil::glmToUsdVector(glm::dvec3(0.0)));
}

if (!rotateOpDefined) {
if (!rotateOpDefined && !orientOpDefined) {
rotateOp = xformable.AddRotateXYZOp(pxr::UsdGeomXformOp::PrecisionDouble);
rotateOp.Set(UsdUtil::glmToUsdVector(glm::dvec3(0.0)));
}
Expand All @@ -760,13 +815,24 @@ std::optional<TranslateRotateScaleOps> getOrCreateTranslateRotateScaleOps(const
scaleOp.Set(UsdUtil::glmToUsdVector(glm::dvec3(1.0)));
}

if (!translateOpDefined || !rotateOpDefined || !scaleOpDefined) {
std::vector<pxr::UsdGeomXformOp> reorderedXformOps = {translateOp, rotateOp, scaleOp};
if (!translateOpDefined || (!rotateOpDefined && !orientOpDefined) || !scaleOpDefined) {
std::vector<pxr::UsdGeomXformOp> reorderedXformOps;

if (orientOpDefined) {
reorderedXformOps = {translateOp, orientOp, scaleOp};
} else {
reorderedXformOps = {translateOp, rotateOp, scaleOp};
}

// Add back additional xform ops like xformOp:rotateX:unitsResolve
reorderedXformOps.insert(reorderedXformOps.end(), xformOps.begin() + opCount, xformOps.end());
xformable.SetXformOpOrder(reorderedXformOps);
}

if (orientOpDefined) {
return TranslateRotateScaleOps{translateOp, orientOp, scaleOp, eulerAngleOrder};
}

return TranslateRotateScaleOps{translateOp, rotateOp, scaleOp, eulerAngleOrder};
}

Expand Down

0 comments on commit 826be31

Please sign in to comment.