80 lines
3.0 KiB
C++
80 lines
3.0 KiB
C++
#include "CreatePrimCommand.h"
|
||
#include "../../utils/Logger.h"
|
||
#include <pxr/usd/usd/prim.h>
|
||
#include <pxr/usd/usdGeom/xformCommonAPI.h>
|
||
#include <pxr/usd/usdGeom/metrics.h>
|
||
#include <pxr/usd/usdGeom/tokens.h>
|
||
|
||
namespace UsdLayerManager {
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// ApplyCameraDefaultOrientation
|
||
//
|
||
// USD cameras always use +Y-up / look-down-−Z in their own local frame.
|
||
// For a Y-up stage that is already the standard world forward direction, so
|
||
// the identity transform is fine.
|
||
//
|
||
// For a Z-up stage the identity transform would point the camera straight
|
||
// DOWN (world −Z = −up), which produces wrong orientation when the viewport
|
||
// switches to the prim, and wrong tumble/roll directions when navigating.
|
||
//
|
||
// Fix: rotate the camera +90° around its local X axis so that:
|
||
// camera local +Y (up) → world +Z (stage up axis) ✓
|
||
// camera local −Z (view) → world +Y (horizontal "forward") ✓
|
||
// ---------------------------------------------------------------------------
|
||
static void ApplyCameraDefaultOrientation(pxr::UsdPrim& prim,
|
||
pxr::UsdStageRefPtr stage)
|
||
{
|
||
if (!prim.IsValid() || !stage) return;
|
||
|
||
bool isZUp = (pxr::UsdGeomGetStageUpAxis(stage) == pxr::UsdGeomTokens->z);
|
||
if (!isZUp) return; // Y-up default (identity) is already correct
|
||
|
||
pxr::UsdGeomXformCommonAPI xformAPI(prim);
|
||
// +90° around X: camera up aligns with world Z, view direction becomes +Y
|
||
xformAPI.SetRotate(pxr::GfVec3f(90.f, 0.f, 0.f),
|
||
pxr::UsdGeomXformCommonAPI::RotationOrderXYZ,
|
||
pxr::UsdTimeCode::Default());
|
||
}
|
||
|
||
CreatePrimCommand::CreatePrimCommand(pxr::UsdStageRefPtr stage,
|
||
const pxr::SdfPath& primPath,
|
||
const pxr::TfToken& typeName)
|
||
: m_stage(stage)
|
||
, m_primPath(primPath)
|
||
, m_typeName(typeName)
|
||
, m_description("Create " + typeName.GetString() + " " + primPath.GetString())
|
||
{
|
||
}
|
||
|
||
void CreatePrimCommand::Execute() {
|
||
if (!m_stage) return;
|
||
try {
|
||
pxr::UsdPrim prim = m_stage->DefinePrim(m_primPath, m_typeName);
|
||
if (!prim.IsValid()) {
|
||
LOG_ERROR("CreatePrimCommand: failed to define prim " + m_primPath.GetString());
|
||
return;
|
||
}
|
||
|
||
// Camera-specific initialisation: orient the prim so the camera looks
|
||
// in the correct "forward" direction for the stage's up-axis.
|
||
if (m_typeName == pxr::TfToken("Camera"))
|
||
ApplyCameraDefaultOrientation(prim, m_stage);
|
||
|
||
} catch (const std::exception& e) {
|
||
LOG_ERROR(std::string("CreatePrimCommand::Execute error: ") + e.what());
|
||
}
|
||
}
|
||
|
||
void CreatePrimCommand::Undo() {
|
||
if (!m_stage) return;
|
||
try {
|
||
if (!m_stage->RemovePrim(m_primPath))
|
||
LOG_ERROR("CreatePrimCommand: failed to remove prim " + m_primPath.GetString());
|
||
} catch (const std::exception& e) {
|
||
LOG_ERROR(std::string("CreatePrimCommand::Undo error: ") + e.what());
|
||
}
|
||
}
|
||
|
||
} // namespace UsdLayerManager
|