diff --git a/cmake/modules/FindMaya.cmake b/cmake/modules/FindMaya.cmake index 7404899a54..438a8caee7 100644 --- a/cmake/modules/FindMaya.cmake +++ b/cmake/modules/FindMaya.cmake @@ -11,6 +11,7 @@ # MAYA_INCLUDE_DIRS Path to the devkit's include directories # MAYA_API_VERSION Maya version (6-8 digits) # MAYA_APP_VERSION Maya app version (4 digits) +# MAYA_LIGHTAPI_VERSION Maya light API version (1 or 2) # #============================================================================= @@ -297,6 +298,40 @@ find_program(MAYA_PY_EXECUTABLE "Maya's Python executable path" ) +set(MAYA_LIGHTAPI_VERSION 1) +if(IS_MACOSX) + set(MAYA_DSO_SUFFIX ".dylib") + set(MAYA_DSO_PREFIX "lib") +elseif(IS_WINDOWS) + set(MAYA_DSO_SUFFIX ".dll") + set(MAYA_DSO_PREFIX "") +else(IS_LINUX) + set(MAYA_DSO_SUFFIX ".so") + set(MAYA_DSO_PREFIX "lib") +endif() +find_file(MAYA_OGSDEVICES_LIBRARY + "${MAYA_DSO_PREFIX}OGSDevices${MAYA_DSO_SUFFIX}" + HINTS + "${MAYA_LIBRARY_DIR}" + "${MAYA_LOCATION}" + PATH_SUFFIXES + lib/ + bin/ + DOC + "Maya's ${MAYA_LIB} library path" + # NO_CMAKE_SYSTEM_PATH needed to avoid conflicts between + # Maya's Foundation library and OSX's framework. + NO_CMAKE_SYSTEM_PATH +) +message(INFO " Got MAYA_OGSDEVICES_LIBRARY = ${MAYA_OGSDEVICES_LIBRARY}") +if (MAYA_OGSDEVICES_LIBRARY) + file(STRINGS ${MAYA_OGSDEVICES_LIBRARY} HAS_LIGHTAPI_2 REGEX "InitializeLightShader") + if (HAS_LIGHTAPI_2) + set(MAYA_LIGHTAPI_VERSION 2) + endif() +endif() +message(INFO " Got MAYA_LIGHTAPI_VERSION = ${MAYA_LIGHTAPI_VERSION}") + # handle the QUIETLY and REQUIRED arguments and set MAYA_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) @@ -310,6 +345,7 @@ find_package_handle_standard_args(Maya MAYA_LIBRARIES MAYA_API_VERSION MAYA_APP_VERSION + MAYA_LIGHTAPI_VERSION VERSION_VAR MAYA_APP_VERSION ) diff --git a/lib/mayaUsd/CMakeLists.txt b/lib/mayaUsd/CMakeLists.txt index 7e657ae481..03e831819b 100644 --- a/lib/mayaUsd/CMakeLists.txt +++ b/lib/mayaUsd/CMakeLists.txt @@ -75,6 +75,13 @@ if (MAYA_API_VERSION VERSION_GREATER_EQUAL 20230000 AND UFE_VERSION VERSION_GREA ) endif() +if (MAYA_LIGHTAPI_VERSION EQUAL 2) + target_compile_definitions(${PROJECT_NAME} + PRIVATE + MAYA_LIGHTAPI_VERSION_2=2 + ) +endif() + # Some of the UFE classes are exporting STL classes which causes this warning. if(UFE_FOUND AND MSVC) target_compile_options(${PROJECT_NAME} diff --git a/lib/mayaUsd/render/vp2ShaderFragments/CMakeLists.txt b/lib/mayaUsd/render/vp2ShaderFragments/CMakeLists.txt index 3030ef0e7c..ab2550596a 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/CMakeLists.txt +++ b/lib/mayaUsd/render/vp2ShaderFragments/CMakeLists.txt @@ -15,13 +15,15 @@ list(APPEND SHADERFRAGMENTS_XMLS Float4ToFloatX.xml Float4ToFloatY.xml Float4ToFloatZ.xml - UsdPreviewSurface.xml + UsdPreviewSurfaceLightAPI1.xml + UsdPreviewSurfaceLightAPI2.xml lightingContributions.xml opacityToTransparency.xml scaledDiffusePassThrough.xml scaledSpecularPassThrough.xml usdPreviewSurfaceCombiner.xml - usdPreviewSurfaceLighting.xml + usdPreviewSurfaceLightingAPI1.xml + usdPreviewSurfaceLightingAPI2.xml # New fragments BasisCurvesCubicColorDomain.xml BasisCurvesCubicCPVHull.xml diff --git a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurface.xml b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI1.xml similarity index 89% rename from lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurface.xml rename to lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI1.xml index 273bc17bc6..7df571c65c 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurface.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI1.xml @@ -33,7 +33,7 @@ limitations under the License. and combining them with material properties. --> - + @@ -61,15 +61,15 @@ limitations under the License. - - - - + + + + - - - + + + @@ -82,23 +82,23 @@ limitations under the License. - + - + - + - - + + - - + + @@ -108,8 +108,8 @@ limitations under the License. - - + + diff --git a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml new file mode 100644 index 0000000000..fcdf919642 --- /dev/null +++ b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/mayaUsd/render/vp2ShaderFragments/shaderFragments.cpp b/lib/mayaUsd/render/vp2ShaderFragments/shaderFragments.cpp index 48fd39eae7..82dd9fd19c 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/shaderFragments.cpp +++ b/lib/mayaUsd/render/vp2ShaderFragments/shaderFragments.cpp @@ -67,7 +67,8 @@ TF_DEFINE_PRIVATE_TOKENS( (scaledDiffusePassThrough) (scaledSpecularPassThrough) (opacityToTransparency) - (usdPreviewSurfaceLighting) + (usdPreviewSurfaceLightingAPI1) + (usdPreviewSurfaceLightingAPI2) (usdPreviewSurfaceCombiner) (UsdPrimvarColor) @@ -80,6 +81,10 @@ TF_DEFINE_PRIVATE_TOKENS( (UsdPrimvarReader_float3) (UsdPrimvarReader_float4) (UsdPrimvarReader_vector) + + // Graph: + (UsdPreviewSurfaceLightAPI1) + (UsdPreviewSurfaceLightAPI2) ); // clang-format on @@ -119,17 +124,14 @@ static const TfTokenVector _FragmentNames = { _tokens->BasisCurvesCubicColorDoma _tokens->scaledDiffusePassThrough, _tokens->scaledSpecularPassThrough, _tokens->opacityToTransparency, - _tokens->usdPreviewSurfaceLighting, + _tokens->usdPreviewSurfaceLightingAPI1, + _tokens->usdPreviewSurfaceLightingAPI2, _tokens->usdPreviewSurfaceCombiner }; static const TfTokenVector _FragmentGraphNames - = { _tokens->BasisCurvesCubicCPVShader, - _tokens->BasisCurvesCubicFallbackShader, - _tokens->BasisCurvesLinearCPVShader, - _tokens->BasisCurvesLinearFallbackShader, - _tokens->FallbackCPVShader, - _tokens->FallbackShader, - HdVP2ShaderFragmentsTokens->SurfaceFragmentGraphName }; + = { _tokens->BasisCurvesCubicCPVShader, _tokens->BasisCurvesCubicFallbackShader, + _tokens->BasisCurvesLinearCPVShader, _tokens->BasisCurvesLinearFallbackShader, + _tokens->FallbackCPVShader, _tokens->FallbackShader }; namespace { //! Get the file path of the shader fragment. @@ -300,6 +302,32 @@ MStatus HdVP2ShaderFragments::registerFragments() } } + // Register a UsdPreviewSurface shader graph: + { + const MString fragGraphName(HdVP2ShaderFragmentsTokens->SurfaceFragmentGraphName.GetText()); +#ifdef MAYA_LIGHTAPI_VERSION_2 + const MString fragGraphFileName(_tokens->UsdPreviewSurfaceLightAPI2.GetText()); +#else + const MString fragGraphFileName(_tokens->UsdPreviewSurfaceLightAPI1.GetText()); +#endif + if (!fragmentManager->hasFragment(fragGraphName)) { + const std::string fragGraphXmlFile + = TfStringPrintf("%s.xml", fragGraphFileName.asChar()); + const std::string fragGraphXmlPath = _GetResourcePath(fragGraphXmlFile); + + const MString addedName + = fragmentManager->addFragmentGraphFromFile(fragGraphXmlPath.c_str()); + if (addedName != fragGraphName) { + MGlobal::displayError(TfStringPrintf( + "Failed to register fragment graph '%s' from file: %s", + fragGraphName.asChar(), + fragGraphXmlPath.c_str()) + .c_str()); + return MS::kFailure; + } + } + } + #if MAYA_API_VERSION >= 20210000 // Register automatic shader stage input parameters. @@ -361,6 +389,13 @@ MStatus HdVP2ShaderFragments::deregisterFragments() #endif + // De-register UsdPreviewsurface graph: + if (!fragmentManager->removeFragment( + HdVP2ShaderFragmentsTokens->SurfaceFragmentGraphName.GetText())) { + MGlobal::displayWarning("Failed to remove fragment graph: UsdPreviewsurface"); + return MS::kFailure; + } + // De-register all fragment graphs. for (const TfToken& fragGraphNameToken : _FragmentGraphNames) { const MString fragGraphName(fragGraphNameToken.GetText()); diff --git a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI1.xml similarity index 97% rename from lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml rename to lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI1.xml index 368a10b88d..5250c025a5 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI1.xml @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ======================================================================== --> - + Computes the diffuse and specular lighting contributions for a light. @@ -69,11 +69,11 @@ limitations under the License. - + - + - + - + - + + + + Computes usdPreviewSurface using latest maya lighting functions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.0) { + vec3 F0 = specularColor; + vec3 F90 = vec3(1.0); + + if (!useSpecularWorkflow) { + vec3 specColor = mix(vec3(1.0), diffuseColor, metallic); + F0 = mix(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - mix(F0, F90, fresnel)); + } + + // Evaluate clearcoat + vec3 s2 = vec3(0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + R * R * clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +//-- glsl Preview.LightIntegration + +vec3 +evaluateIndirectLighting( + vec3 diffuseColor, + vec3 specularColor, + vec3 Neye, + vec3 E, + float EdotH, + float ior, + float metallic, + float occlusion, + float roughness, + bool useSpecularWorkflow, + float clearcoatAmount, + vec3 clearcoatColor, + float clearcoatRoughness) +{ + vec3 indirect = vec3(0.0); + + vec3 F0 = specularColor; + vec3 F90 = vec3(1.0); + vec3 d = diffuseColor; + const float R = (1.0 - ior) / (1.0 + ior); + if (!useSpecularWorkflow) { + vec3 specColor = mix(vec3(1.0), diffuseColor, metallic); + F0 = mix(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + // Adjust the diffuse so glazing angles have less diffuse + float fresnel = SchlickFresnel(EdotH); + vec3 F = mix(F0, F90, fresnel); + d *= (1.0 - F); + + vec3 diffuse = mayaGetIrradianceEnvironment(Neye); + + // Specular Component + float phongExp = mayaRoughnessToPhongExp(roughness); + vec3 Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + vec3 specular = Li * F; + + // Clearcoat Component + vec3 clearcoat = vec3(0.0); + if (clearcoatAmount > 0.0) { + const vec3 clearcoatF = clearcoatAmount * mix( + R * R * clearcoatColor, // Clearcoat F0 + clearcoatColor, // Clearcoat F90 + fresnel); + phongExp = mayaRoughnessToPhongExp(clearcoatRoughness); + Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + clearcoat = Li * clearcoatF; + } + + // Indirect Lighting + indirect = (d * diffuse + specular + clearcoat) * occlusion; + + return indirect; +} + +vec3 +evaluateLights( + vec3 emissiveColor, + vec3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + vec3 specularColor, + float specularRoughness, + float clearcoatAmount, + vec3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + vec3 Peye, + vec3 Neye) +{ + vec3 n = Neye; + vec3 e = normalize(u_viewPosition - Peye); + float NdotE = max(0.0, dot(n, e)); + + vec3 directLight = vec3(0.0); + vec3 indirectLight = vec3(0.0); + + int numLights = mayaGetNumLights(); + for (int i = 0; i < numLights; ++i) { + + irradiance lightShader = mayaGetLightIrradiance(i, Peye, Neye, e); + + vec3 l = lightShader.Ld; + vec3 h = normalize(e + l); + float NdotL = max(0.0, dot(n, l)); + float NdotH = max(0.0, dot(n, h)); + float EdotH = max(0.0, dot(e, h)); + + vec3 lightDiffuseIrradiance = lightShader.diffuseI; + vec3 lightSpecularIrradiance = lightShader.specularI; + + LightingContributions lightingContrib = evaluateLight( + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + specularRoughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + NdotL, + NdotE, + NdotH, + EdotH, + lightDiffuseIrradiance, + lightSpecularIrradiance); + + // calculate the indirect light (DomeLight) + directLight += (lightingContrib.diffuse + lightingContrib.specular); + } + + { + // Calculate necessary vector information for lighting + vec3 Plight = vec3(0,0,0); + vec3 l = normalize(Plight - Peye); + vec3 h = normalize(e + l); + float EdotH = max(0.0, dot(e, h)); + + indirectLight = evaluateIndirectLighting(diffuseColor, + specularColor, Neye, e, + EdotH, ior, metallic, occlusion, + specularRoughness, useSpecularWorkflow, + clearcoatAmount, clearcoatColor, + clearcoatRoughness); + } + + return (emissiveColor + directLight + indirectLight); +} + + +//-- glsl Preview.Surface + +mayaSurfaceShaderOutput +surfaceShader(vec3 Peye, vec3 Neye, + float clearcoatAmount, + float clearcoatRoughness, + vec3 diffuseColor, + vec3 emissiveColor, + float ior, + float metallic, + float occlusion, + vec3 transparency, + float opacityThreshold, + float roughness, + vec3 specularColor, + bool useSpecularWorkflow, + vec3 clearcoatColor, + float specularAmount +) +{ + float opacity = 1.0 - transparency.r; + if (opacity < opacityThreshold) { + discard; + } + + mayaSurfaceShaderOutput result; + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + + // Evaluate all lights. + result.outColor = evaluateLights( + emissiveColor, + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + roughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + Peye, + Neye); + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = vec3(0.0, 0.0, 0.0); + result.outMatteOpacity = vec3(opacity); + + return result; +} + + +]]> + + + + + + 0.0) { + vec3 F0 = specularColor; + vec3 F90 = vec3(1.0); + + if (!useSpecularWorkflow) { + vec3 specColor = mix(vec3(1.0), diffuseColor, metallic); + F0 = mix(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - mix(F0, F90, fresnel)); + } + + // Evaluate clearcoat + vec3 s2 = vec3(0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + R * R * clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +//-- glsl Preview.LightIntegration + +vec3 +evaluateIndirectLighting( + vec3 diffuseColor, + vec3 specularColor, + vec3 Neye, + vec3 E, + float EdotH, + float ior, + float metallic, + float occlusion, + float roughness, + bool useSpecularWorkflow, + float clearcoatAmount, + vec3 clearcoatColor, + float clearcoatRoughness) +{ + vec3 indirect = vec3(0.0); + + vec3 F0 = specularColor; + vec3 F90 = vec3(1.0); + vec3 d = diffuseColor; + const float R = (1.0 - ior) / (1.0 + ior); + if (!useSpecularWorkflow) { + vec3 specColor = mix(vec3(1.0), diffuseColor, metallic); + F0 = mix(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + // Adjust the diffuse so glazing angles have less diffuse + float fresnel = SchlickFresnel(EdotH); + vec3 F = mix(F0, F90, fresnel); + d *= (1.0 - F); + + vec3 diffuse = mayaGetIrradianceEnvironment(Neye); + + // Specular Component + float phongExp = mayaRoughnessToPhongExp(roughness); + vec3 Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + vec3 specular = Li * F; + + // Clearcoat Component + vec3 clearcoat = vec3(0.0); + if (clearcoatAmount > 0.0) { + const vec3 clearcoatF = clearcoatAmount * mix( + R * R * clearcoatColor, // Clearcoat F0 + clearcoatColor, // Clearcoat F90 + fresnel); + phongExp = mayaRoughnessToPhongExp(clearcoatRoughness); + Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + clearcoat = Li * clearcoatF; + } + + // Indirect Lighting + indirect = (d * diffuse + specular + clearcoat) * occlusion; + + return indirect; +} + +vec3 +evaluateLights( + vec3 emissiveColor, + vec3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + vec3 specularColor, + float specularRoughness, + float clearcoatAmount, + vec3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + vec3 Peye, + vec3 Neye) +{ + vec3 n = Neye; + vec3 e = normalize(u_viewPosition - Peye); + float NdotE = max(0.0, dot(n, e)); + + vec3 directLight = vec3(0.0); + vec3 indirectLight = vec3(0.0); + + int numLights = mayaGetNumLights(); + for (int i = 0; i < numLights; ++i) { + + irradiance lightShader = mayaGetLightIrradiance(i, Peye, Neye, e); + + vec3 l = lightShader.Ld; + vec3 h = normalize(e + l); + float NdotL = max(0.0, dot(n, l)); + float NdotH = max(0.0, dot(n, h)); + float EdotH = max(0.0, dot(e, h)); + + vec3 lightDiffuseIrradiance = lightShader.diffuseI; + vec3 lightSpecularIrradiance = lightShader.specularI; + + LightingContributions lightingContrib = evaluateLight( + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + specularRoughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + NdotL, + NdotE, + NdotH, + EdotH, + lightDiffuseIrradiance, + lightSpecularIrradiance); + + // calculate the indirect light (DomeLight) + directLight += (lightingContrib.diffuse + lightingContrib.specular); + } + + { + // Calculate necessary vector information for lighting + vec3 Plight = vec3(0,0,0); + vec3 l = normalize(Plight - Peye); + vec3 h = normalize(e + l); + float EdotH = max(0.0, dot(e, h)); + + indirectLight = evaluateIndirectLighting(diffuseColor, + specularColor, Neye, e, + EdotH, ior, metallic, occlusion, + specularRoughness, useSpecularWorkflow, + clearcoatAmount, clearcoatColor, + clearcoatRoughness); + } + + return (emissiveColor + directLight + indirectLight); +} + + +//-- glsl Preview.Surface + +mayaSurfaceShaderOutput +surfaceShader(vec3 Peye, vec3 Neye, + float clearcoatAmount, + float clearcoatRoughness, + vec3 diffuseColor, + vec3 emissiveColor, + float ior, + float metallic, + float occlusion, + vec3 transparency, + float opacityThreshold, + float roughness, + vec3 specularColor, + bool useSpecularWorkflow, + vec3 clearcoatColor, + float specularAmount +) +{ + float opacity = 1.0 - transparency.r; + if (opacity < opacityThreshold) { + discard; + } + + mayaSurfaceShaderOutput result; + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + + // Evaluate all lights. + result.outColor = evaluateLights( + emissiveColor, + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + roughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + Peye, + Neye); + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = vec3(0.0, 0.0, 0.0); + result.outMatteOpacity = vec3(opacity); + + return result; +} + + +]]> + + + + + + 0.0) { + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + + if (!useSpecularWorkflow) { + float3 specColor = lerp(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = lerp(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - lerp(F0, F90, fresnel)); + } + + // Evaluate clearcoat + float3 s2 = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + R * R * clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +//-- glsl Preview.LightIntegration + +float3 +evaluateIndirectLighting( + float3 diffuseColor, + float3 specularColor, + float3 Neye, + float3 E, + float EdotH, + float ior, + float metallic, + float occlusion, + float roughness, + bool useSpecularWorkflow, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness) +{ + float3 indirect = float3(0.0, 0.0, 0.0); + + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + float3 d = diffuseColor; + const float R = (1.0 - ior) / (1.0 + ior); + if (!useSpecularWorkflow) { + float3 specColor = lerp(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = lerp(R * R * specColor, specColor, metallic); + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + // Adjust the diffuse so glazing angles have less diffuse + float fresnel = SchlickFresnel(EdotH); + float3 F = lerp(F0, F90, fresnel); + d *= (1.0 - F); + + float3 diffuse = mayaGetIrradianceEnvironment(Neye); + + // Specular Component + float phongExp = mayaRoughnessToPhongExp(roughness); + float3 Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + float3 specular = Li * F; + + // Clearcoat Component + float3 clearcoat = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + const float3 clearcoatF = clearcoatAmount * lerp( + R * R * clearcoatColor, // Clearcoat F0 + clearcoatColor, // Clearcoat F90 + fresnel); + phongExp = mayaRoughnessToPhongExp(clearcoatRoughness); + Li = mayaGetSpecularEnvironment(Neye, E, phongExp); + clearcoat = Li * clearcoatF; + } + + // Indirect Lighting + indirect = (d * diffuse + specular + clearcoat) * occlusion; + + return indirect; +} + +float3 +evaluateLights( + float3 emissiveColor, + float3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + float3 specularColor, + float specularRoughness, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + float3 Peye, + float3 Neye) +{ + float3 n = Neye; + float3 e = normalize(u_viewPosition - Peye); + float NdotE = max(0.0, dot(n, e)); + + float3 directLight = float3(0.0, 0.0, 0.0); + float3 indirectLight = float3(0.0, 0.0, 0.0); + + int numLights = mayaGetNumLights(); + for (int i = 0; i < numLights; ++i) { + + irradiance lightShader = mayaGetLightIrradiance(i, Peye, Neye, e); + + float3 l = lightShader.Ld; + float3 h = normalize(e + l); + float NdotL = max(0.0, dot(n, l)); + float NdotH = max(0.0, dot(n, h)); + float EdotH = max(0.0, dot(e, h)); + + float3 lightDiffuseIrradiance = lightShader.diffuseI; + float3 lightSpecularIrradiance = lightShader.specularI; + + LightingContributions lightingContrib = evaluateLight( + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + specularRoughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + NdotL, + NdotE, + NdotH, + EdotH, + lightDiffuseIrradiance, + lightSpecularIrradiance); + + // calculate the indirect light (DomeLight) + directLight += (lightingContrib.diffuse + lightingContrib.specular); + } + + { + // Calculate necessary vector information for lighting + float3 Plight = float3(0,0,0); + float3 l = normalize(Plight - Peye); + float3 h = normalize(e + l); + float EdotH = max(0.0, dot(e, h)); + + indirectLight = evaluateIndirectLighting(diffuseColor, + specularColor, Neye, e, + EdotH, ior, metallic, occlusion, + specularRoughness, useSpecularWorkflow, + clearcoatAmount, clearcoatColor, + clearcoatRoughness); + } + + return (emissiveColor + directLight + indirectLight); +} + + +//-- glsl Preview.Surface + +mayaSurfaceShaderOutput +surfaceShader(float3 Peye, float3 Neye, + float clearcoatAmount, + float clearcoatRoughness, + float3 diffuseColor, + float3 emissiveColor, + float ior, + float metallic, + float occlusion, + float3 transparency, + float opacityThreshold, + float roughness, + float3 specularColor, + bool useSpecularWorkflow, + float3 clearcoatColor, + float specularAmount +) +{ + float opacity = 1.0 - transparency.r; + if (opacity < opacityThreshold) { + discard; + } + + mayaSurfaceShaderOutput result; + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + + // Evaluate all lights. + result.outColor = evaluateLights( + emissiveColor, + diffuseColor, + useSpecularWorkflow, + ior, + metallic, + specularAmount, + specularColor, + roughness, + clearcoatAmount, + clearcoatColor, + clearcoatRoughness, + occlusion, + Peye, + Neye); + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = float3(opacity, opacity, opacity); + + return result; +} + + + +]]> + + + + \ No newline at end of file diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/CMakeLists.txt b/test/lib/mayaUsd/render/vp2RenderDelegate/CMakeLists.txt index 02e5731cf0..69ee70daeb 100644 --- a/test/lib/mayaUsd/render/vp2RenderDelegate/CMakeLists.txt +++ b/test/lib/mayaUsd/render/vp2RenderDelegate/CMakeLists.txt @@ -58,6 +58,7 @@ foreach(script ${TEST_SCRIPT_FILES}) ENV "MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/lib/maya" "LD_LIBRARY_PATH=${ADDITIONAL_LD_LIBRARY_PATH}" + "MAYA_LIGHTAPI_VERSION=${MAYA_LIGHTAPI_VERSION}" # Maya uses a very old version of GLEW, so we need support for # pre-loading a newer version from elsewhere. diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponse.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponseLightAPI1.png similarity index 100% rename from test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponse.png rename to test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponseLightAPI1.png diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponseLightAPI2.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponseLightAPI2.png new file mode 100644 index 0000000000..d4cdb66d40 Binary files /dev/null and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/testMetallicResponseLightAPI2.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py b/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py index c4e3c31797..f6252147da 100644 --- a/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py +++ b/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py @@ -32,7 +32,6 @@ import os - class testVP2RenderDelegateUSDPreviewSurface(imageUtils.ImageDiffingTestCase): """ Test various features of the USD Preview Surface implementation. @@ -104,7 +103,10 @@ def testMetallicResponse(self): panel = mayaUtils.activeModelPanel() cmds.modelEditor(panel, edit=True, lights=False, displayLights="all") - self.assertSnapshotClose("testMetallicResponse.png") + if int(os.getenv("MAYA_LIGHTAPI_VERSION")) == 2: + self.assertSnapshotClose("testMetallicResponseLightAPI2.png") + else: + self.assertSnapshotClose("testMetallicResponseLightAPI1.png") if __name__ == '__main__': diff --git a/test/testUtils/mayaUtils.py b/test/testUtils/mayaUtils.py index 8c8b7d15da..9003ffb897 100644 --- a/test/testUtils/mayaUtils.py +++ b/test/testUtils/mayaUtils.py @@ -245,6 +245,8 @@ def previewReleaseVersion(): def mayaMajorVersion(): return int(cmds.about(majorVersion=True)) +def mayaMinorVersion(): + return int(cmds.about(minorVersion=True)) def activeModelPanel(): """Return the model panel that will be used for playblasting etc..."""