Color Shift on srgb textures in the viewport
- Dominant language
- Wolfram Language
- Stars
- 905
- Forks
- 223
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 17
Description
**Describe the bug**
Hi there,
We (AL) have encountered an bug where we see a color shift which seems to be due to an issue with the [_localTextureMap](https://github.com/Autodesk/maya-usd/blob/e87e10dab08af4364f38e87f74bc41c2e6f0c9a1/lib/mayaUsd/render/vp2RenderDelegate/material.h#L197) and the texture manager becoming out of sync. We have a workflow where the stage contains a geom and material in one variant and we need to switch to another variant where the geom and material do not exist, during the switching there are two important things happen:
- The geom and its material will be removed from the stage, the corresponding HdVP2Material and the texture is destroyed and released as expected;
- We have a custom script would run after switching to the new variant and creates a native Maya geometry and references the same texture file, which causes the MTextureManager loads and caches the texture file globally.
If we then switch back to previous variant, we can observe a color shift
This seems to be due to the fact that Maya's [MTextureManager](https://github.com/Autodesk/maya-usd/blob/e87e10dab08af4364f38e87f74bc41c2e6f0c9a1/lib/mayaUsd/render/vp2RenderDelegate/material.cpp#L1419) still holds a reference to the texture (and will [return early](https://github.com/Autodesk/maya-usd/blob/dev/lib/mayaUsd/render/vp2RenderDelegate/material.cpp#L1426-L1427)), but the [HdVP2TextureInfoSharedPtr](https://github.com/Autodesk/maya-usd/blob/e87e10dab08af4364f38e87f74bc41c2e6f0c9a1/lib/mayaUsd/render/vp2RenderDelegate/material.h#L78) object which holds the [HdVP2TextureInfo](https://github.com/Autodesk/maya-usd/blob/e87e10dab08af4364f38e87f74bc41c2e6f0c9a1/lib/mayaUsd/render/vp2RenderDelegate/material.h#L57) _isColorSpaceSRGB info has been destroyed during the de-construction of HdVP2Material, in our case, [_LoadTexture](https://github.com/Autodesk/maya-usd/blob/e87e10dab08af4364f38e87f74bc41c2e6f0c9a1/lib/mayaUsd/render/vp2RenderDelegate/material.cpp#L1399) returns the texture but leaving the isSRGB and uvScaleOffset being default value which is the discrepancy we found
I have attached a code snippet, layer and jpg texture to repro this
Could you advise on the best option to fix this?
**Steps to reproduce**
Steps to reproduce the behavior:
1. Download/save the attached `srgbColorChart.jpg` texture and `simplePlaneMaterial.usda` layer
2. Update the rootLayer and srgbTexture path variables in the attached srgb_texture_scene_setup.py file and execute
3. You should observe the following color shift
USD Geom on the left, Maya poly mesh on the right

**Expected behavior**
We would expect no color shift to take place during variant switching / activation toggling
**Attachments**

`simplePlaneMaterial.usda`
```
#usda 1.0
(
)
def Xform "plane01" (
kind = "component"
)
{
def Mesh "planeMesh" (
apiSchemas = ["MaterialBindingAPI"]
)
{
float3[] extent = [(-145, -145, 0), (145, 145, 0)]
int[] faceVertexCounts = [4]
int[] faceVertexIndices = [0, 1, 2, 3]
rel material:binding =
point3f[] points = [(-145, -145, 0), (145, -145, 0), (145, 145, 0), (-145, 145, 0)]
texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1)] (
interpolation = "varying"
)
}
def Material "planeMaterial"
{
token inputs:frame:stPrimvarName = "st"
token outputs:surface.connect =
def Shader "PBRShader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor.connect =
float inputs:metallic = 0
float inputs:roughness = 0.4
token outputs:surface
}
def Shader "stReader"
{
uniform token info:id = "UsdPrimvarReader_float2"
token inputs:varname.connect =
float2 outputs:result
}
def Shader "diffuseTexture"
{
uniform token info:id = "UsdUVTexture"
asset inputs:file = @./srgbColorChart.jpg@
float2 inputs:st.connect =
float3 outputs:rgb
}
}
}
```
`srgb_texture_scene_setup.py`
```python
from functools import partial
import mayaUsd
from maya import cmds
def main():
# NOTE: ################### UPDATE PATHS ###########################
# layer contains a relative reference to the srgbColorChart.jpg file.
rootLayer = "/path/to/simplePlaneMaterial.usda"
srgbTexture = "/path/to/srgbColorChart.jpg"
cmds.file(force=True, new=True)
# Make sure the sync mode is ON (disable async loading)
cmds.optionVar(intValue=("mayaUsd_DisableAsyncTextureLoading", 1))
# setup camera
cmds.xform("persp", translation=(145, 2, 568), rotation=(0, 0, 0), worldSpace=True)
panel = activeModelPanel()
cmds.modelEditor(
panel,
edit=True,
lights=False,
displayLights="default",
displayTextures=True,
grid=False,
)
# load usd stage
shapeNode, _ = createProxyFromFile(rootLayer)
#### setup plane with srgb texture assigned ####
polyPlaneName, _nodeName = cmds.polyPlane()
cmds.xform(
polyPlaneName,
translation=(290, 0, 0),
scale=(290, 290, 290),
rotation=(90, 0, 0),
)
# create usdPreviewSufraceShader
lambertShader = cmds.shadingNode("usdPreviewSurface", asShader=True)
shaderGroup = cmds.sets(renderable=True, noSurfaceShader=True, empty=True)
cmds.connectAttr(
f"{lambertShader}.outColor", f"{shaderGroup}.surfaceShader", force=True
)
# create fileTexture node
fileTexture = cmds.shadingNode("file", asShader=True, isColorManaged=True)
cmds.setAttr(f"{fileTexture}.fileTextureName", srgbTexture, type="string")
cmds.connectAttr(
f"{fileTexture}.outColor", f"{lambertShader}.diffuseColor", force=True
)
# assign shader to the polyPlane
cmds.sets(polyPlaneName, forceElement=shaderGroup)
cmds.select(cl=True)
stage = mayaUsd.ufe.getStage(shapeNode)
prim = stage.GetPrimAtPath("/plane01")
assert prim.IsValid()
def toggleState(prim):
prim.SetActive(False)
prim.SetActive(True)
cmds.evalDeferred(partial(toggleState, prim))
def createProxyFromFile(filePath):
cmds.createNode("mayaUsdProxyShape", name="stageShape")
shapeNode = cmds.ls(sl=True, l=True)[0]
cmds.setAttr("{}.filePath".format(shapeNode), filePath, type="string")
shapeStage = mayaUsd.lib.GetPrim(shapeNode).GetStage()
cmds.select(clear=True)
cmds.connectAttr("time1.outTime", "{}.time".format(shapeNode))
return shapeNode, shapeStage
def activeModelPanel():
for panel in cmds.getPanel(type="modelPanel"):
if cmds.modelEditor(panel, q=1, av=1):
return panel
if __name__ == "__main__":
main()
```
**Specs (if applicable):**
- OS & version [e.g. CentOS-7.8 ]
- Compiler & version [ gcc 6.3.1]
- Maya version [e.g. Maya 2022.3]
- Maya USD commit SHA [e.g. dev at 91a5ff052dae1d3f3c8acc9aac0e3d4cfe64fe60]
**Additional context**
Add any other context about the problem here.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.