USD Flip simulation - arnold deform motion blur error

34 views
Skip to first unread message

s.des...@gmail.com

unread,
Nov 24, 2025, 11:35:53 AM (10 days ago) Nov 24
to gaffer-dev
Hello,

I'm trying to render a flip simulation coming from Houdini in USD format with arnold. ( The cache is split by frame).
When I try to render it with deformed motion blur, I get this error :

ParameterAlgo::dataToArray() : Mismatched sample lengths.

 
In Houdini, it seems there is a way to render motion blur on changing topology mesh to avoid this problem by using the "Velocity Blur" option but this option seems available only for HTOA.

Do you have an idea how I can fix this issue in gaffer ?

Thx,

Seb

dan...@image-engine.com

unread,
Nov 24, 2025, 7:55:02 PM (10 days ago) Nov 24
to gaffer-dev
Handling velocity blur in Gaffer is something that has come up periodically ... we really should have a better approach by now, but whenever we think about trying to make a built in node to handle it, we bump up against some ugly special cases that make it a bit hard to define exactly how it should work in all cases, in order to be compatible with every situation where it might be needed.

A basic version of a VelocityBlur node is quite easy to hack up though - I've pasted a simple version implemented in OSL at the end of this email - you can paste this into Gaffer, and you'll get a box that implements a basic version of converting an object to use velocity blur. You just need to set "velocityPrimvar" to the name of a velocity primvar on your cache, and then connect a filter that targets the locations that need to be converted to velocity blur.

Caveats with this quickly thrown together node:
* it assumes the renderer is using "centered motion blur", and the shutter angle is less than 360 ( ie shutter length is less than 1 frame ). The default shutter of [-0.25, 0.25] should work fine, but it will get confused if you try with a shutter like [-0.5, 0.5] ( too long ), or [0, 0.5] ( not centered ).
* it's a bit less efficient than a C++ implementation would be

This hasn't been more of a priority because most people who have needed a node like this have either hacked up an OSL version, or have an internal node suited to their specific pipeline ( eg. I know ImageEngine has a node like this ).

It is very useful functionality to have though, even if it doesn't cover every possibility. It really is about time we implemented this as a built-in node ... but for now, hopefully this example box allows you to render your sim:

-Daniel




import Gaffer
import GafferOSL
import GafferScene
import IECore
import imath

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

__children = {}

__children["VelocityBlur"] = Gaffer.Box( "VelocityBlur" )
parent.addChild( __children["VelocityBlur"] )
__children["VelocityBlur"].addChild( GafferOSL.OSLObject( "OSLObject1" ) )
__children["VelocityBlur"]["OSLObject1"]["primitiveVariables"].addChild( Gaffer.NameValuePlug( "P", Gaffer.V3fPlug( "value", defaultValue = imath.V3f( 0, 0, 0 ), interpretation = IECore.GeometricData.Interpretation.Point ), True, "primitiveVariable", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
__children["VelocityBlur"]["OSLObject1"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferScene.FilterPlug( "filter", defaultValue = 0, minValue = 0, maxValue = 7, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferOSL.OSLCode( "OSLCode1" ) )
__children["VelocityBlur"]["OSLCode1"]["parameters"].addChild( Gaffer.V3fPlug( "velocity", defaultValue = imath.V3f( 0, 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, interpretation = IECore.GeometricData.Interpretation.Vector ) )
__children["VelocityBlur"]["OSLCode1"]["parameters"].addChild( Gaffer.FloatPlug( "frameOffset", defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"]["OSLCode1"]["parameters"].addChild( Gaffer.FloatPlug( "velocityScale", defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"]["OSLCode1"]["out"].addChild( Gaffer.V3fPlug( "outP", direction = Gaffer.Plug.Direction.Out, defaultValue = imath.V3f( 0, 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, interpretation = IECore.GeometricData.Interpretation.Vector ) )
__children["VelocityBlur"]["OSLCode1"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferOSL.OSLShader( "InVector" ) )
__children["VelocityBlur"]["InVector"].loadShader( "ObjectProcessing/InVector" )
__children["VelocityBlur"]["InVector"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.Expression( "Expression2" ) )
__children["VelocityBlur"]["Expression2"]["__out"].addChild( Gaffer.FloatPlug( "p0", direction = Gaffer.Plug.Direction.Out, defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"]["Expression2"]["__out"].addChild( Gaffer.FloatPlug( "p1", direction = Gaffer.Plug.Direction.Out, defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"]["Expression2"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.TimeWarp( "TimeWarp" ) )
__children["VelocityBlur"]["TimeWarp"].setup( GafferScene.ScenePlug( "in", ) )
__children["VelocityBlur"]["TimeWarp"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferScene.ScenePlug( "in", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferScene.MergeScenes( "MergeScenes" ) )
__children["VelocityBlur"]["MergeScenes"]["in"].resize( 3 )
__children["VelocityBlur"]["MergeScenes"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferScene.ScenePlug( "out", direction = Gaffer.Plug.Direction.Out, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoxIn( "BoxIn" ) )
__children["VelocityBlur"]["BoxIn"].setup( GafferScene.FilterPlug( "out", defaultValue = 0, minValue = 0, maxValue = 7, ) )
__children["VelocityBlur"]["BoxIn"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoxIn( "BoxIn1" ) )
__children["VelocityBlur"]["BoxIn1"].setup( GafferScene.ScenePlug( "out", ) )
__children["VelocityBlur"]["BoxIn1"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoxOut( "BoxOut" ) )
__children["VelocityBlur"]["BoxOut"].setup( GafferScene.ScenePlug( "in", ) )
__children["VelocityBlur"]["BoxOut"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoolPlug( "enabled", defaultValue = True, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( GafferScene.Isolate( "Isolate" ) )
__children["VelocityBlur"]["Isolate"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoxIn( "BoxIn2" ) )
__children["VelocityBlur"]["BoxIn2"].setup( Gaffer.FloatPlug( "out", defaultValue = 0.0, ) )
__children["VelocityBlur"]["BoxIn2"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.FloatPlug( "velocityScale", defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.BoxIn( "BoxIn3" ) )
__children["VelocityBlur"]["BoxIn3"].setup( Gaffer.StringPlug( "out", defaultValue = 'velocity', ) )
__children["VelocityBlur"]["BoxIn3"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["VelocityBlur"].addChild( Gaffer.StringPlug( "velocityPrimitiveVariable", defaultValue = 'velocity', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"], 'uiEditor:emptySections', IECore.StringVectorData( [  ] ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"], 'uiEditor:emptySectionIndices', IECore.IntVectorData( [  ] ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["user"], 'layout:section', 'User' )
__children["VelocityBlur"]["OSLObject1"]["in"].setInput( __children["VelocityBlur"]["TimeWarp"]["out"] )
__children["VelocityBlur"]["OSLObject1"]["filter"].setInput( __children["VelocityBlur"]["BoxIn"]["out"] )
__children["VelocityBlur"]["OSLObject1"]["primitiveVariables"]["primitiveVariable"]["value"].setInput( __children["VelocityBlur"]["OSLCode1"]["out"]["outP"] )
__children["VelocityBlur"]["OSLObject1"]["__uiPosition"].setValue( imath.V2f( 248.812561, 84.3298798 ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'nodule:type', 'GafferUI::StandardNodule' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'description', 'The filter used to control which parts of the scene are\nprocessed. A Filter node should be connected here.' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'noduleLayout:section', 'right' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'plugValueWidget:type', 'GafferSceneUI.FilterPlugValueWidget' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'layout:section', 'Filter' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["filter"], 'layout:index', 3 )
__children["VelocityBlur"]["OSLCode1"]["parameters"]["velocity"].setInput( __children["VelocityBlur"]["InVector"]["out"]["value"] )
__children["VelocityBlur"]["OSLCode1"]["parameters"]["frameOffset"].setInput( __children["VelocityBlur"]["Expression2"]["__out"]["p1"] )
__children["VelocityBlur"]["OSLCode1"]["parameters"]["velocityScale"].setInput( __children["VelocityBlur"]["BoxIn2"]["out"] )
__children["VelocityBlur"]["OSLCode1"]["code"].setValue( '\noutP = P + ( velocity * velocityScale *frameOffset );' )
__children["VelocityBlur"]["OSLCode1"]["__uiPosition"].setValue( imath.V2f( 235.012756, 84.170723 ) )
__children["VelocityBlur"]["InVector"]["parameters"]["name"].setInput( __children["VelocityBlur"]["BoxIn3"]["out"] )
__children["VelocityBlur"]["InVector"]["__uiPosition"].setValue( imath.V2f( 222.894104, 85.3707199 ) )
__children["VelocityBlur"]["Expression2"]["__uiPosition"].setValue( imath.V2f( 223.603882, 94.6265717 ) )
__children["VelocityBlur"]["TimeWarp"]["speed"].setValue( 0.0 )
__children["VelocityBlur"]["TimeWarp"]["offset"].setInput( __children["VelocityBlur"]["Expression2"]["__out"]["p0"] )
__children["VelocityBlur"]["TimeWarp"]["__uiPosition"].setValue( imath.V2f( 247.312561, 92.4939423 ) )
__children["VelocityBlur"]["TimeWarp"]["in"].setInput( __children["VelocityBlur"]["BoxIn1"]["out"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["TimeWarp"]["in"], 'noduleLayout:section', 'top' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["TimeWarp"]["out"], 'noduleLayout:section', 'bottom' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["in"], 'noduleLayout:section', 'top' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["in"], 'layout:section', 'Settings' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["in"], 'layout:index', 0 )
__children["VelocityBlur"]["MergeScenes"]["in"][0].setInput( __children["VelocityBlur"]["BoxIn1"]["out"] )
__children["VelocityBlur"]["MergeScenes"]["in"][1].setInput( __children["VelocityBlur"]["Isolate"]["out"] )
__children["VelocityBlur"]["MergeScenes"]["objectMode"].setValue( 1 )
__children["VelocityBlur"]["MergeScenes"]["__uiPosition"].setValue( imath.V2f( 214.647873, 68.0741196 ) )
__children["VelocityBlur"]["out"].setInput( __children["VelocityBlur"]["BoxOut"]["__out"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["out"], 'description', 'The processed output scene.' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["out"], 'nodule:type', 'GafferUI::StandardNodule' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["out"], 'layout:section', 'Settings' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["out"], 'layout:index', 1 )
__children["VelocityBlur"]["BoxIn"]["name"].setValue( 'filter' )
__children["VelocityBlur"]["BoxIn"]["__in"].setInput( __children["VelocityBlur"]["filter"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn"]["__in"], 'nodule:type', 'GafferUI::StandardNodule' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn"]["__in"], 'description', 'The filter used to control which parts of the scene are\nprocessed. A Filter node should be connected here.' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn"]["__in"], 'noduleLayout:section', 'right' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn"]["__in"], 'plugValueWidget:type', 'GafferSceneUI.FilterPlugValueWidget' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn"]["out"], 'noduleLayout:section', 'left' )
__children["VelocityBlur"]["BoxIn"]["__uiPosition"].setValue( imath.V2f( 279.794495, 87.9299088 ) )
__children["VelocityBlur"]["BoxIn1"]["__in"].setInput( __children["VelocityBlur"]["in"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn1"]["__in"], 'noduleLayout:section', 'top' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn1"]["out"], 'noduleLayout:section', 'bottom' )
__children["VelocityBlur"]["BoxIn1"]["__uiPosition"].setValue( imath.V2f( 214.647873, 100.825974 ) )
__children["VelocityBlur"]["BoxOut"]["in"].setInput( __children["VelocityBlur"]["MergeScenes"]["out"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxOut"]["__out"], 'description', 'The processed output scene.' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxOut"]["__out"], 'nodule:type', 'GafferUI::StandardNodule' )
__children["VelocityBlur"]["BoxOut"]["passThrough"].setInput( __children["VelocityBlur"]["BoxIn1"]["out"] )
__children["VelocityBlur"]["BoxOut"]["enabled"].setInput( __children["VelocityBlur"]["enabled"] )
__children["VelocityBlur"]["BoxOut"]["__uiPosition"].setValue( imath.V2f( 216.147873, 57.4523201 ) )
__children["VelocityBlur"]["__uiPosition"].setValue( imath.V2f( 226.754227, 80.5332108 ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["__uiPosition"], 'layout:section', 'Settings' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["enabled"], 'layout:section', 'Node' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["enabled"], 'layout:index', 4 )
__children["VelocityBlur"]["Isolate"]["in"].setInput( __children["VelocityBlur"]["OSLObject1"]["out"] )
__children["VelocityBlur"]["Isolate"]["filter"].setInput( __children["VelocityBlur"]["BoxIn"]["out"] )
__children["VelocityBlur"]["Isolate"]["__uiPosition"].setValue( imath.V2f( 248.812561, 76.1658173 ) )
__children["VelocityBlur"]["BoxIn2"]["name"].setValue( 'velocityScale' )
__children["VelocityBlur"]["BoxIn2"]["__in"].setInput( __children["VelocityBlur"]["velocityScale"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn2"]["__in"], 'noduleLayout:section', 'left' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn2"]["__in"], 'label', 'velocityScale' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn2"]["__in"], 'description', '' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn2"]["__in"], 'noduleLayout:visible', True )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn2"]["out"], 'noduleLayout:section', 'right' )
__children["VelocityBlur"]["BoxIn2"]["__uiPosition"].setValue( imath.V2f( 217.11116, 79.3658905 ) )
__children["VelocityBlur"]["velocityScale"].setValue( 1.0 )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'noduleLayout:section', 'left' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'description', '' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'noduleLayout:visible', True )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'layout:section', 'Settings' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'layout:index', 2 )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityScale"], 'nodule:type', '' )
__children["VelocityBlur"]["BoxIn3"]["name"].setValue( 'velocityPrimitiveVariable' )
__children["VelocityBlur"]["BoxIn3"]["__in"].setInput( __children["VelocityBlur"]["velocityPrimitiveVariable"] )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn3"]["__in"], 'noduleLayout:section', 'left' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn3"]["__in"], 'description', '' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn3"]["__in"], 'noduleLayout:visible', True )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["BoxIn3"]["out"], 'noduleLayout:section', 'right' )
__children["VelocityBlur"]["BoxIn3"]["__uiPosition"].setValue( imath.V2f( 207.637039, 85.9714661 ) )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityPrimitiveVariable"], 'noduleLayout:section', 'left' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityPrimitiveVariable"], 'description', '' )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityPrimitiveVariable"], 'noduleLayout:visible', True )
Gaffer.Metadata.registerValue( __children["VelocityBlur"]["velocityPrimitiveVariable"], 'nodule:type', '' )
__children["VelocityBlur"]["Expression2"]["__engine"].setValue( 'OSL' )
__children["VelocityBlur"]["Expression2"]["__expression"].setValue( '\nfloat f = context("frame");\nfloat intF = round( f );\n\nparent.__out.p0 = intF;\nparent.__out.p1 = f - intF;' )


del __children

s.des...@gmail.com

unread,
Nov 26, 2025, 3:29:55 AM (9 days ago) Nov 26
to gaffer-dev
Hello Daniel,

Thank you very much for this velocity setup, It works fine !
You rock !

Seb
Reply all
Reply to author
Forward
0 new messages