From 90845c175ee46cc59f1a7f4d45a2e8f1e7748842 Mon Sep 17 00:00:00 2001 From: Samuel Liu Date: Tue, 12 Nov 2024 17:18:55 -0500 Subject: [PATCH] Add prim reader writer to cylinder, disk and dome light --- .../fileio/translators/translatorLight.cpp | 180 ++++++++++++++++++ .../fileio/translators/translatorLight.h | 28 +++ lib/usd/translators/CMakeLists.txt | 7 + lib/usd/translators/lightReader.cpp | 12 ++ lib/usd/translators/lightWriter.cpp | 111 +++++++++++ lib/usd/translators/lightWriter.h | 12 ++ 6 files changed, 350 insertions(+) diff --git a/lib/mayaUsd/fileio/translators/translatorLight.cpp b/lib/mayaUsd/fileio/translators/translatorLight.cpp index 8fceb349df..dbb8fde20d 100644 --- a/lib/mayaUsd/fileio/translators/translatorLight.cpp +++ b/lib/mayaUsd/fileio/translators/translatorLight.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -62,6 +64,9 @@ TF_DEFINE_PRIVATE_TOKENS( ((DirectionalLightMayaTypeName, "directionalLight")) ((PointLightMayaTypeName, "pointLight")) ((AreaLightMayaTypeName, "areaLight")) + ((CylinderLightMayaTypeName, "volumeLight")) + ((DiskLightMayaTypeName, "volumeLight")) + ((DomeLightMayaTypeName, "volumeLight")) ((normalizeAttrName, "normalize")) // Maya light plug names. ((IntensityPlugName, "intensity")) @@ -76,6 +81,7 @@ TF_DEFINE_PRIVATE_TOKENS( ((PenumbraAnglePlugName, "penumbraAngle")) ((ConeAnglePlugName, "coneAngle")) ((LightRadiusPlugName, "lightRadius")) + ((LightLengthPlugName, "lightHeight")) ); // clang-format on @@ -424,6 +430,169 @@ static bool _ReadAreaLight( return success; } +// Export the specialized MFnVolumeLight attributes +bool UsdMayaTranslatorLight::WriteCylinderLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxCylinderLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter) +{ + MStatus status; + + MPlug lightRadiusPlug + = mayaLight.findPlug(_tokens->LightRadiusPlugName.GetText(), true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + float lightRadius = lightRadiusPlug.asFloat(); + + MPlug lightLengthPlug + = mayaLight.findPlug(_tokens->LightLengthPlugName.GetText(), true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + float lightLength = lightLengthPlug.asFloat(); + + UsdMayaWriteUtil::SetAttribute(usdLight.GetRadiusAttr(), lightRadius, usdTime, valueWriter); + UsdMayaWriteUtil::SetAttribute(usdLight.GetLengthAttr(), lightLength, usdTime, valueWriter); + + UsdPrim prim = usdLight.GetPrim(); + UsdLuxShapingAPI shapingAPI = UsdLuxShapingAPI::Apply(prim); + + return true; +} + +bool UsdMayaTranslatorLight::WriteDiskLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxDiskLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter) +{ + MStatus status; + + MPlug lightRadiusPlug + = mayaLight.findPlug(_tokens->LightRadiusPlugName.GetText(), true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + float lightRadius = lightRadiusPlug.asFloat(); + + UsdMayaWriteUtil::SetAttribute(usdLight.GetRadiusAttr(), lightRadius, usdTime, valueWriter); + + UsdPrim prim = usdLight.GetPrim(); + UsdLuxShapingAPI shapingAPI = UsdLuxShapingAPI::Apply(prim); + + return true; +} + +bool UsdMayaTranslatorLight::WriteDomeLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxDomeLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter) +{ + MStatus status; + + MPlug lightRadiusPlug + = mayaLight.findPlug(_tokens->LightRadiusPlugName.GetText(), true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + float lightRadius = lightRadiusPlug.asFloat(); + + UsdMayaWriteUtil::SetAttribute( + usdLight.CreateGuideRadiusAttr(), lightRadius, usdTime, valueWriter); + + UsdPrim prim = usdLight.GetPrim(); + UsdLuxShapingAPI shapingAPI = UsdLuxShapingAPI::Apply(prim); + + return true; +} + +static bool _ReadVolumeLight( + const UsdLuxLightAPI& lightSchema, + MFnDependencyNode& depFn, + const UsdMayaPrimReaderArgs& args, + UsdMayaPrimReaderContext& context) +{ + // Both Cylinder light and disk light will be mapped to volume light in Maya + + MStatus status; + bool success = true; + UsdPrim prim = lightSchema.GetPrim(); + + if (prim.IsA()) { + UsdLuxCylinderLight cylinderLight(prim); + MPlug plug = depFn.findPlug("lightShape", true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + success &= UsdMayaReadUtil::SetMayaAttr(plug, VtValue(2), false); + + MPlug plug2 = depFn.findPlug("faceAxis", true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + success &= UsdMayaReadUtil::SetMayaAttr(plug2, VtValue(0), false); + + success &= UsdMayaReadUtil::ReadUsdAttribute( + cylinderLight.GetRadiusAttr(), depFn, _tokens->LightRadiusPlugName, args, &context); + + UsdLuxShapingAPI shapingAPI(prim); + if (!shapingAPI) { + return false; + } + + // We need to specify a time when getting an attribute, otherwise we can get invalid data + // for single time-samples + UsdTimeCode timeCode(args.GetTimeInterval().GetMin()); + // We need some magic conversions between maya dropOff, coneAngle, penumbraAngle, + // and Usd shapingFocus, shapingConeAngle, shapingConeSoftness + success &= UsdMayaReadUtil::ReadUsdAttribute( + cylinderLight.GetLengthAttr(), depFn, _tokens->LightLengthPlugName, args, &context); + + return success; + + } else if (prim.IsA()) { + UsdLuxDiskLight diskLight(prim); + if (!diskLight) { + return false; + } + + MPlug plug = depFn.findPlug("lightShape", true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + success &= UsdMayaReadUtil::SetMayaAttr(plug, VtValue(2), false); + + MPlug plug2 = depFn.findPlug("faceAxis", true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + success &= UsdMayaReadUtil::SetMayaAttr(plug2, VtValue(2), false); + + success &= UsdMayaReadUtil::ReadUsdAttribute( + diskLight.GetRadiusAttr(), depFn, _tokens->LightRadiusPlugName, args, &context); + + UsdLuxShapingAPI shapingAPI(prim); + if (!shapingAPI) { + return false; + } + + return success; + } else if (prim.IsA()) { + UsdLuxDomeLight domeLight(prim); + if (!domeLight) { + return false; + } + + MPlug plug = depFn.findPlug("lightShape", true, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + success &= UsdMayaReadUtil::SetMayaAttr(plug, VtValue(1), false); + + success &= UsdMayaReadUtil::ReadUsdAttribute( + domeLight.GetGuideRadiusAttr(), depFn, _tokens->LightRadiusPlugName, args, &context); + + UsdLuxShapingAPI shapingAPI(prim); + if (!shapingAPI) { + return false; + } + + return success; + } else { + return false; + } +} + /* static */ bool UsdMayaTranslatorLight::Read( const UsdMayaPrimReaderArgs& args, @@ -456,6 +625,15 @@ bool UsdMayaTranslatorLight::Read( UsdLuxShapingAPI shapingAPI(lightSchema); mayaLightTypeToken = (shapingAPI) ? _tokens->SpotLightMayaTypeName : _tokens->PointLightMayaTypeName; + } else if (usdPrim.IsA()) { + // USD Cylinder Light => Maya Volume Light + mayaLightTypeToken = _tokens->CylinderLightMayaTypeName; + } else if (usdPrim.IsA()) { + // USD Disk Light => Maya Volume Light + mayaLightTypeToken = _tokens->DiskLightMayaTypeName; + } else if (usdPrim.IsA()) { + // USD Dome Light => Maya Dome Light + mayaLightTypeToken = _tokens->DomeLightMayaTypeName; } if (mayaLightTypeToken.IsEmpty()) { TF_RUNTIME_ERROR( @@ -513,6 +691,8 @@ bool UsdMayaTranslatorLight::Read( _ReadSpotLight(lightSchema, depFn, args, context); } else if (mayaLightTypeToken == _tokens->AreaLightMayaTypeName) { _ReadAreaLight(lightSchema, depFn, args, context); + } else if (mayaLightTypeToken == _tokens->CylinderLightMayaTypeName) { + _ReadVolumeLight(lightSchema, depFn, args, context); } return true; } diff --git a/lib/mayaUsd/fileio/translators/translatorLight.h b/lib/mayaUsd/fileio/translators/translatorLight.h index e2ee8f43ce..506584f390 100644 --- a/lib/mayaUsd/fileio/translators/translatorLight.h +++ b/lib/mayaUsd/fileio/translators/translatorLight.h @@ -24,7 +24,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -33,6 +36,7 @@ #include #include #include +#include PXR_NAMESPACE_OPEN_SCOPE @@ -81,6 +85,30 @@ struct UsdMayaTranslatorLight MFnAreaLight& mayaLight, FlexibleSparseValueWriter* valueWriter = nullptr); + /// Exports Maya's area light attributes using UsdLuxCylinderLight schema + MAYAUSD_CORE_PUBLIC + static bool WriteCylinderLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxCylinderLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter = nullptr); + + /// Exports Maya's area light attributes using UsdLuxRectLight schema + MAYAUSD_CORE_PUBLIC + static bool WriteDiskLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxDiskLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter = nullptr); + + /// Exports Maya's area light attributes using UsdLuxRectLight schema + MAYAUSD_CORE_PUBLIC + static bool WriteDomeLightAttrs( + const UsdTimeCode& usdTime, + const UsdLuxDomeLight& usdLight, + MFnVolumeLight& mayaLight, + FlexibleSparseValueWriter* valueWriter = nullptr); + /// Import a UsdLuxLightAPI schema as a corresponding Maya light. /// Return true if the maya light was properly created and imported MAYAUSD_CORE_PUBLIC diff --git a/lib/usd/translators/CMakeLists.txt b/lib/usd/translators/CMakeLists.txt index 8b5282e161..f5e3544436 100644 --- a/lib/usd/translators/CMakeLists.txt +++ b/lib/usd/translators/CMakeLists.txt @@ -50,6 +50,13 @@ if(CMAKE_UFE_V3_FEATURES_AVAILABLE) ) endif() +if (UFE_VOLUME_LIGHTS_SUPPORT) + target_compile_definitions(${TARGET_NAME} + PRIVATE + UFE_VOLUME_LIGHTS_SUPPORT=1 + ) +endif() + add_subdirectory(shading) # ----------------------------------------------------------------------------- diff --git a/lib/usd/translators/lightReader.cpp b/lib/usd/translators/lightReader.cpp index 8b699f2713..f3dc643b3b 100644 --- a/lib/usd/translators/lightReader.cpp +++ b/lib/usd/translators/lightReader.cpp @@ -31,7 +31,11 @@ PXRUSDMAYA_DEFINE_READER(UsdLuxCylinderLight, args, context) if (TfGetEnvSetting(MAYAUSD_IMPORT_RFM_LIGHTS)) { return UsdMayaTranslatorRfMLight::Read(args, context); } +#ifdef UFE_VOLUME_LIGHTS_SUPPORT + return UsdMayaTranslatorLight::Read(args, context); +#else return false; +#endif } PXRUSDMAYA_DEFINE_READER(UsdLuxDiskLight, args, context) @@ -39,7 +43,11 @@ PXRUSDMAYA_DEFINE_READER(UsdLuxDiskLight, args, context) if (TfGetEnvSetting(MAYAUSD_IMPORT_RFM_LIGHTS)) { return UsdMayaTranslatorRfMLight::Read(args, context); } +#ifdef UFE_VOLUME_LIGHTS_SUPPORT + return UsdMayaTranslatorLight::Read(args, context); +#else return false; +#endif } PXRUSDMAYA_DEFINE_READER(UsdLuxDistantLight, args, context) @@ -55,7 +63,11 @@ PXRUSDMAYA_DEFINE_READER(UsdLuxDomeLight, args, context) if (TfGetEnvSetting(MAYAUSD_IMPORT_RFM_LIGHTS)) { return UsdMayaTranslatorRfMLight::Read(args, context); } +#ifdef UFE_VOLUME_LIGHTS_SUPPORT + return UsdMayaTranslatorLight::Read(args, context); +#else return false; +#endif } PXRUSDMAYA_DEFINE_READER(UsdLuxGeometryLight, args, context) diff --git a/lib/usd/translators/lightWriter.cpp b/lib/usd/translators/lightWriter.cpp index ca6bacba5b..4505af1f77 100644 --- a/lib/usd/translators/lightWriter.cpp +++ b/lib/usd/translators/lightWriter.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -222,4 +223,114 @@ void PxrUsdTranslators_AreaLightWriter::Write(const UsdTimeCode& usdTime) usdTime, primSchema, lightFn, _GetSparseValueWriter()); } +#ifdef UFE_VOLUME_LIGHTS_SUPPORT +PXRUSDMAYA_REGISTER_WRITER(volumeLight, PxrUsdTranslators_VolumeLightWriter); + +PxrUsdTranslators_VolumeLightWriter::PxrUsdTranslators_VolumeLightWriter( + const MFnDependencyNode& depNodeFn, + const SdfPath& usdPath, + UsdMayaWriteJobContext& jobCtx) + : UsdMayaPrimWriter(depNodeFn, usdPath, jobCtx) +{ + MPlug plug = depNodeFn.findPlug("lightShape"); + VtValue lightShape + = UsdMayaWriteUtil::GetVtValue(plug, MayaUsd::Converter::getUsdTypeName(plug), false); + if (lightShape.IsEmpty()) { + return; + } + + if (lightShape == 1) { + UsdLuxDomeLight domeLight = UsdLuxDomeLight::Define(GetUsdStage(), GetUsdPath()); + _usdPrim = domeLight.GetPrim(); + } else { + // Both cylinder and disk lights have the light shape as 2 + MPlug plug2 = depNodeFn.findPlug("faceAxis"); + VtValue faceAxis + = UsdMayaWriteUtil::GetVtValue(plug2, MayaUsd::Converter::getUsdTypeName(plug2), false); + + // A way to tell if the volume Light is a cylinder or a disk is where the major axis is + // Cylinder light will have the major axis along the x-axis + // Disk light will emit light along the negative z-axis + if (faceAxis == 0) { + UsdLuxCylinderLight cylinderLight + = UsdLuxCylinderLight::Define(GetUsdStage(), GetUsdPath()); + _usdPrim = cylinderLight.GetPrim(); + + } else { + UsdLuxDiskLight diskLight = UsdLuxDiskLight::Define(GetUsdStage(), GetUsdPath()); + _usdPrim = diskLight.GetPrim(); + } + } + + if (!TF_VERIFY( + _usdPrim, + "Could not get UsdPrim for UsdLuxCylinderLight at path '%s'\n", + GetUsdPath().GetText())) { + return; + } +} + +/* virtual */ +void PxrUsdTranslators_VolumeLightWriter::Write(const UsdTimeCode& usdTime) +{ + MStatus status; + UsdMayaPrimWriter::Write(usdTime); + // Since write() above will take care of any animation on the light's + // transform, we only want to proceed here if: + // - We are at the default time and NO attributes on the shape are animated. + // OR + // - We are at a non-default time and some attribute on the shape IS animated. + if (usdTime.IsDefault() == _HasAnimCurves()) { + return; + } + if (_usdPrim.IsA()) { + UsdLuxCylinderLight primSchema(_usdPrim); + MFnVolumeLight lightFn(GetDagPath(), &status); + if (!status) { + // Do this just to get the print + CHECK_MSTATUS(status); + return; + } + // First write the base light attributes + UsdMayaTranslatorLight::WriteLightAttrs( + usdTime, primSchema.LightAPI(), lightFn, _GetSparseValueWriter()); + // Then write the specialized attributes for spot lights + UsdMayaTranslatorLight::WriteCylinderLightAttrs( + usdTime, primSchema, lightFn, _GetSparseValueWriter()); + + } else if (_usdPrim.IsA()) { + UsdLuxDiskLight primSchema(_usdPrim); + MFnVolumeLight lightFn(GetDagPath(), &status); + if (!status) { + // Do this just to get the print + CHECK_MSTATUS(status); + return; + } + // First write the base light attributes + UsdMayaTranslatorLight::WriteLightAttrs( + usdTime, primSchema.LightAPI(), lightFn, _GetSparseValueWriter()); + // Then write the specialized attributes for spot lights + UsdMayaTranslatorLight::WriteDiskLightAttrs( + usdTime, primSchema, lightFn, _GetSparseValueWriter()); + + } else if (_usdPrim.IsA()) { + UsdLuxDomeLight primSchema(_usdPrim); + MFnVolumeLight lightFn(GetDagPath(), &status); + if (!status) { + // Do this just to get the print + CHECK_MSTATUS(status); + return; + } + // First write the base light attributes + UsdMayaTranslatorLight::WriteLightAttrs( + usdTime, primSchema.LightAPI(), lightFn, _GetSparseValueWriter()); + // Then write the specialized attributes for spot lights + UsdMayaTranslatorLight::WriteDomeLightAttrs( + usdTime, primSchema, lightFn, _GetSparseValueWriter()); + } else { + return; + } +} +#endif // UFE_VOLUME_LIGHTS_SUPPORT + PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/usd/translators/lightWriter.h b/lib/usd/translators/lightWriter.h index 058a373eee..4c15c0ca3c 100644 --- a/lib/usd/translators/lightWriter.h +++ b/lib/usd/translators/lightWriter.h @@ -88,6 +88,18 @@ class PxrUsdTranslators_AreaLightWriter : public UsdMayaPrimWriter void Write(const UsdTimeCode& usdTime) override; }; +/// Exports Maya volume lights to UsdLux sphere lights +class PxrUsdTranslators_VolumeLightWriter : public UsdMayaPrimWriter +{ +public: + PxrUsdTranslators_VolumeLightWriter( + const MFnDependencyNode& depNodeFn, + const SdfPath& usdPath, + UsdMayaWriteJobContext& jobCtx); + + void Write(const UsdTimeCode& usdTime) override; +}; + PXR_NAMESPACE_CLOSE_SCOPE #endif