Exemplo n.º 1
0
    def testMerging(self):

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

        plane = GafferScene.Plane()
        plane["divisions"].setValue(imath.V2i(20, 20))

        # Assign a basic gradient shader
        uvGradientCode = GafferOSL.OSLCode()
        uvGradientCode["out"].addChild(
            Gaffer.Color3fPlug("out", direction=Gaffer.Plug.Direction.Out))
        uvGradientCode["code"].setValue('out = color( u, v, 0.5 );')

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

        # Set up a random id from 0 - 3 on each face

        randomCode = GafferOSL.OSLCode()
        randomCode["out"].addChild(
            Gaffer.IntPlug("randomId", direction=Gaffer.Plug.Direction.Out))
        randomCode["code"].setValue(
            'randomId = int(cellnoise( P * 100 ) * 4);')

        outInt = GafferOSL.OSLShader()
        outInt.loadShader("ObjectProcessing/OutInt")
        outInt["parameters"]["name"].setValue('randomId')
        outInt["parameters"]["value"].setInput(randomCode["out"]["randomId"])

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

        oSLObject = GafferOSL.OSLObject()
        oSLObject["in"].setInput(shaderAssignment["out"])
        oSLObject["filter"].setInput(allFilter["out"])
        oSLObject["shader"].setInput(outObject["out"])
        oSLObject["interpolation"].setValue(2)

        # Create 4 meshes by picking each of the 4 ids

        deleteContextVariables = Gaffer.DeleteContextVariables()
        deleteContextVariables.setup(GafferScene.ScenePlug())
        deleteContextVariables["variables"].setValue('collect:rootName')
        deleteContextVariables["in"].setInput(oSLObject["out"])

        pickCode = GafferOSL.OSLCode()
        pickCode["parameters"].addChild(Gaffer.IntPlug("targetId"))
        pickCode["out"].addChild(
            Gaffer.IntPlug("cull", direction=Gaffer.Plug.Direction.Out))
        pickCode["code"].setValue(
            'int randomId; getattribute( "randomId", randomId ); cull = randomId != targetId;'
        )

        expression = Gaffer.Expression()
        pickCode.addChild(expression)
        expression.setExpression(
            'parent.parameters.targetId = stoi( context( "collect:rootName", "0" ) );',
            "OSL")

        outInt1 = GafferOSL.OSLShader()
        outInt1.loadShader("ObjectProcessing/OutInt")
        outInt1["parameters"]["name"].setValue('deleteFaces')
        outInt1["parameters"]["value"].setInput(pickCode["out"]["cull"])

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

        oSLObject1 = GafferOSL.OSLObject()
        oSLObject1["in"].setInput(deleteContextVariables["out"])
        oSLObject1["filter"].setInput(allFilter["out"])
        oSLObject1["shader"].setInput(outObject1["out"])
        oSLObject1["interpolation"].setValue(2)

        deleteFaces = GafferScene.DeleteFaces()
        deleteFaces["in"].setInput(oSLObject1["out"])
        deleteFaces["filter"].setInput(allFilter["out"])

        collectScenes = GafferScene.CollectScenes()
        collectScenes["in"].setInput(deleteFaces["out"])
        collectScenes["rootNames"].setValue(
            IECore.StringVectorData(['0', '1', '2', '3']))
        collectScenes["sourceRoot"].setValue('/plane')

        # First variant:  bake everything, covering the whole 1001 UDIM

        customAttributes1 = GafferScene.CustomAttributes()
        customAttributes1["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/complete/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes1["in"].setInput(collectScenes["out"])

        # Second vaiant: bake just 2 of the 4 meshes, leaving lots of holes that will need filling
        pruneFilter = GafferScene.PathFilter()
        pruneFilter["paths"].setValue(IECore.StringVectorData(['/2', '/3']))

        prune = GafferScene.Prune()
        prune["in"].setInput(collectScenes["out"])
        prune["filter"].setInput(pruneFilter["out"])

        customAttributes2 = GafferScene.CustomAttributes()
        customAttributes2["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/incomplete/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes2["in"].setInput(prune["out"])

        # Third variant: bake everything, but with one mesh at a higher resolution

        customAttributes3 = GafferScene.CustomAttributes()
        customAttributes3["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/mismatch/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes3["in"].setInput(collectScenes["out"])

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

        customAttributes = GafferScene.CustomAttributes()
        customAttributes["attributes"].addMember('bake:resolution',
                                                 IECore.IntData(200))
        customAttributes["filter"].setInput(pathFilter2["out"])
        customAttributes["in"].setInput(customAttributes3["out"])

        # Merge the 3 variants
        mergeGroup = GafferScene.Group()
        mergeGroup["in"][-1].setInput(customAttributes["out"])
        mergeGroup["in"][-1].setInput(customAttributes1["out"])
        mergeGroup["in"][-1].setInput(customAttributes2["out"])

        arnoldTextureBake = GafferArnold.ArnoldTextureBake()
        arnoldTextureBake["in"].setInput(mergeGroup["out"])
        arnoldTextureBake["filter"].setInput(allFilter["out"])
        arnoldTextureBake["bakeDirectory"].setValue(self.temporaryDirectory() +
                                                    '/bakeMerge/')
        arnoldTextureBake["defaultResolution"].setValue(128)

        # We want to check the intermediate results
        arnoldTextureBake["cleanupIntermediateFiles"].setValue(False)

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

        # Check results
        imageReader = GafferImage.ImageReader()

        outLayer = GafferOSL.OSLShader()
        outLayer.loadShader("ImageProcessing/OutLayer")
        outLayer["parameters"]["layerColor"].setInput(
            uvGradientCode["out"]["out"])

        outImage = GafferOSL.OSLShader()
        outImage.loadShader("ImageProcessing/OutImage")
        outImage["parameters"]["in0"].setInput(outLayer["out"]["layer"])
        oSLImage = GafferOSL.OSLImage()
        oSLImage["in"].setInput(imageReader["out"])
        oSLImage["shader"].setInput(outImage["out"])

        merge3 = GafferImage.Merge()
        merge3["in"]["in0"].setInput(oSLImage["out"])
        merge3["in"]["in1"].setInput(imageReader["out"])
        merge3["operation"].setValue(10)

        edgeDetect = self.SimpleEdgeDetect()
        edgeDetect["in"].setInput(imageReader["out"])

        edgeStats = GafferImage.ImageStats()
        edgeStats["in"].setInput(edgeDetect["out"])

        refDiffStats = GafferImage.ImageStats()
        refDiffStats["in"].setInput(merge3["out"])

        oneLayerReader = GafferImage.ImageReader()

        grade = GafferImage.Grade()
        grade["in"].setInput(oneLayerReader["out"])
        grade["channels"].setValue('[A]')
        grade["blackPoint"].setValue(imath.Color4f(0, 0, 0, 0.999899983))

        copyChannels = GafferImage.CopyChannels()
        copyChannels["in"]["in0"].setInput(merge3["out"])
        copyChannels["in"]["in1"].setInput(grade["out"])
        copyChannels["channels"].setValue('[A]')

        premultiply = GafferImage.Premultiply()
        premultiply["in"].setInput(copyChannels["out"])

        refDiffCoveredStats = GafferImage.ImageStats()
        refDiffCoveredStats["in"].setInput(premultiply["out"])

        # We are testing 3 different cases:
        # complete : Should be an exact match.
        # incomplete : Expect some mild variance of slopes and some error, because we have to
        #              reconstruct a lot of missing data.
        # mismatch : We should get a larger image, sized to the highest override on any mesh.
        #            Match won't be as perfect, because we're combining source images at
        #            different resolutions
        for name, expectedSize, maxEdge, maxRefDiff, maxMaskedDiff in [
            ("complete", 128, 0.01, 0.000001, 0.000001),
            ("incomplete", 128, 0.05, 0.15, 0.000001),
            ("mismatch", 200, 0.01, 0.01, 0.01)
        ]:
            imageReader["fileName"].setValue(self.temporaryDirectory() +
                                             "/bakeMerge/" + name +
                                             "/beauty/beauty.1001.tx")
            oneLayerReader["fileName"].setValue(self.temporaryDirectory() +
                                                "/bakeMerge/" + name +
                                                "/beauty/beauty.1001.exr")

            self.assertEqual(imageReader["out"]["format"].getValue().width(),
                             expectedSize)
            self.assertEqual(imageReader["out"]["format"].getValue().height(),
                             expectedSize)

            edgeStats["area"].setValue(
                imath.Box2i(imath.V2i(1), imath.V2i(expectedSize - 1)))
            refDiffStats["area"].setValue(
                imath.Box2i(imath.V2i(1), imath.V2i(expectedSize - 1)))
            refDiffCoveredStats["area"].setValue(
                imath.Box2i(imath.V2i(0), imath.V2i(expectedSize)))

            # Blue channel is constant, so everything should line up perfectly
            self.assertEqual(0, edgeStats["max"].getValue()[2])
            self.assertEqual(0, refDiffStats["max"].getValue()[2])
            self.assertEqual(0, refDiffCoveredStats["max"].getValue()[2])

            for i in range(2):

                # Make sure we've got actual data, by checking that we have some error ( we're not expecting
                # to perfectly reconstruct the gradient when the input is incomplete )
                self.assertGreater(edgeStats["max"].getValue()[i], 0.005)
                if name == "incomplete":
                    self.assertGreater(edgeStats["max"].getValue()[i], 0.03)
                    self.assertGreater(refDiffStats["max"].getValue()[i], 0.06)

                self.assertLess(edgeStats["max"].getValue()[i], maxEdge)
                self.assertLess(refDiffStats["max"].getValue()[i], maxRefDiff)
                self.assertLess(refDiffCoveredStats["max"].getValue()[i],
                                maxMaskedDiff)
Exemplo n.º 2
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"])
        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)
Exemplo n.º 3
0
    def testTasks(self):

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

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

        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(sphere["out"])
        uvScaleOSL["filter"].setInput(allFilter["out"])
        uvScaleOSL["shader"].setInput(outObject2["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"])

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

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

        self.assertEqual(
            sorted(os.listdir(self.temporaryDirectory() + '/bakeSpheres/')), [
                "BAKE_FILE_INDEX_0.0001.txt", "BAKE_FILE_INDEX_1.0001.txt",
                "BAKE_FILE_INDEX_2.0001.txt", "beauty", "diffuse"
            ])
        # Make sure the 16 images that need writing get divided into very approximate thirds
        for i in range(3):
            l = len(
                open(self.temporaryDirectory() +
                     '/bakeSpheres/BAKE_FILE_INDEX_%i.0001.txt' %
                     i).readlines())
            self.assertGreater(l, 2)
            self.assertLess(l, 8)