GafferHQ/gaffer

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

Closed this issue · 6 comments

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


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

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

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

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.

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.

Ah yes..it's working
image

Thank you @johnhaddon