diff --git a/FireRender.Maya.Src/Context/FireRenderContext.cpp b/FireRender.Maya.Src/Context/FireRenderContext.cpp index 9d7768d0..4e1b4d40 100644 --- a/FireRender.Maya.Src/Context/FireRenderContext.cpp +++ b/FireRender.Maya.Src/Context/FireRenderContext.cpp @@ -996,6 +996,29 @@ void FireRenderContext::cleanScene() } } + // detach lights before the rest of the objects to unlink lights correctly + it = m_sceneObjects.begin(); + while (it != m_sceneObjects.end()) + { + FireRenderLight* fireRenderLight = dynamic_cast (it->second.get()); + FireRenderEnvLight* envLight = dynamic_cast(it->second.get()); + + if (fireRenderLight != nullptr) + { + fireRenderLight->detachFromScene(); + it = m_sceneObjects.erase(it); + } + else if (envLight != nullptr) + { + envLight->detachFromScene(); + it = m_sceneObjects.erase(it); + } + else + { + it++; + } + } + m_sceneObjects.clear(); m_camera.clear(); @@ -3648,7 +3671,7 @@ void FireRenderContext::ReadDenoiserFrameBuffersIntoRAM(ReadFrameBufferRequestPa }); } -frw::Light FireRenderContext::GetRprLightFromNode(const MObject& node) +frw::Light FireRenderContext::LinkLightSceneObjectWithCurrentlyParsedMesh(const MObject& node) { MUuid uuidPointer = MFnDependencyNode(node).uuid(); MString uuidString = uuidPointer.asString(); @@ -3682,7 +3705,7 @@ frw::Light FireRenderContext::GetRprLightFromNode(const MObject& node) return envLight->getLight(); } - MGlobal::displayWarning("light with uuid " + MString(lightObjectPointer->uuid().c_str()) + " is not support linking"); + MGlobal::displayWarning("light with uuid " + MString(lightObjectPointer->uuid().c_str()) + " does not support linking"); return frw::Light(); } diff --git a/FireRender.Maya.Src/Context/FireRenderContext.h b/FireRender.Maya.Src/Context/FireRenderContext.h index 47a5c704..16bf70ec 100644 --- a/FireRender.Maya.Src/Context/FireRenderContext.h +++ b/FireRender.Maya.Src/Context/FireRenderContext.h @@ -694,7 +694,7 @@ class FireRenderContext : public IFireRenderContextInfo bool setupDenoiserForViewport(); // used for toon shader light linking - frw::Light GetRprLightFromNode(const MObject& node) override; + frw::Light LinkLightSceneObjectWithCurrentlyParsedMesh(const MObject& node); protected: static int INCORRECT_PLUGIN_ID; diff --git a/FireRender.Maya.Src/Context/FireRenderContextIFace.h b/FireRender.Maya.Src/Context/FireRenderContextIFace.h index 22bd631c..4568d9d1 100644 --- a/FireRender.Maya.Src/Context/FireRenderContextIFace.h +++ b/FireRender.Maya.Src/Context/FireRenderContextIFace.h @@ -60,7 +60,4 @@ class IFireRenderContextInfo virtual bool IsUberScaleSupported() const = 0; virtual bool IsGLTFExport() const = 0; - - // used for toon shader light linking - virtual frw::Light GetRprLightFromNode(const MObject& node) = 0; }; diff --git a/FireRender.Maya.Src/FireMaya.cpp b/FireRender.Maya.Src/FireMaya.cpp index 99d91c4e..e8aae2a2 100644 --- a/FireRender.Maya.Src/FireMaya.cpp +++ b/FireRender.Maya.Src/FireMaya.cpp @@ -1884,6 +1884,21 @@ void FireMaya::Scope::SetCachedShader(const NodeId& id, frw::Shader shader) m->shaderMap[id] = shader; } +std::pair FireMaya::Scope::GetCachedShaderIds(const NodeId& lightId) +{ + return m->lightShaderMap.equal_range(lightId); +} + +void FireMaya::Scope::SetCachedShaderId(const NodeId& lightId, NodeId& shaderId) +{ + m->lightShaderMap.insert(std::pair(lightId, shaderId)); +} + +void FireMaya::Scope::ClearCachedShaderIds(const NodeId& lightId) +{ + m->lightShaderMap.erase(lightId); +} + void FireMaya::Scope::SetCachedVolumeShader(const NodeId& id, frw::Shader shader) { if (!shader) @@ -1965,6 +1980,7 @@ frw::Shader FireMaya::Scope::GetShader(MObject node, const FireRenderMeshCommon* DebugPrint("Parsing shader: %s (forceUpdate=%d, shader.IsDirty()=%d)", shaderId.c_str(), forceUpdate, shader.IsDirty()); m->m_pCurrentlyParsedMesh = pMesh; + m->m_pLastLinkedLight = MObject::kNullObj; // create now shader = ParseShader(node); @@ -1972,6 +1988,18 @@ frw::Shader FireMaya::Scope::GetShader(MObject node, const FireRenderMeshCommon* { SetCachedShader(shaderId, shader); shader.SetDirty(false); + + if (m->m_pLastLinkedLight != MObject::kNullObj) + { + std::string lightId = getNodeUUid(m->m_pLastLinkedLight); + + MFnDependencyNode fnNode(m->m_pLastLinkedLight); + std::string fnName = fnNode.name().asChar(); + + SetCachedShaderId(lightId, shaderId); + + m->m_pLastLinkedLight = MObject::kNullObj; + } } m->m_pCurrentlyParsedMesh = nullptr; diff --git a/FireRender.Maya.Src/FireMaya.h b/FireRender.Maya.Src/FireMaya.h index e72f3bec..c4946364 100644 --- a/FireRender.Maya.Src/FireMaya.h +++ b/FireRender.Maya.Src/FireMaya.h @@ -206,12 +206,14 @@ namespace FireMaya std::map volumeShaderMap; std::map shaderMap; + std::multimap lightShaderMap; // shaderId = lightShaderMap[lightNodeId] std::map valueMap; std::map m_nodeDirtyCallbacks; std::map m_AttributeChangedCallbacks; std::map imageCache; FireRenderMeshCommon const* m_pCurrentlyParsedMesh; // is not supposed to keep any data outside of during mesh parsing + MObject m_pLastLinkedLight; // is not supposed to keep any data outside of during mesh parsing Data(); ~Data(); @@ -232,6 +234,7 @@ namespace FireMaya void NodeDirtyCallback(MObject& node); FireRenderMeshCommon const* GetCurrentlyParsedMesh() const { return m->m_pCurrentlyParsedMesh; } + void SetLastLinkedLight(const MObject& lightObj) const { m->m_pLastLinkedLight = lightObj; } void SetIsLastPassTextureMissing(bool value) const { m_IsLastPassTextureMissing = value; } frw::Value createImageFromShaderNode(MObject node, MString plugName = "outColor", int width = 256, int height = 256) const; @@ -329,6 +332,11 @@ namespace FireMaya frw::Shader GetCachedShader(const NodeId& str) const; void SetCachedShader(const NodeId& str, frw::Shader shader); + typedef std::multimap::iterator MMapNodeIdIterator; + std::pair GetCachedShaderIds(const NodeId& lightId); + void SetCachedShaderId(const NodeId& lightId, NodeId& shaderId);// shaderId = lightShaderMap[lightNodeId] + void ClearCachedShaderIds(const NodeId& lightId); + void Reset(); void Init(rpr_context handle, bool destroyMaterialSystemOnDelete = true, bool createScene = true); void CreateScene(void); diff --git a/FireRender.Maya.Src/FireRenderObjects.cpp b/FireRender.Maya.Src/FireRenderObjects.cpp index 25622cdd..13bfb261 100644 --- a/FireRender.Maya.Src/FireRenderObjects.cpp +++ b/FireRender.Maya.Src/FireRenderObjects.cpp @@ -2028,6 +2028,23 @@ void FireRenderLight::detachFromScene() if (!m_isVisible) return; + FireMaya::Scope& scope = context()->GetScope(); + + MFnDependencyNode fnNode(Object()); + std::string fnName = fnNode.name().asChar(); + + std::string lightId = getNodeUUid(Object()); + auto shaderIds = scope.GetCachedShaderIds(lightId); + for (auto it = shaderIds.first; it != shaderIds.second; ++it) + { + frw::Shader linkedShader = scope.GetCachedShader(it->second); + linkedShader.ClearLinkedLight(GetFrLight().light); + } + if (std::distance(shaderIds.first, shaderIds.second) != 0) + { + scope.ClearCachedShaderIds(lightId); + } + if (auto scene = Scene()) { if (m_light.isAreaLight && m_light.areaLight) @@ -2244,6 +2261,19 @@ void FireRenderEnvLight::detachFromScene() if (!m_isVisible) return; + FireMaya::Scope& scope = context()->GetScope(); + std::string lightId = getNodeUUid(Object()); + auto shaderIds = scope.GetCachedShaderIds(lightId); + for (auto it = shaderIds.first; it != shaderIds.second; ++it) + { + frw::Shader linkedShader = scope.GetCachedShader(it->second); + linkedShader.ClearLinkedLight(getLight()); + } + if (std::distance(shaderIds.first, shaderIds.second) != 0) + { + scope.ClearCachedShaderIds(lightId); + } + if (auto scene = Scene()) { detachFromSceneInternal(); diff --git a/FireRender.Maya.Src/FireRenderToonMaterial.cpp b/FireRender.Maya.Src/FireRenderToonMaterial.cpp index c54525bb..d8597343 100644 --- a/FireRender.Maya.Src/FireRenderToonMaterial.cpp +++ b/FireRender.Maya.Src/FireRenderToonMaterial.cpp @@ -1,6 +1,7 @@ #include "FireRenderToonMaterial.h" #include "FireMaya.h" #include "FireRenderUtils.h" +#include "Context/FireRenderContext.h" #include #include #include @@ -339,14 +340,21 @@ void FireMaya::ToonMaterial::linkLight(Scope& scope, frw::Shader& shader) return; } - frw::Light rprLight = scope.GetIContextInfo()->GetRprLightFromNode(light); + FireRenderContext* pContext = dynamic_cast(scope.GetIContextInfo()); + if (!pContext) + { + return; + } + + frw::Light rprLight = pContext->LinkLightSceneObjectWithCurrentlyParsedMesh(light); if (!rprLight.IsValid()) { return; } - shader.xSetParameterLight(RPR_MATERIAL_INPUT_LIGHT, rprLight); + pContext->GetScope().SetLastLinkedLight(light); + shader.LinkLight(rprLight); } bool checkIsLight(MObject& node) diff --git a/FireRender.Maya.Src/frWrap.h b/FireRender.Maya.Src/frWrap.h index 32bfe447..897578c4 100644 --- a/FireRender.Maya.Src/frWrap.h +++ b/FireRender.Maya.Src/frWrap.h @@ -3712,10 +3712,27 @@ namespace frw return false; } - void xSetParameterLight(rpr_material_node_input parameter, Light light) + void LinkLight(const Light& light) { - const Data& d = data(); - rpr_int res = rprMaterialNodeSetInputLightDataByKey(Handle(), parameter, light.Handle()); + AddReference(light); + + rpr_int res = rprMaterialNodeSetInputLightDataByKey(Handle(), RPR_MATERIAL_INPUT_LIGHT, light.Handle()); + if (res == RPR_ERROR_UNSUPPORTED || + res == RPR_ERROR_INVALID_PARAMETER) + { + // print error/warning if needed + } + else + { + checkStatus(res); + } + } + + void ClearLinkedLight(const Light& light) + { + RemoveReference(light); + + rpr_int res = rprMaterialNodeSetInputLightDataByKey(Handle(), RPR_MATERIAL_INPUT_LIGHT, nullptr); if (res == RPR_ERROR_UNSUPPORTED || res == RPR_ERROR_INVALID_PARAMETER) {