diff --git a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml index b347ded5bf..7974bf22f0 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI2.xml @@ -49,6 +49,7 @@ limitations under the License. + @@ -86,6 +87,7 @@ limitations under the License. + diff --git a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI3.xml b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI3.xml index 46cd092f06..ceb24dde24 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI3.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/UsdPreviewSurfaceLightAPI3.xml @@ -49,6 +49,7 @@ limitations under the License. + @@ -86,6 +87,7 @@ limitations under the License. + diff --git a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI2.xml b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI2.xml index abb6226e85..c4890adc5c 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI2.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI2.xml @@ -379,15 +379,24 @@ surfaceShader(vec3 Peye, vec3 Neye, float specularAmount ) { - float opacity = 1.0 - transparency.r; - if (opacity < opacityThreshold) { - discard; - } - mayaSurfaceShaderOutput result; + result.outGlowColor = vec3(0.0); - // Pre-multiply diffuse color by opacity if not done so already - diffuseColor *= opacity; + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = vec3(0.0); + result.outMatteOpacity = vec3(1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = vec3(opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -406,12 +415,6 @@ surfaceShader(vec3 Peye, vec3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = vec3(0.0, 0.0, 0.0); - result.outMatteOpacity = vec3(opacity); - return result; } @@ -733,15 +736,24 @@ surfaceShader(vec3 Peye, vec3 Neye, float specularAmount ) { - float opacity = 1.0 - transparency.r; - if (opacity < opacityThreshold) { - discard; - } - mayaSurfaceShaderOutput result; + result.outGlowColor = vec3(0.0); - // Pre-multiply diffuse color by opacity if not done so already - diffuseColor *= opacity; + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = vec3(0.0); + result.outMatteOpacity = vec3(1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = vec3(opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -760,12 +772,6 @@ surfaceShader(vec3 Peye, vec3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = vec3(0.0, 0.0, 0.0); - result.outMatteOpacity = vec3(opacity); - return result; } @@ -1087,15 +1093,24 @@ surfaceShader(float3 Peye, float3 Neye, float specularAmount ) { - float opacity = 1.0 - transparency.r; - if (opacity < opacityThreshold) { - discard; - } - mayaSurfaceShaderOutput result; + result.outGlowColor = float3(0.0, 0.0, 0.0); - // Pre-multiply diffuse color by opacity if not done so already - diffuseColor *= opacity; + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = float3(1.0, 1.0, 1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = float3(opacity, opacity, opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -1114,12 +1129,6 @@ surfaceShader(float3 Peye, float3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = float3(0.0, 0.0, 0.0); - result.outMatteOpacity = float3(opacity, opacity, opacity); - return result; } diff --git a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI3.xml b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI3.xml index 4d1c011bc1..b53aff7981 100644 --- a/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI3.xml +++ b/lib/mayaUsd/render/vp2ShaderFragments/usdPreviewSurfaceLightingAPI3.xml @@ -379,15 +379,24 @@ surfaceShader(vec3 Peye, vec3 Neye, float specularAmount ) { - float opacity = 1.0 - transparency.r; - if (opacity < opacityThreshold) { - discard; - } - mayaSurfaceShaderOutput result; + result.outGlowColor = vec3(0.0); - // Pre-multiply diffuse color by opacity if not done so already - diffuseColor *= opacity; + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = vec3(0.0); + result.outMatteOpacity = vec3(1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = vec3(opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -406,12 +415,6 @@ surfaceShader(vec3 Peye, vec3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = vec3(0.0, 0.0, 0.0); - result.outMatteOpacity = vec3(opacity); - return result; } @@ -733,15 +736,24 @@ surfaceShader(vec3 Peye, vec3 Neye, 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; + result.outGlowColor = vec3(0.0); + + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = vec3(0.0); + result.outMatteOpacity = vec3(1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = vec3(opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -760,12 +772,6 @@ surfaceShader(vec3 Peye, vec3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = vec3(0.0, 0.0, 0.0); - result.outMatteOpacity = vec3(opacity); - return result; } @@ -1087,15 +1093,24 @@ surfaceShader(float3 Peye, float3 Neye, 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; + result.outGlowColor = float3(0.0, 0.0, 0.0); + + // Transparency and cutout. + float opacity = 1.0 - transparency.r; + if (opacityThreshold > 0.0) { + if (opacity < opacityThreshold) { + discard; + } + result.outTransparency = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = float3(1.0, 1.0, 1.0); + } else { + result.outTransparency = transparency; + result.outMatteOpacity = float3(opacity, opacity, opacity); + + // Pre-multiply diffuse color by opacity if not done so already + diffuseColor *= opacity; + } // Evaluate all lights. result.outColor = evaluateLights( @@ -1114,12 +1129,6 @@ surfaceShader(float3 Peye, float3 Neye, Peye, Neye); - // Transparency - result.outTransparency = transparency; - - result.outGlowColor = float3(0.0, 0.0, 0.0); - result.outMatteOpacity = float3(opacity, opacity, opacity); - return result; } diff --git a/lib/usd/pxrUsdPreviewSurface/usdPreviewSurface.cpp b/lib/usd/pxrUsdPreviewSurface/usdPreviewSurface.cpp index 05366015ec..8d2114e860 100644 --- a/lib/usd/pxrUsdPreviewSurface/usdPreviewSurface.cpp +++ b/lib/usd/pxrUsdPreviewSurface/usdPreviewSurface.cpp @@ -393,6 +393,8 @@ MStatus PxrMayaUsdPreviewSurface::initialize() status = attributeAffects(opacityAttr, outTransparencyOnAttr); CHECK_MSTATUS_AND_RETURN_IT(status); + status = attributeAffects(opacityThresholdAttr, outTransparencyOnAttr); + CHECK_MSTATUS_AND_RETURN_IT(status); return status; } @@ -444,8 +446,8 @@ MStatus PxrMayaUsdPreviewSurface::compute(const MPlug& plug, MDataBlock& dataBlo CHECK_MSTATUS(status); const float opacityThreshold = opacityThresholdData.asFloat(); - if (opacity < opacityThreshold) { - opacity = 0.0f; + if (opacityThreshold > 0.0f) { + opacity = (opacity < opacityThreshold) ? 0.0f : 1.0f; } const float transparency = 1.0f - opacity; @@ -461,32 +463,44 @@ MStatus PxrMayaUsdPreviewSurface::compute(const MPlug& plug, MDataBlock& dataBlo // details. We don't use the user-visible "outTransparency" attribute for transparency test // because its value depends on upstream nodes and thus error-prone when the "opacity" plug // is connected to certain textures. In that case, we should enable transparency. - bool opacityConnected = false; - const MObject opacityAttr - = depNodeFn.attribute(PxrMayaUsdPreviewSurfaceTokens->OpacityAttrName.GetText()); - const MPlug opacityPlug(thisMObject(), opacityAttr); - if (opacityPlug.isConnected()) { - const MPlug sourcePlug = opacityPlug.source(&status); - CHECK_MSTATUS(status); - const MObject sourceNode = sourcePlug.node(&status); - CHECK_MSTATUS(status); - - // Anim curve output will be evaluated to determine if transparency should be enabled. - if (!sourceNode.hasFn(MFn::kAnimCurve)) { - opacityConnected = true; - } - } + MObject opacityThresholdAttr = depNodeFn.attribute( + PxrMayaUsdPreviewSurfaceTokens->OpacityThresholdAttrName.GetText()); + const MDataHandle opacityThresholdData + = dataBlock.inputValue(opacityThresholdAttr, &status); + CHECK_MSTATUS(status); float transparencyOn = false; - if (opacityConnected) { - transparencyOn = true; - } else { - const MDataHandle opacityData = dataBlock.inputValue(opacityAttr, &status); - CHECK_MSTATUS(status); - const float opacity = opacityData.asFloat(); - if (opacity < 1.0f - std::numeric_limits::epsilon()) { + + // For masked transparency, we want VP2 to treat the shader as opaque. + if (opacityThresholdData.asFloat() <= 0.0f) { + bool opacityConnected = false; + + const MObject opacityAttr + = depNodeFn.attribute(PxrMayaUsdPreviewSurfaceTokens->OpacityAttrName.GetText()); + const MPlug opacityPlug(thisMObject(), opacityAttr); + if (opacityPlug.isConnected()) { + const MPlug sourcePlug = opacityPlug.source(&status); + CHECK_MSTATUS(status); + const MObject sourceNode = sourcePlug.node(&status); + CHECK_MSTATUS(status); + + // Anim curve output will be evaluated to determine if transparency should be + // enabled. + if (!sourceNode.hasFn(MFn::kAnimCurve)) { + opacityConnected = true; + } + } + + if (opacityConnected) { transparencyOn = true; + } else { + const MDataHandle opacityData = dataBlock.inputValue(opacityAttr, &status); + CHECK_MSTATUS(status); + const float opacity = opacityData.asFloat(); + if (opacity < 1.0f - std::numeric_limits::epsilon()) { + transparencyOn = true; + } } } diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_negative.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_negative.png index 819959fe71..788ae61b6d 100644 Binary files a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_negative.png and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_negative.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_positive.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_positive.png index aa23079729..d7da88054c 100644 Binary files a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_positive.png and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_box_all_positive.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_negative.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_negative.png index 4ac239b9a1..a6b541f10b 100644 Binary files a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_negative.png and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_negative.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_positive.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_positive.png index 7acfd06274..9a044418c0 100644 Binary files a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_positive.png and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateDrawModesTest/baseline/post-22_11-DrawModes_cross_all_positive.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/opacityThreshold.png b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/opacityThreshold.png new file mode 100644 index 0000000000..5e5f9fd503 Binary files /dev/null and b/test/lib/mayaUsd/render/vp2RenderDelegate/VP2RenderDelegateUSDPreviewSurface/baseline/opacityThreshold.png differ diff --git a/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py b/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py index 150e1270c2..c1cbc709fa 100644 --- a/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py +++ b/test/lib/mayaUsd/render/vp2RenderDelegate/testVP2RenderDelegateUSDPreviewSurface.py @@ -16,6 +16,8 @@ # limitations under the License. # +import unittest + import fixturesUtils import imageUtils @@ -272,5 +274,43 @@ def testDoubleSided(self): mayaUtils.setBasicCamera(3) self.assertSnapshotClose('doubleSided_disabled_back.png') + @unittest.skipUnless(int(os.getenv("MAYA_LIGHTAPI_VERSION")) >= 2, 'UsdPreviewSurface fragment graph for light API v1 does not support opacityThreshold') + def testOpacityThreshold(self): + ''' + Test UsdPreviewSurface transparency cut-out. The surface fragments should be + should be fully transparent or fully opaque when opacityThreshold is positive. + ''' + cmds.file(new=True, force=True) + mayaUtils.loadPlugin('mayaUsdPlugin') + + # Import the USD file. + testFile = testUtils.getTestScene('UsdPreviewSurface', 'TestOpacityThreshold.usda') + mayaUtils.createProxyFromFile(testFile) + + # Frame the scene for the snapshot. + cmds.xform("persp", t= (0, 1, 2.25)) + cmds.xform("persp", ro=[-25, 0, 0], ws=True) + + # Create a light to cast a shadow. + white_light = cmds.directionalLight(rgb=(1, 1, 1)) + white_transform = cmds.listRelatives(white_light, parent=True)[0] + cmds.xform(white_transform, ro=(-35, -35, 0), ws=True) + + # Turn on texturing, lighting, shadows. + cmds.modelEditor( + mayaUtils.activeModelPanel(), + edit=True, + displayTextures=True, + displayLights='all', + shadows=True, + lights=False + ) + + # This option is needed for VP2 to discard shadow map samples. + cmds.setAttr('hardwareRenderingGlobals.transparentShadow', True) + + # Snapshot and assert similarity. + self.assertSnapshotClose('opacityThreshold.png') + if __name__ == '__main__': fixturesUtils.runTests(globals()) diff --git a/test/testSamples/UsdPreviewSurface/TestOpacityThreshold.usda b/test/testSamples/UsdPreviewSurface/TestOpacityThreshold.usda new file mode 100644 index 0000000000..c1bf3aa97c --- /dev/null +++ b/test/testSamples/UsdPreviewSurface/TestOpacityThreshold.usda @@ -0,0 +1,181 @@ +#usda 1.0 +( + defaultPrim = "scene" + metersPerUnit = 0.01 + upAxis = "Y" +) + +def Scope "scene" +{ + def Scope "geo" + { + def "opacityThreshold_000" ( + prepend apiSchemas = ["MaterialBindingAPI"] + specializes = + ) + { + rel material:binding = + double3 xformOp:translate = (-1, 0, 0) + } + + def "opacityThreshold_025" ( + prepend apiSchemas = ["MaterialBindingAPI"] + specializes = + ) + { + rel material:binding = + double3 xformOp:translate = (-0.5, 0, 0) + } + + def "opacityThreshold_050" ( + prepend apiSchemas = ["MaterialBindingAPI"] + specializes = + ) + { + rel material:binding = + double3 xformOp:translate = (0, 0, 0) + } + + def "opacityThreshold_075" ( + prepend apiSchemas = ["MaterialBindingAPI"] + specializes = + ) + { + rel material:binding = + double3 xformOp:translate = (0.5, 0, 0) + } + + def "opacityThreshold_100" ( + prepend apiSchemas = ["MaterialBindingAPI"] + specializes = + ) + { + rel material:binding = + double3 xformOp:translate = (1, 0, 0) + } + + def Mesh "ground" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + float3[] extent = [(-1, 0, -1), (1, 0, 1)] + int[] faceVertexCounts = [4] + int[] faceVertexIndices = [0, 1, 3, 2] + rel material:binding = + point3f[] points = [(-1, 0, 1), (1, 0, 1), (-1, 0, -1), (1, 0, -1)] + float3[] primvars:normals = [(0, 1, 0)] ( + interpolation = "constant" + ) + double3 xformOp:scale = (1.5, 1, 0.75) + double3 xformOp:translate = (0, -0.225, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + } + + def Scope "mtl" + { + def Material "groundMat" + { + token outputs:surface.connect = + + def Shader "surface" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor = (1, 1, 1) + float inputs:roughness = 1 + int inputs:useSpecularWorkflow = 1 + token outputs:surface + } + } + + def Material "opacityThreshold_000" ( + specializes = + ) + { + float inputs:opacityThreshold = 0 + } + + def Material "opacityThreshold_025" ( + specializes = + ) + { + float inputs:opacityThreshold = 0.25 + } + + def Material "opacityThreshold_050" ( + specializes = + ) + { + float inputs:opacityThreshold = 0.5 + } + + def Material "opacityThreshold_075" ( + specializes = + ) + { + float inputs:opacityThreshold = 0.75 + } + + def Material "opacityThreshold_100" ( + specializes = + ) + { + float inputs:opacityThreshold = 1 + } + } +} + +def Scope "lib" +{ + class Mesh "frontFacingPlane" + { + uniform bool doubleSided = 1 + float3[] extent = [(-1, -1, 0), (1, 1, 0)] + int[] faceVertexCounts = [4] + int[] faceVertexIndices = [0, 1, 3, 2] + normal3f[] normals = [(0, 0, 1)] ( + interpolation = "constant" + ) + point3f[] points = [(-1, -1, 0), (1, -1, 0), (-1, 1, 0), (1, 1, 0)] + texCoord2f[] primvars:st = [(0, 0), (1, 0), (0, 1), (1, 1)] ( + interpolation = "vertex" + ) + uniform token subdivisionScheme = "none" + double3 xformOp:scale = (0.25, 0.25, 0.25) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:scale"] + } + + class Material "texturedOpacityMat" + { + float inputs:opacityThreshold = 0 + token outputs:surface.connect = + + def Shader "surface" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor = (1, 0, 0) + float inputs:opacity.connect = + float inputs:opacityThreshold.connect = + token outputs:surface + } + + def Shader "opacityRamp" + { + uniform token info:id = "UsdUVTexture" + asset inputs:file = @./opacityRamp.png@ ( + colorSpace = "raw" + ) + float2 inputs:st.connect = + float outputs:a + } + + def Shader "texCooordReader" + { + uniform token info:id = "UsdPrimvarReader_float2" + string inputs:varname = "st" + float2 outputs:result + } + } +} + diff --git a/test/testSamples/UsdPreviewSurface/opacityRamp.png b/test/testSamples/UsdPreviewSurface/opacityRamp.png new file mode 100644 index 0000000000..bd14f018ea Binary files /dev/null and b/test/testSamples/UsdPreviewSurface/opacityRamp.png differ