Skip to content

Commit

Permalink
Merge pull request #5817 from johnhaddon/arrayScalarConversions
Browse files Browse the repository at this point in the history
PlugAlgo : Add `array[1]` -> scalar conversion
  • Loading branch information
johnhaddon authored Apr 25, 2024
2 parents 6939708 + c27398f commit 4de8e31
Show file tree
Hide file tree
Showing 6 changed files with 478 additions and 29 deletions.
7 changes: 7 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ Improvements

- TweakPlug : `ListAppend`, `ListPrepend` and `ListRemove` modes are now supported for string values. In this case, the string is treated as a space-separated list.
- Cycles : Changed default value for `principled_bsdf.specular_ior_level` to `0.5`, matching Blender.
- AttributeQuery, PrimitiveVariableQuery, ContextQuery, OptionQuery, ShaderQuery : Added support for querying arrays of length 1 as their equivalent scalar types.

Fixes
-----

- Viewer : Fixed Cycles shader balls.
- TweakPlug : Fixed incorrect results and potential crashes in list modes.

API
---

- PlugAlgo : `setValueFromData()` and `canSetValueFromData()` now support conversion of arrays of length 1 to their equivalent scalar types.
- BoxPlug : Added Python bindings for `ValueType`, `PointType` and `ChildType` type aliases.

1.4.1.0 (relative to 1.4.0.0)
=======

Expand Down
33 changes: 32 additions & 1 deletion python/GafferSceneTest/PrimitiveVariableQueryTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,5 +689,36 @@ def testSerialisation( self ) :
self.assertEqual( output["type"].getValue(), dataType.staticTypeName() )
self.assertEqual( output["value"].getValue(), value )

def testArrayScalarConversion( self ) :

cube = GafferScene.Cube()

cubeFilter = GafferScene.PathFilter()
cubeFilter["paths"].setValue( IECore.StringVectorData( [ "/cube" ] ) )

primitiveVariables = GafferScene.PrimitiveVariables()
primitiveVariables["in"].setInput( cube["out"] )
primitiveVariables["filter"].setInput( cubeFilter["out"] )

primitiveVariables["primitiveVariables"].addChild( Gaffer.NameValuePlug( "testLengthZero", IECore.IntVectorData() ) )
primitiveVariables["primitiveVariables"].addChild( Gaffer.NameValuePlug( "testLengthOne", IECore.IntVectorData( [ 2 ] ) ) )
primitiveVariables["primitiveVariables"].addChild( Gaffer.NameValuePlug( "testLengthTwo", IECore.IntVectorData( [ 3, 3 ] ) ) )

query = GafferScene.PrimitiveVariableQuery()
query["scene"].setInput( primitiveVariables["out"] )
query["location"].setValue( "/cube" )
query.addQuery( Gaffer.IntPlug( defaultValue = -1 ), "testLengthZero" )

self.assertEqual( query["out"][0]["exists"].getValue(), True )
self.assertTrue( query["out"][0]["value"].getValue(), -1 )

query["queries"][0]["name"].setValue( "testLengthOne" )
self.assertEqual( query["out"][0]["exists"].getValue(), True )
self.assertTrue( query["out"][0]["value"].getValue(), 2 )

query["queries"][0]["name"].setValue( "testLengthTwo" )
self.assertEqual( query["out"][0]["exists"].getValue(), True )
self.assertTrue( query["out"][0]["value"].getValue(), -1 )

if __name__ == "__main__":
unittest.main()
unittest.main()
6 changes: 6 additions & 0 deletions python/GafferTest/BoxPlugTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,11 @@ def assertExpectedInputs( numSetInputCalls ) :
s["n"]["user"]["b2"].setInput( s["n"]["user"]["b1"] )
assertExpectedInputs( 1 )

def testTypes( self ) :

self.assertIs( Gaffer.Box3fPlug.ValueType, imath.Box3f )
self.assertIs( Gaffer.Box3fPlug.PointType, imath.V3f )
self.assertIs( Gaffer.Box3fPlug.ChildType, Gaffer.V3fPlug )

if __name__ == "__main__":
unittest.main()
222 changes: 219 additions & 3 deletions python/GafferTest/PlugAlgoTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,9 +929,6 @@ def testCanSetPlugFromValueWithType( self ) :

def testDataConversionsForAllTypes( self ) :

import GafferScene
import GafferImage

for plugType in Gaffer.ValuePlug.__subclasses__() :

valueType = getattr( plugType, "ValueType", None )
Expand Down Expand Up @@ -961,6 +958,225 @@ def testDataConversionsForAllTypes( self ) :
self.assertEqual( plug.getValue(), data.value )
self.assertEqual( Gaffer.PlugAlgo.getValueAsData( plug ), data )

def testSetNumericValueFromVectorData( self ) :

for plugType in Gaffer.FloatPlug, Gaffer.IntPlug, Gaffer.BoolPlug :
plug = plugType()
for dataType in [
IECore.HalfVectorData,
IECore.FloatVectorData,
IECore.DoubleVectorData,
IECore.UCharVectorData,
IECore.ShortVectorData,
IECore.UShortVectorData,
IECore.IntVectorData,
IECore.UIntVectorData,
IECore.Int64VectorData,
IECore.UInt64VectorData,
IECore.BoolVectorData,
] :
with self.subTest( plugType = plugType, dataType = dataType ) :
for value in ( 0, 1 ) :
data = dataType()
# Array length 0, can't set.
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )
# Array length 1, can set.
data.append( value )
self.assertTrue( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertTrue( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertEqual( plug.getValue(), value )
# Array length > 1, can't set.
data.append( value )
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )

def testSetCompoundNumericValueFromVectorData( self ) :

for plugType in [
Gaffer.Color3fPlug, Gaffer.Color4fPlug,
Gaffer.V3fPlug, Gaffer.V3iPlug,
Gaffer.V2fPlug, Gaffer.V2iPlug
] :

plug = plugType()
for dataType in [
IECore.Color3fVectorData,
IECore.Color4fVectorData,
IECore.V3fVectorData,
IECore.V3iVectorData,
IECore.V2fVectorData,
IECore.V2iVectorData,
IECore.FloatVectorData,
IECore.IntVectorData,
IECore.BoolVectorData,
] :
with self.subTest( plugType = plugType, dataType = dataType ) :

data = dataType()

# Array length 0, can't set.

self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )
for childPlug in Gaffer.Plug.Range( plug ) :
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, childPlug, data ) )
self.assertTrue( plug.isSetToDefault() )

# Array length 1, can set.

data.resize( 1 )
value = data[0]
if hasattr( value, "dimensions" ) :
# e.g. `V3f( 1, 2, 3 )`
for i in range( 0, value.dimensions() ) :
value[i] = i + 1
else :
# e.g `2`, `2.0`, or `True`
value = type( value )( 2 )
data[0] = value

self.assertTrue( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertTrue( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
for i, childPlug in enumerate( plug ) :
if hasattr( value, "dimensions" ) :
if i < value.dimensions() :
self.assertEqual( childPlug.getValue(), value[i] )
else :
self.assertEqual( childPlug.getValue(), 1 if i == 3 else 0 )
else :
self.assertEqual( childPlug.getValue(), 1 if i == 3 else value )

# And can also set a component at a time.

plug.setToDefault()
for i, childPlug in enumerate( plug ) :
Gaffer.PlugAlgo.setValueFromData( plug, childPlug, data )
if hasattr( value, "dimensions" ) :
if i < value.dimensions() :
self.assertEqual( childPlug.getValue(), value[i] )
else :
self.assertEqual( childPlug.getValue(), 1 if i == 3 else 0 )
else :
self.assertEqual( childPlug.getValue(), 1 if i == 3 else value )

# Array length > 1, can't set.

data.append( data[0] )

self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )
for childPlug in plug :
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, childPlug, data ) )
self.assertTrue( childPlug.isSetToDefault() )
self.assertTrue( plug.isSetToDefault() )

def testSetTypedValueFromVectorData( self ) :

for plugType, value in [
( Gaffer.StringPlug, "test" ),
( Gaffer.StringPlug, IECore.InternedString( "test" ) ),
( Gaffer.M33fPlug, imath.M33f( 1 ) ),
( Gaffer.M44fPlug, imath.M44f( 1 ) ),
( Gaffer.AtomicBox2fPlug, imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ) ),
( Gaffer.AtomicBox3fPlug, imath.Box3f( imath.V3f( 0 ), imath.V3f( 1 ) ) ),
( Gaffer.AtomicBox2iPlug, imath.Box2i( imath.V2i( 0 ), imath.V2i( 1 ) ) ),
] :

with self.subTest( plugType = plugType, value = value ) :

plug = plugType()
data = IECore.DataTraits.dataFromElement( [ value ] )
self.assertEqual( len( data ), 1 )

# Array length 1, can set

self.assertTrue( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertTrue( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertEqual( plug.getValue(), value )
self.assertFalse( plug.isSetToDefault() )

# Array length 2, can't set

data.append( data[0] )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )

# Array length 0, can't set

data.resize( 0 )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )

def testSetBoxValueFromVectorData( self ) :

for plugType in [
Gaffer.Box2fPlug, Gaffer.Box3fPlug,
Gaffer.Box2iPlug, Gaffer.Box3iPlug,
] :

with self.subTest( plugType = plugType ) :

plug = plugType()

minValue = plugType.PointType()
maxValue = plugType.PointType()
for i in range( 0, minValue.dimensions() ) :
minValue[i] = i
maxValue[i] = i + 1
value = plugType.ValueType( minValue, maxValue )
data = IECore.DataTraits.dataFromElement( [ value ] )

# Array length 1, can set

self.assertTrue( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )
self.assertTrue( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertEqual( plug.getValue(), value )
self.assertFalse( plug.isSetToDefault() )

# And can set individual children

plug.setToDefault()
for childPlug in plug :
for componentPlug in childPlug :
self.assertTrue( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertEqual( plug.getValue(), value )
self.assertFalse( plug.isSetToDefault() )

# Array length 2, can't set

data.append( data[0] )
plug.setToDefault()
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
for childPlug in plug :
for componentPlug in childPlug :
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )

# Array length 0, can't set

data.resize( 0 )
self.assertFalse( Gaffer.PlugAlgo.canSetValueFromData( plug, data ) )
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
for childPlug in plug :
for componentPlug in childPlug :
self.assertFalse( Gaffer.PlugAlgo.setValueFromData( plug, data ) )
self.assertTrue( plug.isSetToDefault() )

def testDependsOnCompute( self ) :

add = GafferTest.AddNode()
Expand Down
Loading

0 comments on commit 4de8e31

Please sign in to comment.