Skip to content

Commit

Permalink
HYDRA-794 : Support maya lighting modes for USD and dome lights (#167)
Browse files Browse the repository at this point in the history
* HYDRA-794 : Support maya lighting modes for USD and dome lights (all kind of lights actually)

* Fix tests

* Fix maya lighting modes tests

* Add a missing texture for tests

* Remove grid from test.

* Fix an issue in C++ code found by linux build

* Fixes from code review
  • Loading branch information
lanierd-adsk authored Sep 10, 2024
1 parent f90b636 commit 378f0f0
Show file tree
Hide file tree
Showing 25 changed files with 769 additions and 9 deletions.
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);

} // 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 @@ -777,26 +807,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 @@ -259,6 +259,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

0 comments on commit 378f0f0

Please sign in to comment.