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 6 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
163 changes: 163 additions & 0 deletions lib/flowViewport/sceneIndex/fvpLightsManagementSceneIndex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// 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 {

bool _IsALight(const TfToken& primType)
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
{
static const TfTokenVector & lightsToken = HdLightPrimTypeTokens();//Get all light tokens from USD
return lightsToken.end() != std::find(lightsToken.begin(), lightsToken.end(), primType);
}

void _DisableLight(HdSceneIndexPrim& prim)
{
//We don't set the intensity to 0 as for domelights this makes disappear the geometry
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this intensity behavior the same for all dome lights, or specific to the Arnold one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's for all dome lights as this is happening in Storm, when the dome light intensity is 0 it is removed, not only ignored.

HdContainerDataSourceEditor editor(prim.dataSource);
editor.Set(
HdLightSchema::GetDefaultLocator().Append(HdLightTokens->ambient),
HdRetainedTypedSampledDataSource<float>::New(0.0f)
);
editor.Set(
HdLightSchema::GetDefaultLocator().Append(HdLightTokens->diffuse),
HdRetainedTypedSampledDataSource<float>::New(0.f)
);
editor.Set(
HdLightSchema::GetDefaultLocator().Append(HdLightTokens->specular),
HdRetainedTypedSampledDataSource<float>::New(0.f)
);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved

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 (_IsALight(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 (! _IsALight(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;//This is also handled in renderOverride.cpp with the _hasDefaultLighting member
Copy link
Collaborator

Choose a reason for hiding this comment

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

Flow Viewport Toolkit can't really know about renderOverride.cpp. I assume all that is needed is to adjust the comment to be more generic.

} break;
case LightingMode::kSelectedLightsOnly: {
const Ufe::GlobalSelection::Ptr& globalUfeSelection = Ufe::GlobalSelection::get();
const Ufe::Selection& ufeSelection = *globalUfeSelection;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor and optional (depends on personal preference really): since you don't use globalUfeSelection again, may as well just do

Suggested change
const Ufe::GlobalSelection::Ptr& globalUfeSelection = Ufe::GlobalSelection::get();
const Ufe::Selection& ufeSelection = *globalUfeSelection;
const Ufe::Selection& ufeSelection = *Ufe::GlobalSelection::get();

if (0 == ufeSelection.size()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor:

Suggested change
if (0 == ufeSelection.size()) {
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 std::string _aiSkyDomeLight("aiSkyDomeLight");

if (! dagPath.isValid()) return false;

const std::string fpName = dagPath.fullPathName().asChar();
return (fpName.find(_aiSkyDomeLight) != std::string::npos);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
}


} // 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
22 changes: 14 additions & 8 deletions lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,26 +784,32 @@ 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 isDomeLight = IsDagPathAnArnoldSkyDomeLight(dagPath);
const bool isSprim = isDomeLight;//we will look in sprims only for the sky dome light
MDagPath shapeDagPath(dagPath);
shapeDagPath.extendToShape();

//For the sky dome light, we want to get it from the Sprims and we are using the dag path shape
// as this is the dag path that gets translated to an Sprim in Hydra
SdfPath primPath = GetPrimPath((isDomeLight) ? shapeDagPath : dagPath, isSprim);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved

//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