Compare commits

...

2 Commits

Author SHA1 Message Date
indigo a24eff04bd CMake: drop invalid OPTIONAL from Cycles runtime-deps install
install(DIRECTORY) disallows OPTIONAL together with FILES_MATCHING, which
broke reconfigure. The directory is always present here (produced by the
CyclesBuild step), so OPTIONAL was unnecessary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:49:29 +08:00
indigo 4d3cc85ece Fix rotate manipulator desync on already-rotated prims
The matrix->Euler decode at the end of a rotate drag used the rows of the
prim's initial rotation matrix (its already-rotated frame) as the
DecomposeRotation axes. But UsdGeomXformCommonAPI::SetRotate interprets the
written angles about the CANONICAL x/y/z axes, so the two only agreed when
the prim was at zero rotation -- the authored orientation desynced from the
manipulator the moment the prim already carried a rotation.

Decompose the result matrix about the canonical axes instead, matching how
SetRotate reconstructs it. The result-matrix computation (which correctly
tracks the visual ring axis) is unchanged.

Verified numerically via the real XformCommonAPI authoring path: from
rotateXYZ=(30,45,60), a +20deg object-X drag now authors exactly
(50,45,60) (err 0.0) vs the old decode's (41.07,27.07,66.61) (err 0.287).

Assumes RotationOrderXYZ (the XformCommonAPI default); non-XYZ orders are
mapped as before -- noted in a code comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:49:22 +08:00
2 changed files with 19 additions and 8 deletions
+3 -2
View File
@@ -402,11 +402,12 @@ if(OPENUSD_HAS_CYCLES)
DESTINATION bin/usd
OPTIONAL
)
# Cycles runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, etc.)
# Cycles runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, etc.).
# No OPTIONAL: install(DIRECTORY) disallows it with FILES_MATCHING, and the
# dir always exists here since it is produced by the CyclesBuild step.
install(DIRECTORY "${CYCLES_INSTALL_DIR}/"
DESTINATION bin
FILES_MATCHING PATTERN "*.dll"
OPTIONAL
)
# tbb12.dll (used by openvdb/embree4) lives in the precompiled lib tree, not install output
install(FILES "${CYCLES_TBB12_DLL}"
+16 -6
View File
@@ -645,11 +645,21 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp,
? deltaM * m_dragRotateInitialRotMat
: m_dragRotateInitialRotMat * deltaM;
// usdtweak: GfRotation::DecomposeRotation(resultingRotation,
// pxAxis, pyAxis, pzAxis, 1.0, &tw, &fb, &lr, &sw, true)
const pxr::GfVec3d pxA=m_dragRotateInitialRotMat.GetRow3(0);
const pxr::GfVec3d pyA=m_dragRotateInitialRotMat.GetRow3(1);
const pxr::GfVec3d pzA=m_dragRotateInitialRotMat.GetRow3(2);
// Decompose `result` (the new total local rotation matrix) back
// into XformCommonAPI Euler angles.
//
// SetRotate() interprets the written angles as rotations about the
// CANONICAL x/y/z axes, so the decompose axes MUST be canonical.
// The previous port used the rows of initRot here -- i.e. the prim's
// already-rotated frame -- which equals the canonical axes only when
// the prim is at zero rotation. That mismatch is exactly why the
// authored result desynced from the manipulator once the prim already
// carried a rotation: the angles were measured in the rotated frame
// but written as if they were canonical-frame angles.
//
// (Decomposition assumes RotationOrderXYZ -- the XformCommonAPI
// default; non-XYZ orders are mapped tw->X, fb->Y, lr->Z as before.)
static const pxr::GfVec3d kCanonX(1,0,0), kCanonY(0,1,0), kCanonZ(0,0,1);
double tw=pxr::GfDegreesToRadians(double(m_dragStartRotate[0]));
double fb=pxr::GfDegreesToRadians(double(m_dragStartRotate[1]));
@@ -657,7 +667,7 @@ bool TransformManipulator::HandleInput(const pxr::GfMatrix4d& vp,
double sw=0;
pxr::GfRotation::DecomposeRotation(
result,pxA,pyA,pzA,1.0,&tw,&fb,&lr,&sw,/*useHint=*/true);
result,kCanonX,kCanonY,kCanonZ,1.0,&tw,&fb,&lr,&sw,/*useHint=*/true);
pxr::GfVec3f newRot(float(pxr::GfRadiansToDegrees(tw)),
float(pxr::GfRadiansToDegrees(fb)),