Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cryptomatte from Blender 3.x/4.x is not Displayed in Viewer #5866

Closed
aditiapratama opened this issue May 24, 2024 · 6 comments · Fixed by #5868
Closed

Cryptomatte from Blender 3.x/4.x is not Displayed in Viewer #5866

aditiapratama opened this issue May 24, 2024 · 6 comments · Fixed by #5868

Comments

@aditiapratama
Copy link

Version: Gaffer 1.4.X.X-(linux, windows)
Third-party tools: None
Third-party modules: None

Description

I have EXR with cryptomatte generated from blender 3.6 LTS and also 4.1.1. Whenever I load it and put cryptomatte node, the Viewer will stay black. However I have another EXR with crypto from blender 2.93 LTS, it will load just fine.

I attached both exr and blend files.

image
image

Steps to reproduce

  1. Download EXR files from here https://1drv.ms/f/s!AipTDeE9i3xFh8401PPddxldrzu5Sw?e=XE6EDa
  2. drag and drop into Gaffer
  3. add cryptomatte node to both of the files
  4. try change layer selection
  5. notice that Viewer will stay black if using exr generated from blender 3 and above

Debug log

Click to Expand


@johnhaddon
Copy link
Member

To me it looks like there are a few different things going on here :

  • The EXR file out of Blender has non-standard channel names, with lowercase .r, .g etc where there should be uppercase .R, .B etc.
  • The EXR file out of Blender has everything nested inside a ViewLayer layer for some reason. This isn't technically wrong, but it is unusual in my experience. This also means there is no standard RGBA "beauty" layer.
  • The Cryptomatte node has a bug when there is no RGBA layer in the input.

If you copy-paste the script below into Gaffer, you should see that things can be made to work if those problems are corrected.

import Gaffer
import GafferImage
import GafferScene
import IECore
import imath

Gaffer.Metadata.registerValue( parent, "serialiser:milestoneVersion", 1, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:majorVersion", 4, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:minorVersion", 3, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:patchVersion", 0, persistent=False )

__children = {}

__children["with_z_b41_0001"] = GafferImage.ImageReader( "with_z_b41_0001" )
parent.addChild( __children["with_z_b41_0001"] )
__children["with_z_b41_0001"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Cryptomatte"] = GafferScene.Cryptomatte( "Cryptomatte" )
parent.addChild( __children["Cryptomatte"] )
__children["Cryptomatte"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Shuffle"] = GafferImage.Shuffle( "Shuffle" )
parent.addChild( __children["Shuffle"] )
__children["Shuffle"]["shuffles"].addChild( Gaffer.ShufflePlug( "shuffle0", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Shuffle"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Expression"] = Gaffer.Expression( "Expression" )
parent.addChild( __children["Expression"] )
__children["Expression"]["__out"].addChild( Gaffer.StringPlug( "p0", direction = Gaffer.Plug.Direction.Out, defaultValue = '', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, substitutions = IECore.StringAlgo.Substitutions.NoSubstitutions ) )
__children["Expression"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Constant"] = GafferImage.Constant( "Constant" )
parent.addChild( __children["Constant"] )
__children["Constant"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CopyChannels"] = GafferImage.CopyChannels( "CopyChannels" )
parent.addChild( __children["CopyChannels"] )
__children["CopyChannels"]["in"].addChild( GafferImage.ImagePlug( "in2", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["CopyChannels"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["with_z_b41_0001"]["fileName"].setValue( '/home/john/Downloads/cryptomatte/with_z_b41_0001.exr' )
__children["with_z_b41_0001"]["__uiPosition"].setValue( imath.V2f( 18.1511688, 33.2099152 ) )
Gaffer.Metadata.registerValue( __children["Cryptomatte"], 'annotation:user:text', 'With all those fixes applied, the Cryptomatte node can recognise the input and generate a matte appropriately.' )
Gaffer.Metadata.registerValue( __children["Cryptomatte"], 'annotation:user:color', imath.Color3f( 0.150000006, 0.25999999, 0.25999999 ) )
__children["Cryptomatte"]["in"].setInput( __children["CopyChannels"]["out"] )
__children["Cryptomatte"]["layer"].setValue( 'ViewLayer.CryptoObject' )
__children["Cryptomatte"]["matteNames"].setValue( IECore.StringVectorData( [ '/Cube', '' ] ) )
__children["Cryptomatte"]["__uiPosition"].setValue( imath.V2f( 21.1511688, 2.11772776 ) )
Gaffer.Metadata.registerValue( __children["Shuffle"], 'annotation:user:text', 'The EXR from Blender is malformed, with channels using lower-case names `r`, `g`, `b` etc instead of the expected upper-case names `R`, `G`, `B`. The Shuffle node fixes that.' )
Gaffer.Metadata.registerValue( __children["Shuffle"], 'annotation:user:color', imath.Color3f( 0.150000006, 0.25999999, 0.25999999 ) )
__children["Shuffle"]["in"].setInput( __children["with_z_b41_0001"]["out"] )
__children["Shuffle"]["shuffles"]["shuffle0"]["source"].setValue( '*.[rgba]' )
__children["Shuffle"]["shuffles"]["shuffle0"]["deleteSource"].setValue( True )
Gaffer.Metadata.registerValue( __children["Shuffle"]["shuffles"]["shuffle0"]["source"], 'channelPlugValueWidget:isCustom', True )
__children["Shuffle"]["shuffles"]["shuffle0"]["destination"].setInput( __children["Expression"]["__out"]["p0"] )
Gaffer.Metadata.registerValue( __children["Shuffle"]["shuffles"]["shuffle0"]["destination"], 'channelPlugValueWidget:isCustom', True )
__children["Shuffle"]["__uiPosition"].setValue( imath.V2f( 18.1511688, 25.0458527 ) )
__children["Expression"]["__uiPosition"].setValue( imath.V2f( 7.6503315, 25.0460129 ) )
__children["Constant"]["__uiPosition"].setValue( imath.V2f( 36.8500023, 18.4458523 ) )
Gaffer.Metadata.registerValue( __children["CopyChannels"], 'annotation:user:text', 'The Cryptomatte node seems to have a bug triggered by not having RGBA channels in the input. Copy in some channels to keep it happy.' )
Gaffer.Metadata.registerValue( __children["CopyChannels"], 'annotation:user:color', imath.Color3f( 0.150000006, 0.25999999, 0.25999999 ) )
__children["CopyChannels"]["in"][0].setInput( __children["Shuffle"]["out"] )
__children["CopyChannels"]["in"][1].setInput( __children["Constant"]["out"] )
__children["CopyChannels"]["channels"].setValue( '*' )
__children["CopyChannels"]["__uiPosition"].setValue( imath.V2f( 21.1511688, 10.2817898 ) )
__children["Expression"]["__engine"].setValue( 'python' )
__children["Expression"]["__expression"].setValue( 'source = context.get( "source", "" )\ndest = source.replace( ".r", ".R" )\ndest = dest.replace( ".g", ".G" )\ndest = dest.replace( ".b", ".B" )\ndest = dest.replace( ".a", ".A" )\n\nparent["__out"]["p0"] = dest' )


del __children

I think it's probably worth us tweaking the ImageReader so that it can conform the non-standard lowercase channels automatically - we already have loads of heuristics for dealing with dodgy EXRs from other sources. And we should fix the Cryptomatte problem too. But ideally you'd be able to get the output from Blender formatted in a more standard way as well...

@johnhaddon
Copy link
Member

The EXR file out of Blender has non-standard channel names, with lowercase .r, .g etc where there should be uppercase .R, .B etc.

Actually, I see now that the Cryptomatte specification says lowercase, but that conflicts with the EXR specification, which says uppercase... 🤷

johnhaddon added a commit to johnhaddon/gaffer that referenced this issue May 24, 2024
- Remove stray hashing of the current input channel.
- Check cryptomatte channels exists before hashing them.
- Include cryptomatte alpha channel in hash.

This fixes one of the problems noted in GafferHQ#5866.
johnhaddon added a commit to johnhaddon/gaffer that referenced this issue May 24, 2024
The EXR standard states that it is only the upper case "R", "G", "B" and "A" that have a predefined interpretation, and that is how we treat channels in GafferImage. But in the last week I've received files from two different sources both using lower-case, so this seems worth fixing up on load.

In the latter case, the file was from Blender and only the Cryptomatte channels were lowercased. To my surprise, that is actually enshrined in the Cryptomatte specification. I can't find a source for _why_, but based on Psyop/Cryptomatte#35 it seems that _maybe_ it's to disable lossy DWA compression when the DCC won't let you control that per-file or per-part? That seems to call into question the entire idea of using RGBA to represent ID and coverage in the first place, which I believe was originally to play well in apps that only recognised RGBA.

In conjunction with GafferHQ#5867, this fixes GafferHQ#5866.
@johnhaddon
Copy link
Member

I've opened PR #5867 with the Cryptomatte fix, and #5868 with a workaround for lowercase names not conforming to the EXR spec.

@aditiapratama
Copy link
Author

Thank you @johnhaddon ,

Anyway I tried to run the python script but it complained about parent not defined...so I set parent = root and it works, but not sure if it's the correct way .

Also I tried using shuffle and copied your python expression, but it's not working as well.

I tried using the plugs and it works if manually setup.

@johnhaddon
Copy link
Member

Anyway I tried to run the python script but it complained about parent not defined

If you paste it directly into the Graph Editor it should work.

@aditiapratama
Copy link
Author

Ah yes..it's working
image

Thank you @johnhaddon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants