Ejemplo n.º 1
0
    def testManyImages(self):

        allFilter = GafferScene.PathFilter()
        allFilter["paths"].setValue(IECore.StringVectorData(['/...']))

        sphere = GafferScene.Sphere()
        sphere["transform"]["translate"].setValue(imath.V3f(-3, 0, 0))

        standardSurface = GafferArnold.ArnoldShader()
        standardSurface.loadShader("standard_surface")

        shaderAssignment = GafferScene.ShaderAssignment()
        shaderAssignment["in"].setInput(sphere["out"])
        shaderAssignment["filter"].setInput(allFilter["out"])
        shaderAssignment["shader"].setInput(standardSurface["out"])

        uvScaleCode = GafferOSL.OSLCode()
        uvScaleCode["out"].addChild(
            Gaffer.V3fPlug("uvScaled", direction=Gaffer.Plug.Direction.Out))
        uvScaleCode["code"].setValue('uvScaled = vector( u * 2, v * 2, 0 );')

        outUV = GafferOSL.OSLShader()
        outUV.loadShader("ObjectProcessing/OutUV")
        outUV["parameters"]["value"].setInput(uvScaleCode["out"]["uvScaled"])

        outObject2 = GafferOSL.OSLShader()
        outObject2.loadShader("ObjectProcessing/OutObject")
        outObject2["parameters"]["in0"].setInput(
            outUV["out"]["primitiveVariable"])

        uvScaleOSL = GafferOSL.OSLObject()
        uvScaleOSL["in"].setInput(shaderAssignment["out"])
        uvScaleOSL["filter"].setInput(allFilter["out"])
        uvScaleOSL["shader"].setInput(outObject2["out"]["out"])
        uvScaleOSL["interpolation"].setValue(5)

        mapOffset = GafferScene.MapOffset()
        mapOffset["in"].setInput(uvScaleOSL["out"])
        mapOffset["filter"].setInput(allFilter["out"])
        mapOffset["udim"].setValue(1033)

        offsetGroup = GafferScene.Group()
        offsetGroup["in"]["in0"].setInput(mapOffset["out"])
        offsetGroup["name"].setValue('offset')
        offsetGroup["transform"]["translate"].setValue(imath.V3f(6, 0, 3))

        combineGroup = GafferScene.Group()
        combineGroup["in"]["in0"].setInput(uvScaleOSL["out"])
        combineGroup["in"]["in1"].setInput(offsetGroup["out"])

        lights = []
        for color, rotate in [((1, 0, 0), (0, 0, 0)), ((0, 1, 0), (0, 90, 0)),
                              ((0, 0, 1), (-90, 0, 0))]:
            light = GafferArnold.ArnoldLight()
            light.loadShader("distant_light")
            light["parameters"]["color"].setValue(imath.Color3f(*color))
            light["transform"]["rotate"].setValue(imath.V3f(*rotate))
            combineGroup["in"][-1].setInput(light["out"])
            lights.append(light)

        arnoldTextureBake = GafferArnold.ArnoldTextureBake()
        arnoldTextureBake["in"].setInput(combineGroup["out"])
        arnoldTextureBake["filter"].setInput(allFilter["out"])
        arnoldTextureBake["bakeDirectory"].setValue(self.temporaryDirectory() +
                                                    '/bakeSpheres/')
        arnoldTextureBake["defaultResolution"].setValue(32)
        arnoldTextureBake["aovs"].setValue('beauty:RGBA diffuse:diffuse')
        arnoldTextureBake["tasks"].setValue(3)
        arnoldTextureBake["cleanupIntermediateFiles"].setValue(True)

        # Dispatch the bake
        script = Gaffer.ScriptNode()
        script.addChild(arnoldTextureBake)
        dispatcher = GafferDispatch.LocalDispatcher()
        dispatcher["jobsDirectory"].setValue(self.temporaryDirectory())
        dispatcher.dispatch([arnoldTextureBake])

        # Test that we are writing all expected files, and that we have cleaned up all temp files
        expectedUdims = [i + j for j in [1001, 1033] for i in [0, 1, 10, 11]]
        self.assertEqual(
            sorted(os.listdir(self.temporaryDirectory() + '/bakeSpheres/')),
            ["beauty", "diffuse"])
        self.assertEqual(
            sorted(
                os.listdir(self.temporaryDirectory() + '/bakeSpheres/beauty')),
            ["beauty.%i.tx" % i for i in expectedUdims])
        self.assertEqual(
            sorted(
                os.listdir(self.temporaryDirectory() +
                           '/bakeSpheres/diffuse')),
            ["diffuse.%i.tx" % i for i in expectedUdims])

        # Read back in the 4 udim tiles of a sphere

        reader = GafferImage.ImageReader()

        imageTransform = GafferImage.ImageTransform()
        imageTransform["in"].setInput(reader["out"])

        exprBox = Gaffer.Box()
        expression = Gaffer.Expression()
        exprBox.addChild(reader)
        exprBox.addChild(imageTransform)
        exprBox.addChild(expression)
        expression.setExpression(
            inspect.cleandoc(
                """
			i = context.get( "loop:index", 0 )
			layer = context.get( "collect:layerName", "beauty" )
			x = i % 2
			y = i // 2
			parent["ImageReader"]["fileName"] = '""" + self.temporaryDirectory() +
                """/bakeSpheres/%s/%s.%i.tx' % ( layer, layer, 1001 + x + y * 10 )

			parent["ImageTransform"]["transform"]["translate"] = imath.V2f( 32 * x, 32 * y )
			"""), "python")

        udimLoop = Gaffer.Loop()
        udimLoop.setup(GafferImage.ImagePlug())
        udimLoop["iterations"].setValue(4)

        udimMerge = GafferImage.Merge()
        udimMerge["in"]["in0"].setInput(imageTransform["out"])
        udimMerge["in"]["in1"].setInput(udimLoop["previous"])

        udimLoop["next"].setInput(udimMerge["out"])

        aovCollect = GafferImage.CollectImages()
        aovCollect["in"].setInput(udimLoop["out"])
        aovCollect["rootLayers"].setValue(
            IECore.StringVectorData(['beauty', 'diffuse']))

        # We have a little reference image for how the diffuse should look
        imageReaderRef = GafferImage.ImageReader()
        imageReaderRef["fileName"].setValue(
            os.path.dirname(__file__) + "/images/sphereLightBake.exr")

        resizeRef = GafferImage.Resize()
        resizeRef["in"].setInput(imageReaderRef["out"])
        resizeRef["format"].setValue(GafferImage.Format(64, 64, 1.000))

        shuffleRef = GafferImage.Shuffle()
        shuffleRef["in"].setInput(resizeRef["out"])
        for layer in ["beauty", "diffuse"]:
            for channel in ["R", "G", "B"]:
                shuffleRef["channels"].addChild(
                    GafferImage.Shuffle.ChannelPlug())
                shuffleRef["channels"][-1]["in"].setValue(channel)
                shuffleRef["channels"][-1]["out"].setValue(layer + "." +
                                                           channel)

        differenceMerge = GafferImage.Merge()
        differenceMerge["in"]["in0"].setInput(aovCollect["out"])
        differenceMerge["in"]["in1"].setInput(shuffleRef["out"])
        differenceMerge["operation"].setValue(
            GafferImage.Merge.Operation.Difference)

        stats = GafferImage.ImageStats()
        stats["in"].setInput(differenceMerge["out"])
        stats["area"].setValue(imath.Box2i(imath.V2i(0, 0), imath.V2i(64, 64)))

        # We should get a very close match to our single tile low res reference bake
        stats["channels"].setValue(
            IECore.StringVectorData(
                ['diffuse.R', 'diffuse.G', 'diffuse.B', 'diffuse.A']))
        for i in range(3):
            self.assertLess(stats["average"].getValue()[i], 0.002)
            self.assertLess(stats["max"].getValue()[i], 0.02)

        # The beauty should be mostly a close match, but with a high max difference due to the spec pings
        stats["channels"].setValue(
            IECore.StringVectorData(
                ['beauty.R', 'beauty.G', 'beauty.B', 'beauty.A']))
        for i in range(3):
            self.assertLess(stats["average"].getValue()[i], 0.1)
            self.assertGreater(stats["max"].getValue()[i], 0.3)
Ejemplo n.º 2
0
    def _createPointLight(self):

        light = GafferArnold.ArnoldLight()
        light.loadShader("point_light")
        return light, light["parameters"]["color"]
Ejemplo n.º 3
0
	def testLightAndShadowLinking( self ) :

		sphere1 = GafferScene.Sphere()
		sphere2 = GafferScene.Sphere()

		attributes = GafferScene.StandardAttributes()
		arnoldAttributes = GafferArnold.ArnoldAttributes()

		light1 = GafferArnold.ArnoldLight()
		light1.loadShader( "point_light" )

		light2 = GafferArnold.ArnoldLight()
		light2.loadShader( "point_light" )

		group = GafferScene.Group()

		render = GafferArnold.ArnoldRender()

		attributes["in"].setInput( sphere1["out"] )
		arnoldAttributes["in"].setInput( attributes["out"] )
		group["in"][0].setInput( arnoldAttributes["out"] )
		group["in"][1].setInput( light1["out"] )
		group["in"][2].setInput( light2["out"] )
		group["in"][3].setInput( sphere2["out"] )

		render["in"].setInput( group["out"] )

		# Illumination
		attributes["attributes"]["linkedLights"]["enabled"].setValue( True )
		attributes["attributes"]["linkedLights"]["value"].setValue( "/group/light" )

		# Shadows
		arnoldAttributes["attributes"]["shadowGroup"]["enabled"].setValue( True )
		arnoldAttributes["attributes"]["shadowGroup"]["value"].setValue( "/group/light1" )

		render["mode"].setValue( render.Mode.SceneDescriptionMode )
		render["fileName"].setValue( self.temporaryDirectory() + "/test.ass" )
		render["task"].execute()

		with IECoreArnold.UniverseBlock( writable = True ) :

			arnold.AiASSLoad( self.temporaryDirectory() + "/test.ass" )

			# the first sphere had linked lights
			sphere = arnold.AiNodeLookUpByName( "/group/sphere" )

			# check illumination
			self.assertTrue( arnold.AiNodeGetBool( sphere, "use_light_group" ) )
			lights = arnold.AiNodeGetArray( sphere, "light_group" )
			self.assertEqual( arnold.AiArrayGetNumElements( lights ), 1 )
			self.assertEqual(
				arnold.AiNodeGetName( arnold.AiArrayGetPtr( lights, 0 ) ),
				"light:/group/light"
			)

			# check shadows
			self.assertTrue( arnold.AiNodeGetBool( sphere, "use_shadow_group" ) )
			shadows = arnold.AiNodeGetArray( sphere, "shadow_group" )
			self.assertEqual( arnold.AiArrayGetNumElements( shadows ), 1 )
			self.assertEqual(
				arnold.AiNodeGetName( arnold.AiArrayGetPtr( shadows, 0 ) ),
				"light:/group/light1"
			)

			# the second sphere does not have any light linking enabled
			sphere1 = arnold.AiNodeLookUpByName( "/group/sphere1" )

			# check illumination
			self.assertFalse( arnold.AiNodeGetBool( sphere1, "use_light_group" ) )
			lights = arnold.AiNodeGetArray( sphere1, "light_group" )
			self.assertEqual( arnold.AiArrayGetNumElements( lights ), 0 )

			# check shadows
			self.assertFalse( arnold.AiNodeGetBool( sphere1, "use_shadow_group" ) )
			shadows = arnold.AiNodeGetArray( sphere1, "shadow_group" )
			self.assertEqual( arnold.AiArrayGetNumElements( shadows ), 0 )
Ejemplo n.º 4
0
	def testShaderSubstitutions( self ) :

		s = Gaffer.ScriptNode()

		s["plane"] = GafferScene.Plane()

		s["planeAttrs"] = GafferScene.CustomAttributes()
		s["planeAttrs"]["in"].setInput( s["plane"]["out"] )
		s["planeAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "A", Gaffer.StringPlug( "value", defaultValue = 'bar' ) ) )
		s["planeAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "B", Gaffer.StringPlug( "value", defaultValue = 'foo' ) ) )

		s["cube"] = GafferScene.Cube()

		s["cubeAttrs"] = GafferScene.CustomAttributes()
		s["cubeAttrs"]["in"].setInput( s["cube"]["out"] )
		s["cubeAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "B", Gaffer.StringPlug( "value", defaultValue = 'override' ) ) )

		s["parent"] = GafferScene.Parent()
		s["parent"]["in"].setInput( s["planeAttrs"]["out"] )
		s["parent"]["children"][0].setInput( s["cubeAttrs"]["out"] )
		s["parent"]["parent"].setValue( "/plane" )

		s["shader"] = GafferArnold.ArnoldShader()
		s["shader"].loadShader( "image" )
		s["shader"]["parameters"]["filename"].setValue( "<attr:A>/path/<attr:B>.tx" )

		s["filter"] = GafferScene.PathFilter()
		s["filter"]["paths"].setValue( IECore.StringVectorData( [ "/plane" ] ) )

		s["shaderAssignment"] = GafferScene.ShaderAssignment()
		s["shaderAssignment"]["in"].setInput( s["parent"]["out"] )
		s["shaderAssignment"]["filter"].setInput( s["filter"]["out"] )
		s["shaderAssignment"]["shader"].setInput( s["shader"]["out"] )

		s["light"] = GafferArnold.ArnoldLight()
		s["light"].loadShader( "photometric_light" )
		s["light"]["parameters"]["filename"].setValue( "/path/<attr:A>.ies" )

		s["goboTexture"] = GafferArnold.ArnoldShader()
		s["goboTexture"].loadShader( "image" )
		s["goboTexture"]["parameters"]["filename"].setValue( "<attr:B>/gobo.tx" )

		s["gobo"] = GafferArnold.ArnoldShader()
		s["gobo"].loadShader( "gobo" )
		s["gobo"]["parameters"]["slidemap"].setInput( s["goboTexture"]["out"] )

		s["goboAssign"] = GafferScene.ShaderAssignment()
		s["goboAssign"]["in"].setInput( s["light"]["out"] )
		s["goboAssign"]["shader"].setInput( s["gobo"]["out"] )

		s["lightBlocker"] = GafferArnold.ArnoldLightFilter()
		s["lightBlocker"].loadShader( "light_blocker" )
		s["lightBlocker"]["parameters"]["geometry_type"].setValue( "<attr:geometryType>" )

		s["lightGroup"] = GafferScene.Group()
		s["lightGroup"]["name"].setValue( "lightGroup" )
		s["lightGroup"]["in"][0].setInput( s["goboAssign"]["out"] )
		s["lightGroup"]["in"][1].setInput( s["lightBlocker"]["out"] )

		s["parent2"] = GafferScene.Parent()
		s["parent2"]["in"].setInput( s["shaderAssignment"]["out"] )
		s["parent2"]["children"][0].setInput( s["lightGroup"]["out"] )
		s["parent2"]["parent"].setValue( "/" )

		s["globalAttrs"] = GafferScene.CustomAttributes()
		s["globalAttrs"]["in"].setInput( s["parent2"]["out"] )
		s["globalAttrs"]["global"].setValue( True )
		s["globalAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "A", Gaffer.StringPlug( "value", defaultValue = 'default1' ) ) )
		s["globalAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "B", Gaffer.StringPlug( "value", defaultValue = 'default2' ) ) )
		s["globalAttrs"]["attributes"].addChild( Gaffer.NameValuePlug( "geometryType", Gaffer.StringPlug( "value", defaultValue = 'cylinder' ) ) )

		s["render"] = GafferArnold.ArnoldRender()
		s["render"]["in"].setInput( s["globalAttrs"]["out"] )
		s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
		s["render"]["fileName"].setValue( self.temporaryDirectory() + "/test.ass" )

		s["render"]["task"].execute()

		with IECoreArnold.UniverseBlock( writable = True ) :

			arnold.AiASSLoad( self.temporaryDirectory() + "/test.ass" )
			plane = arnold.AiNodeLookUpByName( "/plane" )
			shader = arnold.AiNodeGetPtr( plane, "shader" )
			self.assertEqual( arnold.AiNodeGetStr( shader, "filename" ), "bar/path/foo.tx" )

			cube = arnold.AiNodeLookUpByName( "/plane/cube" )
			shader2 = arnold.AiNodeGetPtr( cube, "shader" )
			self.assertEqual( arnold.AiNodeGetStr( shader2, "filename" ), "bar/path/override.tx" )

			light = arnold.AiNodeLookUpByName( "light:/lightGroup/light" )
			self.assertEqual( arnold.AiNodeGetStr( light, "filename" ), "/path/default1.ies" )

			gobo = arnold.AiNodeGetPtr( light, "filters" )
			goboTex = arnold.AiNodeGetLink( gobo, "slidemap" )
			self.assertEqual( arnold.AiNodeGetStr( goboTex, "filename" ), "default2/gobo.tx" )

			lightFilter = arnold.AiNodeLookUpByName( "lightFilter:/lightGroup/lightFilter" )
			self.assertEqual( arnold.AiNodeGetStr( lightFilter, "geometry_type" ), "cylinder" )
Ejemplo n.º 5
0
    def testLightLinking(self):

        sphere1 = GafferScene.Sphere()
        sphere2 = GafferScene.Sphere()

        attributes = GafferScene.StandardAttributes()

        light1 = GafferArnold.ArnoldLight()
        light1.loadShader("point_light")

        light2 = GafferArnold.ArnoldLight()
        light2.loadShader("point_light")

        group = GafferScene.Group()
        group["in"].addChild(GafferScene.ScenePlug("in1"))
        group["in"].addChild(GafferScene.ScenePlug("in2"))
        group["in"].addChild(GafferScene.ScenePlug("in3"))
        group["in"].addChild(GafferScene.ScenePlug("in4"))

        evaluate = GafferScene.EvaluateLightLinks()

        render = GafferArnold.ArnoldRender()

        attributes["in"].setInput(sphere1["out"])
        group["in"]["in1"].setInput(attributes["out"])
        group["in"]["in2"].setInput(light1["out"])
        group["in"]["in3"].setInput(light2["out"])
        group["in"]["in4"].setInput(sphere2["out"])
        evaluate["in"].setInput(group["out"])
        render["in"].setInput(evaluate["out"])

        attributes["attributes"]["linkedLights"]["enabled"].setValue(True)
        attributes["attributes"]["linkedLights"]["value"].setValue(
            "/group/light /group/light1")

        # make sure we pass correct data into the renderer
        self.assertEqual(
            set(render["in"].attributes("/group/sphere")["linkedLights"]),
            set(IECore.StringVectorData(["/group/light", "/group/light1"])))

        render["mode"].setValue(render.Mode.SceneDescriptionMode)
        render["fileName"].setValue(self.temporaryDirectory() + "/test.ass")
        render["task"].execute()

        with IECoreArnold.UniverseBlock(writable=True):

            arnold.AiASSLoad(self.temporaryDirectory() + "/test.ass")

            # the first sphere had linked lights
            sphere = arnold.AiNodeLookUpByName("/group/sphere")
            lights = arnold.AiNodeGetArray(sphere, "light_group")
            lightNames = []
            for i in range(lights.contents.nelements):
                light = arnold.cast(arnold.AiArrayGetPtr(lights, i),
                                    arnold.POINTER(arnold.AtNode))
                lightNames.append(arnold.AiNodeGetName(light.contents))

            doLinking = arnold.AiNodeGetBool(sphere, "use_light_group")

            self.assertEqual(lightNames,
                             ["light:/group/light", "light:/group/light1"])
            self.assertEqual(doLinking, True)

            # the second sphere does not have any light linking enabled
            sphere1 = arnold.AiNodeLookUpByName("/group/sphere1")
            lights = arnold.AiNodeGetArray(sphere1, "light_group")
            lightNames = []
            for i in range(lights.contents.nelements):
                light = arnold.cast(arnold.AiArrayGetPtr(lights, i),
                                    arnold.POINTER(arnold.AtNode))
                lightNames.append(arnold.AiNodeGetName(light.contents))

            doLinking = arnold.AiNodeGetBool(sphere1, "use_light_group")

            self.assertEqual(lightNames, [])
            self.assertEqual(doLinking, False)
    def testLightLinkingAfterParameterUpdates(self):

        s = Gaffer.ScriptNode()
        s["catalogue"] = GafferImage.Catalogue()

        s["s"] = GafferScene.Sphere()

        s["PathFilter"] = GafferScene.PathFilter("PathFilter")
        s["PathFilter"]["paths"].setValue(IECore.StringVectorData(['/sphere']))

        s["ShaderAssignment"] = GafferScene.ShaderAssignment(
            "ShaderAssignment")
        s["ShaderAssignment"]["in"].setInput(s["s"]["out"])
        s["ShaderAssignment"]["filter"].setInput(s["PathFilter"]["out"])

        s["lambert"], _ = self._createMatteShader()
        s["ShaderAssignment"]["shader"].setInput(s["lambert"]["out"])

        s["StandardAttributes"] = GafferScene.StandardAttributes(
            "StandardAttributes")
        s["StandardAttributes"]["attributes"]["linkedLights"][
            "enabled"].setValue(True)
        s["StandardAttributes"]["attributes"]["linkedLights"][
            "value"].setValue("defaultLights")
        s["StandardAttributes"]["filter"].setInput(s["PathFilter"]["out"])
        s["StandardAttributes"]["in"].setInput(s["ShaderAssignment"]["out"])

        s["Light"] = GafferArnold.ArnoldLight("skydome_light")
        s["Light"].loadShader("skydome_light")

        s["c"] = GafferScene.Camera()
        s["c"]["transform"]["translate"]["z"].setValue(2)

        s["group"] = GafferScene.Group()
        s["group"]["in"][0].setInput(s["StandardAttributes"]["out"])
        s["group"]["in"][1].setInput(s["Light"]["out"])
        s["group"]["in"][2].setInput(s["c"]["out"])

        s["o"] = GafferScene.Outputs()
        s["o"].addOutput(
            "beauty",
            IECoreScene.Output(
                "test", "ieDisplay", "rgba", {
                    "driverType":
                    "ClientDisplayDriver",
                    "displayHost":
                    "localhost",
                    "displayPort":
                    str(s['catalogue'].displayDriverServer().portNumber()),
                    "remoteDisplayType":
                    "GafferImage::GafferDisplayDriver",
                }))
        s["o"]["in"].setInput(s["group"]["out"])

        s["so"] = GafferScene.StandardOptions()
        s["so"]["options"]["renderCamera"]["value"].setValue("/group/camera")
        s["so"]["options"]["renderCamera"]["enabled"].setValue(True)
        s["so"]["in"].setInput(s["o"]["out"])

        s["r"] = self._createInteractiveRender()
        s["r"]["in"].setInput(s["so"]["out"])

        # Start rendering and make sure the light is linked to the sphere

        with GafferTest.ParallelAlgoTest.UIThreadCallHandler() as handler:

            s["r"]["state"].setValue(s["r"].State.Running)

            handler.waitFor(1.0)

            self.assertAlmostEqual(self._color4fAtUV(s["catalogue"],
                                                     imath.V2f(0.5)).r,
                                   1,
                                   delta=0.01)

            # Change a value on the light. The light should still be linked to the sphere
            # and we should get the same result as before.
            s["Light"]['parameters']['shadow_density'].setValue(0.0)

            handler.waitFor(1.0)

            self.assertAlmostEqual(self._color4fAtUV(s["catalogue"],
                                                     imath.V2f(0.5)).r,
                                   1,
                                   delta=0.01)

            s["r"]["state"].setValue(s["r"].State.Stopped)
Ejemplo n.º 7
0
    def testBasic(self):

        g = GafferScene.Group()

        inputs = []
        for shader, name in [
            ("spot_light", "spot1"),
            ("spot_light", "spot2"),
            ("distant_light", "distant1"),
            ("skydome_light", "env1"),
        ]:
            l = GafferArnold.ArnoldLight()
            l.loadShader(shader)
            l["name"].setValue(name)
            inputs.append(l)

        inputs.append(GafferScene.Camera())
        for i in inputs:
            g["in"][-1].setInput(i["out"])

        f = GafferScene.PathFilter()
        f['paths'].setValue(
            IECore.StringVectorData(
                ["/group/spot1", "/group/env1", "/group/distant1"]))

        lc = GafferScene.LightToCamera()
        lc["in"].setInput(g["out"])
        lc["filter"].setInput(f["out"])

        # Test spot to persp cam
        self.assertEqual(
            lc["out"].object("/group/spot1").parameters(),
            IECore.CompoundData({
                'projection:fov':
                IECore.FloatData(65),
                'clippingPlanes':
                IECore.V2fData(imath.V2f(0.01, 100000)),
                'projection':
                IECore.StringData('perspective'),
                'resolutionOverride':
                IECore.V2iData(imath.V2i(512, 512)),
                'screenWindow':
                IECore.Box2fData(
                    imath.Box2f(imath.V2f(-1, -1), imath.V2f(1, 1)))
            }))

        # Test distant to ortho cam
        self.assertEqual(
            lc["out"].object("/group/distant1").parameters(),
            IECore.CompoundData({
                'clippingPlanes':
                IECore.V2fData(imath.V2f(-100000, 100000)),
                'projection':
                IECore.StringData('orthographic'),
                'resolutionOverride':
                IECore.V2iData(imath.V2i(512, 512)),
                'screenWindow':
                IECore.Box2fData(
                    imath.Box2f(imath.V2f(-1, -1), imath.V2f(1, 1)))
            }))

        # Test light with no corresponding camera ( gets default cam )
        self.assertEqual(
            lc["out"].object("/group/env1").parameters(),
            IECore.CompoundData({
                'projection':
                IECore.StringData('perspective'),
                'resolutionOverride':
                IECore.V2iData(imath.V2i(512, 512))
            }))

        self.assertEqual(lc["out"].set("__lights").value.paths(),
                         ["/group/spot2"])
        self.assertEqual(
            set(lc["out"].set("__cameras").value.paths()),
            set([
                "/group/camera", "/group/spot1", "/group/distant1",
                "/group/env1"
            ]))