Skip to content

Commit

Permalink
Merge pull request #2113 from donboie/OSLObjectInterpolation
Browse files Browse the repository at this point in the history
OSLObject FaceVarying and Uniform interpolation
  • Loading branch information
donboie committed Jun 7, 2017
2 parents 2e7e0ce + 2fd2c43 commit 42365f2
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 20 deletions.
14 changes: 14 additions & 0 deletions include/GafferOSL/OSLObject.h
Expand Up @@ -39,6 +39,8 @@

#include "GafferScene/SceneElementProcessor.h"
#include "GafferScene/ShaderPlug.h"
#include "Gaffer/NumericPlug.h"
#include "Gaffer/StringPlug.h"

#include "GafferOSL/TypeIds.h"

Expand All @@ -58,6 +60,9 @@ class OSLObject : public GafferScene::SceneElementProcessor
GafferScene::ShaderPlug *shaderPlug();
const GafferScene::ShaderPlug *shaderPlug() const;

Gaffer::IntPlug *interpolationPlug();
const Gaffer::IntPlug *interpolationPlug() const;

virtual void affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const;

protected :
Expand All @@ -72,8 +77,17 @@ class OSLObject : public GafferScene::SceneElementProcessor
virtual void hashProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const;
virtual IECore::ConstObjectPtr computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const;

virtual void hash( const Gaffer::ValuePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const;
virtual void compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const;

private :

GafferScene::ScenePlug *resampledInPlug();
const GafferScene::ScenePlug *resampledInPlug() const;

Gaffer::StringPlug *resampledNamesPlug();
const Gaffer::StringPlug *resampledNamesPlug() const;

static size_t g_firstPlugIndex;

};
Expand Down
199 changes: 199 additions & 0 deletions python/GafferOSLTest/OSLObjectTest.py
Expand Up @@ -236,5 +236,204 @@ def testReferencePromotedPlug( self ) :

s["r"]["p"].setInput( s["s"]["out"] )

def testCanShadeVertexInterpolatedPrimitiveVariablesAsUniform( self ) :

s = Gaffer.ScriptNode()

c = GafferScene.Cube()
s.addChild( c )

o = GafferOSL.OSLObject()
s.addChild( o )

f = GafferScene.PathFilter( "PathFilter" )
s.addChild( f )
f["paths"].setValue( IECore.StringVectorData( [ '/cube' ] ) )
o["filter"].setInput( f["out"] )

# ensure the source position primitive variable interpolation is set to Vertex
self.assertEqual(c["out"].object("/cube")['P'].interpolation, IECore.PrimitiveVariable.Interpolation.Vertex )

o['in'].setInput( c["out"] )
o['interpolation'].setValue( IECore.PrimitiveVariable.Interpolation.Uniform )

inPoint = GafferOSL.OSLShader( "InPoint" )
s.addChild( inPoint )
inPoint.loadShader( "ObjectProcessing/InPoint" )

vectorAdd = GafferOSL.OSLShader( "VectorAdd" )
s.addChild( vectorAdd )
vectorAdd.loadShader( "Maths/VectorAdd" )
vectorAdd["parameters"]["b"].setValue( IECore.V3f( 1, 2, 3 ) )

vectorAdd["parameters"]["a"].setInput( inPoint["out"]["value"] )

outPoint = GafferOSL.OSLShader( "OutPoint" )
s.addChild( outPoint )
outPoint.loadShader( "ObjectProcessing/OutPoint" )
outPoint['parameters']['name'].setValue("P_copy")

outPoint["parameters"]["value"].setInput( vectorAdd["out"]["out"] )

outObject = GafferOSL.OSLShader( "OutObject" )
s.addChild( outObject )
outObject.loadShader( "ObjectProcessing/OutObject" )
outObject["parameters"]["in0"].setInput( outPoint["out"]["primitiveVariable"] )

o["shader"].setInput( outObject["out"] )

cubeObject = s['OSLObject']['out'].object( "/cube" )

self.assertTrue( "P_copy" in cubeObject.keys() )
self.assertEqual( cubeObject["P_copy"].interpolation, IECore.PrimitiveVariable.Interpolation.Uniform)

self.assertEqual( cubeObject["P_copy"].data[0], IECore.V3f( 0.0, 0.0, -0.5 ) + IECore.V3f( 1, 2, 3 ))
self.assertEqual( cubeObject["P_copy"].data[1], IECore.V3f( 0.5, 0.0, 0.0 ) + IECore.V3f( 1, 2, 3 ))
self.assertEqual( cubeObject["P_copy"].data[2], IECore.V3f( 0.0, 0.0, 0.5 ) + IECore.V3f( 1, 2, 3 ))
self.assertEqual( cubeObject["P_copy"].data[3], IECore.V3f( -0.5, 0.0, 0.0 ) + IECore.V3f( 1, 2, 3 ))
self.assertEqual( cubeObject["P_copy"].data[4], IECore.V3f( 0.0, 0.5, 0.0 ) + IECore.V3f( 1, 2, 3 ))
self.assertEqual( cubeObject["P_copy"].data[5], IECore.V3f( 0.0, -0.5, 0.0 ) + IECore.V3f( 1, 2, 3 ))

def testCanShadeFaceVaryingInterpolatedPrimitiveVariablesAsVertex( self ) :

s = Gaffer.ScriptNode()

p = GafferScene.Plane()
p["divisions"].setValue( IECore.V2i( 2, 2 ) ) # 2x2 plane = 4 quads & 9 vertices
s.addChild( p )

o = GafferOSL.OSLObject()
s.addChild( o )

f = GafferScene.PathFilter( "PathFilter" )
s.addChild( f )
f["paths"].setValue( IECore.StringVectorData( [ '/plane' ] ) )
o["filter"].setInput( f["out"] )

# ensure the source primvars are face varying
self.assertEqual(p["out"].object("/plane")['s'].interpolation, IECore.PrimitiveVariable.Interpolation.FaceVarying )
self.assertEqual(p["out"].object("/plane")['t'].interpolation, IECore.PrimitiveVariable.Interpolation.FaceVarying )

o['in'].setInput( p["out"] )
o['interpolation'].setValue( IECore.PrimitiveVariable.Interpolation.Vertex )

inS = GafferOSL.OSLShader( "InFloat" )
s.addChild( inS )
inS.loadShader( "ObjectProcessing/InFloat" )
inS['parameters']['name'].setValue('s')

inT = GafferOSL.OSLShader( "InFloat" )
s.addChild( inT )
inT.loadShader( "ObjectProcessing/InFloat" )
inT['parameters']['name'].setValue('t')

floatAdd = GafferOSL.OSLShader( "FloatAdd" )
s.addChild( floatAdd )
floatAdd.loadShader( "Maths/FloatAdd" )

floatAdd["parameters"]["a"].setInput( inT["out"]["value"] )
floatAdd["parameters"]["b"].setInput( inS["out"]["value"] )

outFloat = GafferOSL.OSLShader( "OutFloat" )
s.addChild( outFloat )
outFloat.loadShader( "ObjectProcessing/OutFloat" )
outFloat['parameters']['name'].setValue("st_add")

outFloat["parameters"]["value"].setInput( floatAdd["out"]["out"] )

outObject = GafferOSL.OSLShader( "OutObject" )
s.addChild( outObject )
outObject.loadShader( "ObjectProcessing/OutObject" )
outObject["parameters"]["in0"].setInput( outFloat["out"]["primitiveVariable"] )

o["shader"].setInput( outObject["out"] )

planeObject = s['OSLObject']['out'].object( "/plane" )

self.assertTrue( "st_add" in planeObject.keys() )
self.assertEqual( planeObject["st_add"].interpolation, IECore.PrimitiveVariable.Interpolation.Vertex)

# note our plane origin position (0,0,0) has a UV (0,1) because of 1.0 - t convention in cortex.
self.assertEqual( planeObject["st_add"].data[0], 0.0 + 1.0)
self.assertEqual( planeObject["st_add"].data[1], 0.5 + 1.0)
self.assertEqual( planeObject["st_add"].data[2], 1.0 + 1.0)
self.assertEqual( planeObject["st_add"].data[3], 0.0 + 0.5)
self.assertEqual( planeObject["st_add"].data[4], 0.5 + 0.5)
self.assertEqual( planeObject["st_add"].data[5], 1.0 + 0.5)
self.assertEqual( planeObject["st_add"].data[6], 0.0 + 0.0)
self.assertEqual( planeObject["st_add"].data[7], 0.5 + 0.0)
self.assertEqual( planeObject["st_add"].data[8], 1.0 + 0.0)


def testCanReadFromConstantPrimitiveVariables( self ) :

s = Gaffer.ScriptNode()

p = GafferScene.Plane()
p["divisions"].setValue( IECore.V2i( 2, 2 ) ) # 2x2 plane = 4 quads & 9 vertices
s.addChild( p )

o = GafferOSL.OSLObject()
s.addChild( o )

f = GafferScene.PathFilter( "PathFilter" )
s.addChild( f )
f["paths"].setValue( IECore.StringVectorData( [ '/plane' ] ) )
o["filter"].setInput( f["out"] )


pv = GafferScene.PrimitiveVariables( "PrimitiveVariables" )
s.addChild( pv )

pv["primitiveVariables"].addChild( Gaffer.CompoundDataPlug.MemberPlug( "member1", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
pv["primitiveVariables"]["member1"].addChild( Gaffer.StringPlug( "name", defaultValue = '', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
pv["primitiveVariables"]["member1"]["name"].setValue( 'const_foo' )
pv["primitiveVariables"]["member1"].addChild( Gaffer.FloatPlug( "value", defaultValue = 0.0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
pv["primitiveVariables"]["member1"]["value"].setValue( 1 )
pv["primitiveVariables"]["member1"].addChild( Gaffer.BoolPlug( "enabled", defaultValue = True, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )

pv["in"].setInput( p["out"] )
pv["filter"].setInput( f["out"] )

o['in'].setInput( pv["out"] )
o['interpolation'].setValue( IECore.PrimitiveVariable.Interpolation.Vertex )

inConstFoo = GafferOSL.OSLShader( "InFloat" )
s.addChild( inConstFoo )
inConstFoo.loadShader( "ObjectProcessing/InFloat" )
inConstFoo['parameters']['name'].setValue('const_foo')


outFloat = GafferOSL.OSLShader( "OutFloat" )
s.addChild( outFloat )
outFloat.loadShader( "ObjectProcessing/OutFloat" )
outFloat['parameters']['name'].setValue("out_foo")

outFloat["parameters"]["value"].setInput( inConstFoo["out"]["value"] )

outObject = GafferOSL.OSLShader( "OutObject" )
s.addChild( outObject )
outObject.loadShader( "ObjectProcessing/OutObject" )
outObject["parameters"]["in0"].setInput( outFloat["out"]["primitiveVariable"] )

o["shader"].setInput( outObject["out"] )

planeObject = s['OSLObject']['out'].object( "/plane" )

self.assertTrue( "out_foo" in planeObject.keys() )
self.assertEqual( planeObject["out_foo"].interpolation, IECore.PrimitiveVariable.Interpolation.Vertex)

self.assertEqual( planeObject["out_foo"].data[0], 1)
self.assertEqual( planeObject["out_foo"].data[1], 1)
self.assertEqual( planeObject["out_foo"].data[2], 1)
self.assertEqual( planeObject["out_foo"].data[3], 1)
self.assertEqual( planeObject["out_foo"].data[4], 1)
self.assertEqual( planeObject["out_foo"].data[5], 1)
self.assertEqual( planeObject["out_foo"].data[6], 1)
self.assertEqual( planeObject["out_foo"].data[7], 1)
self.assertEqual( planeObject["out_foo"].data[8], 1)

if __name__ == "__main__":
unittest.main()


19 changes: 19 additions & 0 deletions python/GafferOSLUI/OSLObjectUI.py
Expand Up @@ -34,6 +34,7 @@
#
##########################################################################

import IECore
import Gaffer
import GafferUI

Expand Down Expand Up @@ -70,7 +71,25 @@
"noduleLayout:section", "left",

],
"interpolation" : [

"description",
"""
The interpolation type of the primitive variables created by this node.
For instance, Uniform interpolation means that the shader is run once per face on a mesh, allowing it to output primitive variables with a value per face.
All non-constant input primitive variables are resampled to match the selected interpolation so that they can be accessed from the shader.
""",

"preset:Uniform", IECore.PrimitiveVariable.Interpolation.Uniform,
"preset:Vertex", IECore.PrimitiveVariable.Interpolation.Vertex,
"preset:FaceVarying", IECore.PrimitiveVariable.Interpolation.FaceVarying,

"plugValueWidget:type", "GafferUI.PresetsPlugValueWidget",


]

}

)

0 comments on commit 42365f2

Please sign in to comment.