diff --git a/lib/mayaUsd/ufe/CMakeLists.txt b/lib/mayaUsd/ufe/CMakeLists.txt index c3174427d5..979b0c601d 100644 --- a/lib/mayaUsd/ufe/CMakeLists.txt +++ b/lib/mayaUsd/ufe/CMakeLists.txt @@ -79,6 +79,14 @@ if(CMAKE_UFE_V3_FEATURES_AVAILABLE) endif() if(CMAKE_UFE_V4_FEATURES_AVAILABLE) + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4007) + target_sources(${PROJECT_NAME} + PRIVATE + UsdLight.cpp + UsdLightHandler.cpp + ) + endif() + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4001) target_sources(${PROJECT_NAME} PRIVATE @@ -165,6 +173,13 @@ if(CMAKE_UFE_V3_FEATURES_AVAILABLE) endif() if(CMAKE_UFE_V4_FEATURES_AVAILABLE) + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4007) + list(APPEND HEADERS + UsdLight.h + UsdLightHandler.h + ) + endif() + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4001) list(APPEND HEADERS UsdShaderNodeDef.h diff --git a/lib/mayaUsd/ufe/Global.cpp b/lib/mayaUsd/ufe/Global.cpp index c933d31128..a485a005d7 100644 --- a/lib/mayaUsd/ufe/Global.cpp +++ b/lib/mayaUsd/ufe/Global.cpp @@ -44,6 +44,9 @@ #include #endif #ifdef UFE_V4_FEATURES_AVAILABLE +#if (UFE_PREVIEW_VERSION_NUM >= 4007) +#include +#endif #if (UFE_PREVIEW_VERSION_NUM >= 4001) #include #endif @@ -158,8 +161,10 @@ MStatus initialize() handlers.uiInfoHandler = UsdUIInfoHandler::create(); handlers.cameraHandler = UsdCameraHandler::create(); #ifdef UFE_V4_FEATURES_AVAILABLE +#if (UFE_PREVIEW_VERSION_NUM >= 4007) + handlers.lightHandler = UsdLightHandler::create(); +#endif #if (UFE_PREVIEW_VERSION_NUM >= 4001) - handlers.nodeDefHandler = UsdShaderNodeDefHandler::create(); #endif #endif diff --git a/lib/mayaUsd/ufe/UsdLight.cpp b/lib/mayaUsd/ufe/UsdLight.cpp new file mode 100644 index 0000000000..f314903629 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdLight.cpp @@ -0,0 +1,480 @@ +// +// Copyright 2022 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "UsdLight.h" + +#include "private/Utils.h" + +#include +#include +#include +#include + +#include +#if PXR_VERSION < 2111 +#include +#else +#include +#endif +#include +#include +#include +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +template +class SetValueUndoableCommandImpl : public Ufe::SetValueUndoableCommand +{ +public: + using ValueTypeNonRef = typename std::remove_reference::type; + using ValueTypeOut = typename std::remove_const::type; + + typedef std::function GetterFunc; + typedef std::function SetterFunc; + + SetValueUndoableCommandImpl(const Ufe::Path& path, const SetterFunc& sf) + : Ufe::SetValueUndoableCommand(path) + , _setterFunc(sf) + { + } + + ~SetValueUndoableCommandImpl() override { } + + bool set(ValueTypeIn v) override + { + _value = v; + return true; + } + + void execute() override + { + UsdUndoBlock undoBlock(&_undoableItem); + if (auto pItem + = std::dynamic_pointer_cast(Ufe::BaseUndoableCommand::sceneItem())) { + _setterFunc(pItem->prim(), _value); + } + } + + void undo() override { _undoableItem.undo(); } + void redo() override { _undoableItem.redo(); } + +private: + SetterFunc _setterFunc; + ValueTypeOut _value; + UsdUndoableItem _undoableItem; +}; + +UsdLight::UsdLight() + : Light() +{ +} + +UsdLight::UsdLight(const UsdSceneItem::Ptr& item) + : Light() + , fItem(item) +{ +} + +UsdLight::Ptr UsdLight::create(const UsdSceneItem::Ptr& item) +{ + return std::make_shared(item); +} + +#if PXR_VERSION < 2111 +using UsdLuxLightCommon = UsdLuxLight; +#else +using UsdLuxLightCommon = UsdLuxLightAPI; +#endif + +//------------------------------------------------------------------------------ +// Ufe::Light overrides +//------------------------------------------------------------------------------ + +const Ufe::Path& UsdLight::path() const { return fItem->path(); } + +Ufe::SceneItem::Ptr UsdLight::sceneItem() const { return fItem; } + +Ufe::Light::Type UsdLight::type() const +{ + const UsdPrim usdPrim = prim(); + + if (usdPrim.IsA()) { + return Ufe::Light::Directional; + } else if (usdPrim.IsA()) { + return Ufe::Light::Area; + } else if (usdPrim.IsA()) { + const UsdLuxShapingAPI shapingAPI(usdPrim); + return shapingAPI.GetShapingConeAngleAttr().IsValid() ? Ufe::Light::Spot + : Ufe::Light::Point; + } + + return Ufe::Light::Invalid; +} + +float getLightIntensity(const UsdPrim& prim) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetIntensityAttr(); + + float val = 0.f; + lightAttribute.Get(&val); + return val; +} + +void setLightIntensity(const UsdPrim& prim, float attrVal) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetIntensityAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::IntensityUndoableCommand::Ptr UsdLight::intensityCmd(float li) +{ + auto pCmd = std::make_shared>(path(), setLightIntensity); + + pCmd->set(li); + return pCmd; +} + +void UsdLight::intensity(float li) { setLightIntensity(prim(), li); } + +float UsdLight::intensity() const { return getLightIntensity(prim()); } + +Ufe::Color3f getLightColor(const UsdPrim& prim) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetColorAttr(); + + GfVec3f val(0.f, 0.f, 0.f); + lightAttribute.Get(&val); + return Ufe::Color3f(val[0], val[1], val[2]); +} + +void setLightColor(const UsdPrim& prim, const Ufe::Color3f& attrVal) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetColorAttr(); + + lightAttribute.Set(GfVec3f(attrVal.r(), attrVal.g(), attrVal.b())); +} + +Ufe::Light::ColorUndoableCommand::Ptr UsdLight::colorCmd(float r, float g, float b) +{ + auto pCmd + = std::make_shared>(path(), setLightColor); + + pCmd->set(Ufe::Color3f(r, g, b)); + return pCmd; +} + +void UsdLight::color(float r, float g, float b) { setLightColor(prim(), Ufe::Color3f(r, g, b)); } + +Ufe::Color3f UsdLight::color() const { return getLightColor(prim()); } + +bool getLightShadowEnable(const UsdPrim& prim) +{ + const UsdLuxShadowAPI shadowAPI(prim); + const pxr::UsdAttribute lightAttribute = shadowAPI.GetShadowEnableAttr(); + + bool val = false; + lightAttribute.Get(&val); + return val; +} + +void setLightShadowEnable(const UsdPrim& prim, bool attrVal) +{ + const UsdLuxShadowAPI shadowAPI(prim); + const pxr::UsdAttribute lightAttribute = shadowAPI.GetShadowEnableAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::ShadowEnableUndoableCommand::Ptr UsdLight::shadowEnableCmd(bool se) +{ + auto pCmd = std::make_shared>(path(), setLightShadowEnable); + + pCmd->set(se); + return pCmd; +} + +void UsdLight::shadowEnable(bool se) { setLightShadowEnable(prim(), se); } + +bool UsdLight::shadowEnable() const { return getLightShadowEnable(prim()); } + +Ufe::Color3f getLightShadowColor(const UsdPrim& prim) +{ + const UsdLuxShadowAPI shadowAPI(prim); + const pxr::UsdAttribute lightAttribute = shadowAPI.GetShadowColorAttr(); + + GfVec3f val(0.f, 0.f, 0.f); + lightAttribute.Get(&val); + return Ufe::Color3f(val[0], val[1], val[2]); +} + +void setLightShadowColor(const UsdPrim& prim, const Ufe::Color3f& attrVal) +{ + const UsdLuxShadowAPI shadowAPI(prim); + const pxr::UsdAttribute lightAttribute = shadowAPI.GetShadowColorAttr(); + + lightAttribute.Set(GfVec3f(attrVal.r(), attrVal.g(), attrVal.b())); +} + +Ufe::Light::ShadowColorUndoableCommand::Ptr UsdLight::shadowColorCmd(float r, float g, float b) +{ + auto pCmd = std::make_shared>( + path(), setLightShadowColor); + + pCmd->set(Ufe::Color3f(r, g, b)); + return pCmd; +} + +void UsdLight::shadowColor(float r, float g, float b) +{ + setLightShadowColor(prim(), Ufe::Color3f(r, g, b)); +} + +Ufe::Color3f UsdLight::shadowColor() const { return getLightShadowColor(prim()); } + +float getLightDiffuse(const UsdPrim& prim) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetDiffuseAttr(); + + float val = 0.f; + lightAttribute.Get(&val); + return val; +} + +void setLightDiffuse(const UsdPrim& prim, float attrVal) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetDiffuseAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::DiffuseUndoableCommand::Ptr UsdLight::diffuseCmd(float ld) +{ + auto pCmd = std::make_shared>(path(), setLightDiffuse); + + pCmd->set(ld); + return pCmd; +} + +void UsdLight::diffuse(float ld) { setLightDiffuse(prim(), ld); } + +float UsdLight::diffuse() const { return getLightDiffuse(prim()); } + +float getLightSpecular(const UsdPrim& prim) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetSpecularAttr(); + + float val = 0.f; + lightAttribute.Get(&val); + return val; +} + +void setLightSpecular(const UsdPrim& prim, float attrVal) +{ + const UsdLuxLightCommon lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetSpecularAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::SpecularUndoableCommand::Ptr UsdLight::specularCmd(float ls) +{ + auto pCmd = std::make_shared>(path(), setLightSpecular); + + pCmd->set(ls); + return pCmd; +} + +void UsdLight::specular(float ls) { setLightSpecular(prim(), ls); } + +float UsdLight::specular() const { return getLightSpecular(prim()); } + +float getLightAngle(const UsdPrim& prim) +{ + const UsdLuxDistantLight lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetAngleAttr(); + + float val = 0.f; + lightAttribute.Get(&val); + return val; +} + +void setLightAngle(const UsdPrim& prim, float attrVal) +{ + const UsdLuxDistantLight lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetAngleAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::AngleUndoableCommand::Ptr UsdDirectionalInterface::angleCmd(float la) +{ + auto pCmd = std::make_shared>(fItem->path(), setLightAngle); + + pCmd->set(la); + return pCmd; +} + +void UsdDirectionalInterface::angle(float la) { setLightAngle(fItem->prim(), la); } + +float UsdDirectionalInterface::angle() const { return getLightAngle(fItem->prim()); } + +Ufe::Light::SphereProps getLightSphereProps(const UsdPrim& prim) +{ + const UsdLuxSphereLight lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetRadiusAttr(); + + Ufe::Light::SphereProps sp; + lightAttribute.Get(&sp.radius); + sp.asPoint = (sp.radius == 0.f); + return sp; +} + +void setLightSphereProps(const UsdPrim& prim, const Ufe::Light::SphereProps& attrVal) +{ + const UsdLuxSphereLight lightSchema(prim); + const pxr::UsdAttribute lightAttribute = lightSchema.GetRadiusAttr(); + + lightAttribute.Set(attrVal.radius); +} + +Ufe::Light::SpherePropsUndoableCommand::Ptr +UsdSphereInterface::spherePropsCmd(float radius, bool asPoint) +{ + auto pCmd = std::make_shared>( + fItem->path(), setLightSphereProps); + + pCmd->set(Ufe::Light::SphereProps { radius, asPoint }); + return pCmd; +} + +void UsdSphereInterface::sphereProps(float radius, bool asPoint) +{ + setLightSphereProps(fItem->prim(), Ufe::Light::SphereProps { radius, asPoint }); +} + +Ufe::Light::SphereProps UsdSphereInterface::sphereProps() const +{ + return getLightSphereProps(fItem->prim()); +} + +Ufe::Light::ConeProps getLightConeProps(const UsdPrim& prim) +{ + const UsdLuxShapingAPI lightSchema(prim); + const pxr::UsdAttribute focusAttribute = lightSchema.GetShapingFocusAttr(); + const pxr::UsdAttribute coneAngleAttribute = lightSchema.GetShapingConeAngleAttr(); + const pxr::UsdAttribute coneSoftnessAttribute = lightSchema.GetShapingConeSoftnessAttr(); + + Ufe::Light::ConeProps cp; + focusAttribute.Get(&cp.focus); + coneAngleAttribute.Get(&cp.angle); + coneSoftnessAttribute.Get(&cp.softness); + return cp; +} + +void setLightConeProps(const UsdPrim& prim, const Ufe::Light::ConeProps& attrVal) +{ + const UsdLuxShapingAPI lightSchema(prim); + const pxr::UsdAttribute focusAttribute = lightSchema.GetShapingFocusAttr(); + const pxr::UsdAttribute coneAngleAttribute = lightSchema.GetShapingConeAngleAttr(); + const pxr::UsdAttribute coneSoftnessAttribute = lightSchema.GetShapingConeSoftnessAttr(); + + focusAttribute.Set(attrVal.focus); + coneAngleAttribute.Set(attrVal.angle); + coneSoftnessAttribute.Set(attrVal.softness); +} + +Ufe::Light::ConePropsUndoableCommand::Ptr +UsdConeInterface::conePropsCmd(float focus, float angle, float softness) +{ + auto pCmd = std::make_shared>( + fItem->path(), setLightConeProps); + + pCmd->set(Ufe::Light::ConeProps { focus, angle, softness }); + return pCmd; +} + +void UsdConeInterface::coneProps(float focus, float angle, float softness) +{ + setLightConeProps(fItem->prim(), Ufe::Light::ConeProps { focus, angle, softness }); +} + +Ufe::Light::ConeProps UsdConeInterface::coneProps() const +{ + return getLightConeProps(fItem->prim()); +} + +bool getLightNormalize(const UsdPrim& prim) +{ + const UsdLuxRectLight rectLight(prim); + const pxr::UsdAttribute lightAttribute = rectLight.GetNormalizeAttr(); + + bool val = false; + lightAttribute.Get(&val); + return val; +} + +void setLightNormalize(const UsdPrim& prim, bool attrVal) +{ + const UsdLuxRectLight rectLight(prim); + const pxr::UsdAttribute lightAttribute = rectLight.GetNormalizeAttr(); + + lightAttribute.Set(attrVal); +} + +Ufe::Light::NormalizeUndoableCommand::Ptr UsdAreaInterface::normalizeCmd(bool nl) +{ + auto pCmd + = std::make_shared>(fItem->path(), setLightNormalize); + + pCmd->set(nl); + return pCmd; +} + +void UsdAreaInterface::normalize(bool ln) { setLightNormalize(fItem->prim(), ln); } + +bool UsdAreaInterface::normalize() const { return getLightNormalize(fItem->prim()); } + +std::shared_ptr UsdLight::directionalInterfaceImpl() +{ + return std::make_shared(fItem); +} + +std::shared_ptr UsdLight::sphereInterfaceImpl() +{ + return std::make_shared(fItem); +} + +std::shared_ptr UsdLight::coneInterfaceImpl() +{ + return std::make_shared(fItem); +} + +std::shared_ptr UsdLight::areaInterfaceImpl() +{ + return std::make_shared(fItem); +} + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdLight.h b/lib/mayaUsd/ufe/UsdLight.h new file mode 100644 index 0000000000..71aead9497 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdLight.h @@ -0,0 +1,161 @@ +// +// Copyright 2022 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include +#include + +#include +#include + +#include +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to control lights through USD. +class MAYAUSD_CORE_PUBLIC UsdLight : public Ufe::Light +{ +public: + typedef std::shared_ptr Ptr; + + UsdLight(); + UsdLight(const UsdSceneItem::Ptr& item); + ~UsdLight() override = default; + + // Delete the copy/move constructors assignment operators. + UsdLight(const UsdLight&) = delete; + UsdLight& operator=(const UsdLight&) = delete; + UsdLight(UsdLight&&) = delete; + UsdLight& operator=(UsdLight&&) = delete; + + //! Create a UsdLight. + static UsdLight::Ptr create(const UsdSceneItem::Ptr& item); + + inline PXR_NS::UsdPrim prim() const + { + PXR_NAMESPACE_USING_DIRECTIVE + TF_AXIOM(fItem != nullptr); + return fItem->prim(); + } + + // Ufe::Light overrides + const Ufe::Path& path() const override; + Ufe::SceneItem::Ptr sceneItem() const override; + Type type() const override; + + IntensityUndoableCommand::Ptr intensityCmd(float li) override; + void intensity(float li) override; + float intensity() const override; + + ColorUndoableCommand::Ptr colorCmd(float r, float g, float b) override; + void color(float r, float g, float b) override; + Ufe::Color3f color() const override; + + ShadowEnableUndoableCommand::Ptr shadowEnableCmd(bool se) override; + void shadowEnable(bool se) override; + bool shadowEnable() const override; + + ShadowColorUndoableCommand::Ptr shadowColorCmd(float r, float g, float b) override; + void shadowColor(float r, float g, float b) override; + Ufe::Color3f shadowColor() const override; + + DiffuseUndoableCommand::Ptr diffuseCmd(float ld) override; + void diffuse(float ld) override; + float diffuse() const override; + + SpecularUndoableCommand::Ptr specularCmd(float ls) override; + void specular(float ls) override; + float specular() const override; + +protected: + std::shared_ptr directionalInterfaceImpl(); + std::shared_ptr sphereInterfaceImpl(); + std::shared_ptr coneInterfaceImpl(); + std::shared_ptr areaInterfaceImpl(); + +private: + UsdSceneItem::Ptr fItem; +}; // UsdLight + +class UsdDirectionalInterface : public Ufe::Light::DirectionalInterface +{ +public: + UsdDirectionalInterface(const UsdSceneItem::Ptr& item) + : fItem(item) + { + } + + Ufe::Light::AngleUndoableCommand::Ptr angleCmd(float la) override; + void angle(float la) override; + float angle() const override; + +private: + UsdSceneItem::Ptr fItem; +}; + +class UsdSphereInterface : public Ufe::Light::SphereInterface +{ +public: + UsdSphereInterface(const UsdSceneItem::Ptr& item) + : fItem(item) + { + } + + Ufe::Light::SpherePropsUndoableCommand::Ptr spherePropsCmd(float radius, bool asPoint) override; + void sphereProps(float radius, bool asPoint) override; + Ufe::Light::SphereProps sphereProps() const override; + +private: + UsdSceneItem::Ptr fItem; +}; + +class UsdConeInterface : public Ufe::Light::ConeInterface +{ +public: + UsdConeInterface(const UsdSceneItem::Ptr& item) + : fItem(item) + { + } + + Ufe::Light::ConePropsUndoableCommand::Ptr + conePropsCmd(float focus, float angle, float softness) override; + void coneProps(float focus, float angle, float softness) override; + Ufe::Light::ConeProps coneProps() const override; + +private: + UsdSceneItem::Ptr fItem; +}; + +class UsdAreaInterface : public Ufe::Light::AreaInterface +{ +public: + UsdAreaInterface(const UsdSceneItem::Ptr& item) + : fItem(item) + { + } + + Ufe::Light::NormalizeUndoableCommand::Ptr normalizeCmd(bool nl) override; + void normalize(bool ln) override; + bool normalize() const override; + +private: + UsdSceneItem::Ptr fItem; +}; + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdLightHandler.cpp b/lib/mayaUsd/ufe/UsdLightHandler.cpp new file mode 100644 index 0000000000..067e46da80 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdLightHandler.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2022 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "UsdLightHandler.h" + +#include "UsdLight.h" + +#if PXR_VERSION < 2111 +#include +#else +#include +#endif + +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +#if PXR_VERSION < 2111 +using UsdLuxLightCommon = pxr::UsdLuxLight; +#else +using UsdLuxLightCommon = pxr::UsdLuxLightAPI; +#endif + +UsdLightHandler::UsdLightHandler() + : Ufe::LightHandler() +{ +} + +UsdLightHandler::~UsdLightHandler() { } + +UsdLightHandler::Ptr UsdLightHandler::create() { return std::make_shared(); } + +Ufe::Light::Ptr UsdLightHandler::light(const Ufe::SceneItem::Ptr& item) const +{ + UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast(item); +#if !defined(NDEBUG) + assert(usdItem); +#endif + + // Test if this item is a light. If not, then we cannot create a light + // interface for it, which is a valid case (such as for a mesh node type). + UsdLuxLightCommon lightSchema(usdItem->prim()); + if (!lightSchema) + return nullptr; + + return UsdLight::create(usdItem); +} + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdLightHandler.h b/lib/mayaUsd/ufe/UsdLightHandler.h new file mode 100644 index 0000000000..0ade656bcd --- /dev/null +++ b/lib/mayaUsd/ufe/UsdLightHandler.h @@ -0,0 +1,49 @@ +// +// Copyright 2022 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include + +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to create a UsdLightHandler interface object. +class MAYAUSD_CORE_PUBLIC UsdLightHandler : public Ufe::LightHandler +{ +public: + typedef std::shared_ptr Ptr; + + UsdLightHandler(); + ~UsdLightHandler(); + + // Delete the copy/move constructors assignment operators. + UsdLightHandler(const UsdLightHandler&) = delete; + UsdLightHandler& operator=(const UsdLightHandler&) = delete; + UsdLightHandler(UsdLightHandler&&) = delete; + UsdLightHandler& operator=(UsdLightHandler&&) = delete; + + //! Create a UsdLightHandler. + static UsdLightHandler::Ptr create(); + + // Ufe::LightHandler overrides + Ufe::Light::Ptr light(const Ufe::SceneItem::Ptr& item) const override; + +}; // UsdLightHandler + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/test/lib/ufe/CMakeLists.txt b/test/lib/ufe/CMakeLists.txt index 6d331aa76c..01d5c67f4d 100644 --- a/test/lib/ufe/CMakeLists.txt +++ b/test/lib/ufe/CMakeLists.txt @@ -48,6 +48,12 @@ if(CMAKE_UFE_V3_FEATURES_AVAILABLE) endif() if(CMAKE_UFE_V4_FEATURES_AVAILABLE) + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4007) + list(APPEND TEST_SCRIPT_FILES + testLight.py + ) + endif() + if(CMAKE_WANT_MATERIALX_BUILD) list(APPEND TEST_SCRIPT_FILES testShaderNodeDef.py diff --git a/test/lib/ufe/testLight.py b/test/lib/ufe/testLight.py new file mode 100644 index 0000000000..d7be4bc5bc --- /dev/null +++ b/test/lib/ufe/testLight.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python + +# +# Copyright 2022 Autodesk +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import fixturesUtils +import mayaUtils +import testUtils +import ufeUtils +import usdUtils + +from pxr import Gf + +from maya import cmds +from maya import standalone +from maya.api import OpenMaya as om + +import ufe + +from functools import partial +import unittest + +class LightTestCase(unittest.TestCase): + '''Verify the Light UFE translate interface, for multiple runtimes. + + UFE Feature : Light + Maya Feature : light + Action : set & read light parameters + Applied On Selection : No + Undo/Redo Test : No + Expect Results To Test : + - Setting a value through Ufe correctly updates USD + - Reading a value through Ufe gets the correct value + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + fixturesUtils.readOnlySetUpClass(__file__, loadPlugin=False) + + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + @classmethod + def tearDownClass(cls): + standalone.uninitialize() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # value from UsdGeomLinearUnits + self.inchesToCm = 2.54 + self.mmToCm = 0.1 + + def _StartTest(self, testName): + cmds.file(force=True, new=True) + self._testName = testName + testFile = testUtils.getTestScene("light", self._testName + ".usda") + mayaUtils.createProxyFromFile(testFile) + globalSelection = ufe.GlobalSelection.get() + globalSelection.clear() + + def _TestSpotLight(self, ufeLight, usdLight): + # Trust that the USD API works correctly, validate that UFE gives us + # the same answers + self.assertEqual(ufeLight.type(), ufe.Light.Spot) + self._TestIntensity(ufeLight, usdLight) + self._TestDiffuse(ufeLight, usdLight) + self._TestSpecular(ufeLight, usdLight) + self._TestShadowEnable(ufeLight, usdLight) + self._TestColor(ufeLight, usdLight) + self._TestShadowColor(ufeLight, usdLight) + self._TestSphereProps(ufeLight, usdLight) + self._TestConeProps(ufeLight, usdLight) + self.assertEqual(None, ufeLight.directionalInterface()) + self.assertEqual(None, ufeLight.areaInterface()) + + def _TestPointLight(self, ufeLight, usdLight): + # Trust that the USD API works correctly, validate that UFE gives us + # the same answers + self.assertEqual(ufeLight.type(), ufe.Light.Point) + self._TestIntensity(ufeLight, usdLight) + self._TestDiffuse(ufeLight, usdLight) + self._TestSpecular(ufeLight, usdLight) + self._TestShadowEnable(ufeLight, usdLight) + self._TestColor(ufeLight, usdLight) + self._TestShadowColor(ufeLight, usdLight) + self._TestSphereProps(ufeLight, usdLight) + self.assertEqual(None, ufeLight.coneInterface()) + self.assertEqual(None, ufeLight.directionalInterface()) + self.assertEqual(None, ufeLight.areaInterface()) + + def _TestDirectionalLight(self, ufeLight, usdLight): + # Trust that the USD API works correctly, validate that UFE gives us + # the same answers + self.assertEqual(ufeLight.type(), ufe.Light.Directional) + self._TestIntensity(ufeLight, usdLight) + self._TestDiffuse(ufeLight, usdLight) + self._TestSpecular(ufeLight, usdLight) + self._TestShadowEnable(ufeLight, usdLight) + self._TestColor(ufeLight, usdLight) + self._TestShadowColor(ufeLight, usdLight) + self._TestDirectionalProps(ufeLight, usdLight) + self.assertEqual(None, ufeLight.coneInterface()) + self.assertEqual(None, ufeLight.sphereInterface()) + self.assertEqual(None, ufeLight.areaInterface()) + + def _TestAreaLight(self, ufeLight, usdLight): + # Trust that the USD API works correctly, validate that UFE gives us + # the same answers + self.assertEqual(ufeLight.type(), ufe.Light.Area) + self._TestIntensity(ufeLight, usdLight) + self._TestDiffuse(ufeLight, usdLight) + self._TestSpecular(ufeLight, usdLight) + self._TestShadowEnable(ufeLight, usdLight) + self._TestColor(ufeLight, usdLight) + self._TestShadowColor(ufeLight, usdLight) + self._TestAreaProps(ufeLight, usdLight) + self.assertEqual(None, ufeLight.coneInterface()) + self.assertEqual(None, ufeLight.sphereInterface()) + self.assertEqual(None, ufeLight.directionalInterface()) + + def _TestIntensity(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:intensity') + self.assertAlmostEqual(usdAttr.Get(), ufeLight.intensity()) + + usdAttr.Set(0.5) + self.assertAlmostEqual(0.5, ufeLight.intensity()) + + ufeLight.intensity(100) + self.assertAlmostEqual(usdAttr.Get(), 100) + + def _TestDiffuse(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:diffuse') + self.assertAlmostEqual(usdAttr.Get(), ufeLight.diffuse()) + + usdAttr.Set(0.5) + self.assertAlmostEqual(0.5, ufeLight.diffuse()) + + ufeLight.diffuse(0.9) + self.assertAlmostEqual(usdAttr.Get(), 0.9) + + def _TestSpecular(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:specular') + self.assertAlmostEqual(usdAttr.Get(), ufeLight.specular()) + + usdAttr.Set(0.5) + self.assertAlmostEqual(0.5, ufeLight.specular()) + + ufeLight.specular(0.9) + self.assertAlmostEqual(usdAttr.Get(), 0.9) + + def _TestShadowEnable(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:shadow:enable') + self.assertEqual(usdAttr.Get(), ufeLight.shadowEnable()) + + usdAttr.Set(False) + self.assertEqual(False, ufeLight.shadowEnable()) + + ufeLight.shadowEnable(True) + self.assertAlmostEqual(usdAttr.Get(), True) + + def _TestColor(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:color') + self.assertAlmostEqual(usdAttr.Get()[0], ufeLight.color().r()) + self.assertAlmostEqual(usdAttr.Get()[1], ufeLight.color().g()) + self.assertAlmostEqual(usdAttr.Get()[2], ufeLight.color().b()) + + def _TestShadowColor(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:shadow:color') + self.assertAlmostEqual(usdAttr.Get()[0], ufeLight.shadowColor().r()) + self.assertAlmostEqual(usdAttr.Get()[1], ufeLight.shadowColor().g()) + self.assertAlmostEqual(usdAttr.Get()[2], ufeLight.shadowColor().b()) + + def _TestSphereProps(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:radius') + self.assertAlmostEqual(usdAttr.Get(), ufeLight.sphereInterface().sphereProps().radius) + self.assertEqual(usdAttr.Get() == 0, ufeLight.sphereInterface().sphereProps().asPoint) + + def _TestConeProps(self, ufeLight, usdLight): + usdAttrFocus = usdLight.GetAttribute('inputs:shaping:focus') + usdAttrAngle = usdLight.GetAttribute('inputs:shaping:cone:angle') + usdAttrSoftness = usdLight.GetAttribute('inputs:shaping:cone:softness') + self.assertAlmostEqual(usdAttrFocus.Get(), ufeLight.coneInterface().coneProps().focus) + self.assertAlmostEqual(usdAttrAngle.Get(), ufeLight.coneInterface().coneProps().angle) + self.assertAlmostEqual(usdAttrSoftness.Get(), ufeLight.coneInterface().coneProps().softness) + + def _TestDirectionalProps(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:angle') + self.assertAlmostEqual(usdAttr.Get(), ufeLight.directionalInterface().angle()) + + def _TestAreaProps(self, ufeLight, usdLight): + usdAttr = usdLight.GetAttribute('inputs:normalize') + self.assertEqual(usdAttr.Get(), ufeLight.areaInterface().normalize()) + + def testUsdLight(self): + self._StartTest('SimpleLight') + mayaPathSegment = mayaUtils.createUfePathSegment('|stage|stageShape') + + # test spot light + spotlightUsdPathSegment = usdUtils.createUfePathSegment('/lights/spotLight') + spotlightPath = ufe.Path([mayaPathSegment, spotlightUsdPathSegment]) + spotlightItem = ufe.Hierarchy.createItem(spotlightPath) + + ufeSpotLight = ufe.Light.light(spotlightItem) + usdSpotLight = usdUtils.getPrimFromSceneItem(spotlightItem) + self._TestSpotLight(ufeSpotLight, usdSpotLight) + + # test point light + pointlightUsdPathSegment = usdUtils.createUfePathSegment('/lights/pointLight') + pointlightPath = ufe.Path([mayaPathSegment, pointlightUsdPathSegment]) + pointlightItem = ufe.Hierarchy.createItem(pointlightPath) + + ufePointLight = ufe.Light.light(pointlightItem) + usdPointLight = usdUtils.getPrimFromSceneItem(pointlightItem) + self._TestPointLight(ufePointLight, usdPointLight) + + # test directional light + directionallightUsdPathSegment = usdUtils.createUfePathSegment('/lights/directionalLight') + directionallightPath = ufe.Path([mayaPathSegment, directionallightUsdPathSegment]) + directionallightItem = ufe.Hierarchy.createItem(directionallightPath) + + ufeDirectionalLight = ufe.Light.light(directionallightItem) + usdDirectionalLight = usdUtils.getPrimFromSceneItem(directionallightItem) + self._TestDirectionalLight(ufeDirectionalLight, usdDirectionalLight) + + # test area light + arealightUsdPathSegment = usdUtils.createUfePathSegment('/lights/areaLight') + arealightPath = ufe.Path([mayaPathSegment, arealightUsdPathSegment]) + arealightItem = ufe.Hierarchy.createItem(arealightPath) + + ufeAreaLight = ufe.Light.light(arealightItem) + usdAreaLight = usdUtils.getPrimFromSceneItem(arealightItem) + self._TestAreaLight(ufeAreaLight, usdAreaLight) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/test/testSamples/light/SimpleLight.usda b/test/testSamples/light/SimpleLight.usda new file mode 100644 index 0000000000..35460d6ea0 --- /dev/null +++ b/test/testSamples/light/SimpleLight.usda @@ -0,0 +1,52 @@ +#usda 1.0 +( + metersPerUnit = 0.01 + upAxis = "Y" +) + +def Xform "lights" +{ + def SphereLight "spotLight" + { + double3 xformOp:translate = (0, 1, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + + float inputs:intensity = 20000 + bool inputs:shadow:enable = true + color3f inputs:shadow:color = (1, 0, 0) + + float inputs:shaping:focus = 0.5 + float inputs:shaping:cone:angle = 50 + float inputs:shaping:cone:softness = 0.1 + } + + def SphereLight "pointLight" + { + float inputs:intensity = 200 + bool inputs:shadow:enable = false + color3f inputs:shadow:color = (1, 1, 0) + } + + def DistantLight "directionalLight" + { + float inputs:angle = 0.2 + + color3f inputs:color = (0, 0, 1) + + float inputs:intensity = 20000 + bool inputs:shadow:enable = true + color3f inputs:shadow:color = (1, 0, 0) + } + + def RectLight "areaLight" + { + bool inputs:normalize = true + + color3f inputs:color = (0, 1, 0) + + float inputs:intensity = 20000 + bool inputs:shadow:enable = true + color3f inputs:shadow:color = (1, 0, 0) + } +} +