Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HYDRA-794 : Support maya lighting modes for USD and dome lights #167

Merged
merged 7 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/flowViewport/sceneIndex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target_sources(${TARGET_NAME}
fvpReprSelectorSceneIndex.cpp
fvpBlockPrimRemovalPropagationSceneIndex.cpp
fvpDefaultMaterialSceneIndex.cpp
fvpLightsManagementSceneIndex.cpp
)

set(HEADERS
Expand All @@ -35,6 +36,7 @@ set(HEADERS
fvpReprSelectorSceneIndex.h
fvpBlockPrimRemovalPropagationSceneIndex.h
fvpDefaultMaterialSceneIndex.h
fvpLightsManagementSceneIndex.h
)

# -----------------------------------------------------------------------------
Expand Down
149 changes: 149 additions & 0 deletions lib/flowViewport/sceneIndex/fvpLightsManagementSceneIndex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//
// Copyright 2024 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.
//

//Local headers
#include "fvpLightsManagementSceneIndex.h"

//USD/Hydra headers
#include <pxr/imaging/hd/tokens.h>
#include <pxr/imaging/hd/retainedDataSource.h>
#include <pxr/imaging/hd/overlayContainerDataSource.h>
#include <pxr/imaging/hd/containerDataSourceEditor.h>
#include <pxr/imaging/hd/sceneIndexPrimView.h>
#include <pxr/imaging/hd/light.h>
#include <pxr/imaging/hd/lightSchema.h>
#include <pxr/imaging/glf/simpleLight.h>

//ufe
#include <ufe/globalSelection.h>
#include <ufe/observableSelection.h>


PXR_NAMESPACE_USING_DIRECTIVE

namespace {

void _DisableLight(HdSceneIndexPrim& prim)
{
HdContainerDataSourceEditor editor(prim.dataSource);
//We don't set the intensity to 0 as for domelights this makes the geometry disappear
for (const auto& t : { HdLightTokens->ambient, HdLightTokens->diffuse, HdLightTokens->specular }) {
editor.Set(
HdLightSchema::GetDefaultLocator().Append(t),
HdRetainedTypedSampledDataSource<float>::New(0.0f));
}

prim.dataSource = editor.Finish();
}

} // end of anonymous namespace

/// This is a filtering scene index that manages lights primitives

namespace FVP_NS_DEF {

LightsManagementSceneIndex::LightsManagementSceneIndex(const HdSceneIndexBaseRefPtr& inputSceneIndex, const PathInterface& pathInterface, const SdfPath& defaultLightPath)
: ParentClass(inputSceneIndex),
InputSceneIndexUtils(inputSceneIndex)
,_defaultLightPath(defaultLightPath)
, _pathInterface(pathInterface)
{
}

void LightsManagementSceneIndex::SetLightingMode(LightingMode lightingMode)
{
if (_lightingMode == lightingMode){
return;
}

_lightingMode = lightingMode;
_DirtyAllLightsPrims();
}

void LightsManagementSceneIndex::_DirtyAllLightsPrims()
{
HdSceneIndexObserver::DirtiedPrimEntries entries;
for (const SdfPath& path : HdSceneIndexPrimView(GetInputSceneIndex())) {
auto primType = GetInputSceneIndex()->GetPrim(path).primType;
if (HdPrimTypeIsLight(primType)) {
entries.push_back({ path, HdLightSchema::GetDefaultLocator() });
}
}
_SendPrimsDirtied(entries);
}

bool LightsManagementSceneIndex::_IsDefaultLight(const SdfPath& primPath)const
{
return primPath == _defaultLightPath;
}

HdSceneIndexPrim LightsManagementSceneIndex::GetPrim(const SdfPath& primPath) const
{
auto prim = GetInputSceneIndex()->GetPrim(primPath);
auto primType = prim.primType;
if (! HdPrimTypeIsLight(primType)) {
return prim;//return any non light primitive
}

//This is a light
switch (_lightingMode) {
case LightingMode::kNoLighting: {
_DisableLight(prim);
return prim;
} break;
default:
case LightingMode::kSceneLighting: {
return prim;
} break;
case LightingMode::kDefaultLighting: {
if (! _IsDefaultLight(primPath)){
_DisableLight(prim);
}
return prim;
} break;
case LightingMode::kSelectedLightsOnly: {
const Ufe::Selection& ufeSelection = *Ufe::GlobalSelection::get();
if (ufeSelection.empty()) {
// Nothing is selected
_DisableLight(prim);
return prim;
}

//Convert ufe selection to SdfPath
SdfPathVector selectedLightsSdfPath;
for (const auto& snItem : ufeSelection) {
auto primSelections = _pathInterface.UfePathToPrimSelections(snItem->path());
for (const auto& primSelection : primSelections) {
selectedLightsSdfPath.push_back(primSelection.primPath);
}
}
const bool isSelected = selectedLightsSdfPath.end()
!= std::find(selectedLightsSdfPath.begin(),
selectedLightsSdfPath.end(),
primPath);

if (! isSelected) {
_DisableLight(prim);
}

return prim;
} break;
}

return prim;
}

}//end of namespace FVP_NS_DEF
103 changes: 103 additions & 0 deletions lib/flowViewport/sceneIndex/fvpLightsManagementSceneIndex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// Copyright 2024 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.
//
#ifndef FLOW_VIEWPORT_SCENE_INDEX_FLOW_VIEWPORT_LIGHTS_MANAGEMENT_SCENE_INDEX_H
#define FLOW_VIEWPORT_SCENE_INDEX_FLOW_VIEWPORT_LIGHTS_MANAGEMENT_SCENE_INDEX_H

//Local headers
#include "flowViewport/api.h"
#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h"
#include "flowViewport/sceneIndex/fvpPathInterface.h"

//Hydra headers
#include <pxr/base/tf/declarePtrs.h>
#include <pxr/imaging/hd/filteringSceneIndex.h>

namespace FVP_NS_DEF {

class LightsManagementSceneIndex;
typedef PXR_NS::TfRefPtr<LightsManagementSceneIndex> LightsManagementSceneIndexRefPtr;
typedef PXR_NS::TfRefPtr<const LightsManagementSceneIndex> LightsManagementSceneIndexConstRefPtr;

/// \class LightsManagementSceneIndex
///
/// This is a filtering scene index that manages lights primitives
///
class LightsManagementSceneIndex : public PXR_NS::HdSingleInputFilteringSceneIndexBase
, public Fvp::InputSceneIndexUtils<LightsManagementSceneIndex>
{
public:
using ParentClass = PXR_NS::HdSingleInputFilteringSceneIndexBase;
using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex;

FVP_API
static LightsManagementSceneIndexRefPtr New(const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex, const PathInterface& pathInterface, const PXR_NS::SdfPath& defaultLightPath){
return PXR_NS::TfCreateRefPtr(new LightsManagementSceneIndex(inputSceneIndex, pathInterface, defaultLightPath));
}

// From HdSceneIndexBase
FVP_API
PXR_NS::HdSceneIndexPrim GetPrim(const PXR_NS::SdfPath& primPath) const override;

FVP_API
PXR_NS::SdfPathVector GetChildPrimPaths(const PXR_NS::SdfPath& primPath) const override{
return GetInputSceneIndex()->GetChildPrimPaths(primPath);
}

FVP_API
~LightsManagementSceneIndex() override = default;

enum class LightingMode{
kNoLighting,
kSceneLighting,//All lights
kDefaultLighting,
kSelectedLightsOnly,
};

FVP_API
void SetLightingMode(LightingMode lightingMode);

FVP_API
LightingMode GetLightingMode()const {return _lightingMode;}

protected:

LightsManagementSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex, const PathInterface& pathInterface, const PXR_NS::SdfPath& defaultLightPath);

//From HdSingleInputFilteringSceneIndexBase
void _PrimsAdded(const PXR_NS::HdSceneIndexBase& sender, const PXR_NS::HdSceneIndexObserver::AddedPrimEntries& entries) override{
if (!_IsObserved())return;
_SendPrimsAdded(entries);
}
void _PrimsRemoved(const PXR_NS::HdSceneIndexBase& sender, const PXR_NS::HdSceneIndexObserver::RemovedPrimEntries& entries)override{
if (!_IsObserved())return;
_SendPrimsRemoved(entries);
}
void _PrimsDirtied(const PXR_NS::HdSceneIndexBase& sender, const PXR_NS::HdSceneIndexObserver::DirtiedPrimEntries& entries)override{
if (!_IsObserved())return;
_SendPrimsDirtied(entries);
}

void _DirtyAllLightsPrims();
bool _IsDefaultLight(const PXR_NS::SdfPath& primPath)const;

LightingMode _lightingMode = LightingMode::kSceneLighting;
PXR_NS::SdfPath _defaultLightPath;
const PathInterface& _pathInterface;
};

}//end of namespace FVP_NS_DEF

#endif //FLOW_VIEWPORT_SCENE_INDEX_FLOW_VIEWPORT_LIGHTS_MANAGEMENT_SCENE_INDEX_H
11 changes: 11 additions & 0 deletions lib/mayaHydra/hydraExtensions/mayaUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,15 @@ MObject GetShadingGroupFromShader(const MObject& shader)
return shadingGroup;
}

bool IsDagPathAnArnoldSkyDomeLight(const MDagPath& dagPath)
{
static const MString _aiSkyDomeLight("aiSkyDomeLight");

if (! dagPath.isValid()) return false;
auto shapeDagPath = dagPath;
shapeDagPath.extendToShape();
return _aiSkyDomeLight == MFnDependencyNode(shapeDagPath.node()).typeName();
}


} // namespace MAYAHYDRA_NS_DEF
9 changes: 9 additions & 0 deletions lib/mayaHydra/hydraExtensions/mayaUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ bool SetNodeAttribute(MObject node, std::string attrName, AttrType newValue)
*/
MObject GetShadingGroupFromShader(const MObject& shader);

/**
* @brief Get if this MDagPath is an Arnold sky dome light.
*
* @param[in] dagPath is a MDagPath
*
* @return true if the object is a sky dome light, false otherwise
*/
bool IsDagPathAnArnoldSkyDomeLight(const MDagPath& dagPath);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me uncomfortable. Why are we treating Arnold lights in a special way, with a special conditional? Is there no way that our adapter infrastructure can handle this? What if another renderer has a different way of handling dome lights?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is specific to maya hydra, not specific to a renderer.


} // namespace MAYAHYDRA_NS_DEF

#endif // MAYAHYDRALIB_MAYA_UTILS_H
51 changes: 43 additions & 8 deletions lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,36 @@ class MayaPickHandler : public MayaHydra::PickHandler {
}
};

// For some dag paths we use the shape to translate it to an Hydra path
bool _UseTheShapeDagPath(const MDagPath& dagpath)
{
bool extendToShape = false;

//So far we only have one case : the Arnold sky dome light
const bool isSkyDomeLight = MayaHydra::IsDagPathAnArnoldSkyDomeLight(dagpath);
if (isSkyDomeLight) {
extendToShape = true;
}

return extendToShape;
}

//Check if this dag path is registered in Sprims (such as the Arnold sky dome light)
bool _IsDagPathRegisteredInHydraSPrims(const MDagPath& dagpath)
{
bool isRegisteredInSPrims = false;

//So far we only have one case : the Arnold sky dome light

// The Arnold skydome light has its shape dag path registered as a Sprim in Hydra
const bool isSkyDomeLight = MayaHydra::IsDagPathAnArnoldSkyDomeLight(dagpath);
if (isSkyDomeLight) {
isRegisteredInSPrims = true;
}

return isRegisteredInSPrims;
}

}

PXR_NAMESPACE_OPEN_SCOPE
Expand Down Expand Up @@ -784,26 +814,31 @@ Fvp::PrimSelections MayaHydraSceneIndex::UfePathToPrimSelections(const Ufe::Path

// Not the best implementation performance-wise, as ufeToDagPath converts
// the UFE path to a string, then does a Dag path lookup with the string.
constexpr bool isSprim = false; // Can't handle sprims as of 15-Aug-2023.


auto dagPath = UfeExtensions::ufeToDagPath(appPath);
SdfPath primPath = GetPrimPath(dagPath, isSprim);
TF_DEBUG(MAYAHYDRALIB_SCENE_INDEX)
.Msg(" mapped to scene index path %s.\n", primPath.GetText());

const bool extendToShape = _UseTheShapeDagPath(dagPath);//For Hydra some prims, we need to use the shape dag path not the transform, as this is what gets translated to an hydra path
const bool isSprim = _IsDagPathRegisteredInHydraSPrims(dagPath);

MDagPath shapeDagPath(dagPath);
shapeDagPath.extendToShape();

SdfPath primPath = GetPrimPath((extendToShape) ? shapeDagPath : dagPath, isSprim);

//Check if this maya node has a special SdfPath associated with it, this is for custom or maya usd data producers scene indices.
//The class MhDataProducersMayaNodeToSdfPathRegistry does a mapping between Maya nodes and USD paths.
//The maya nodes registered in this class are used by data producers as a parent to all
//primitives. This class is used when the user selects one of these
//maya nodes to return the matching SdfPath so that all prims child of this maya node are
//highlighted.
MDagPath shapeDagPath(dagPath);
shapeDagPath.extendToShape();

const SdfPath matchingPath = FVP_NS::DataProducersNodeHashCodeToSdfPathRegistry::Instance().GetPath(MObjectHandle(shapeDagPath.node()).hashCode());
if (! matchingPath.IsEmpty()) {
primPath = matchingPath;
}

TF_DEBUG(MAYAHYDRALIB_SCENE_INDEX)
.Msg(" mapped to scene index path %s.\n", primPath.GetText());

return Fvp::PrimSelections({Fvp::PrimSelection{primPath}});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ class MAYAHYDRALIB_API MayaHydraSceneIndex : public HdRetainedSceneIndex, public

///Create the default material from the "standardSurface1" maya material or create a fallback material if it cannot be found
void CreateMayaDefaultMaterialData();

/// Get the maya default light path to be used in filtering scene indices to recognize the default light in primitives path
static const SdfPath& GetMayaDefaultLightPath() {return _mayaDefaultLightPath;}

private:
MayaHydraSceneIndex(
Expand Down
Loading