Autodesk / Autodesk/maya-usd

Color Shift on srgb textures in the viewport

Open
#2,949 1 comment 0 reactions 1 assignee Claimed by @santosg87 View on GitHub
bug
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
![image](https://user-images.githubusercontent.com/31553301/225764048-b48b5c0e-0147-40dd-8181-7a994b073ae7.png)

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

**Attachments**
![srgbColorChart](https://user-images.githubusercontent.com/31553301/225766301-df42032b-0848-4821-89c7-17e006f97895.jpg)

`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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.