Now that we we’ve identified which textures are incompatible with our list of acceptable image dimensions, we’d like to know which scene elements these textures have been applied to. To do that, we’ll need a bit more information about how objects are organized in the FBX SDK, and how this organization relates to a content development tool like Maya. Let’s continue using the cubeMan.fbx character as an example. If we open the file in Maya, and look at the Outliner, the “chest” is the parent of the head, arms, and legs, while the head is the parent of the hat. This way, if we rotate the head, the hat will rotate as well. Likewise, if we move the chest, the rest of the character will follow along with it. In Maya, the chest, head, hat, arms, and legs are known as transform nodes, which control the position, rotation and scale of their underlying shape nodes. To display these shape nodes in the Outliner, Select “Display>Shapes”. A shape node determines the specialized data of an object in the scene, such as a mesh, a light, a camera, and so on. For example, the “hatShape” node defines the hat’s mesh data, including its vertices, its faces, its normals, and its UV’s. The terminology of “transform node” and “shape node” is specific to Maya. In the FBX SDK, a “transform node” is simply known as a “node”, and is represented by an instance of FbxNode. The concept of a “shape node” is equivalent to a “node attribute”, and is represented by an instance of FbxNodeAttribute. Nodes determine where their attached node attribute is positioned, rotated and scaled in the scene. Like transform nodes in Maya, FBX nodes can be arranged in a parent/child hierarchy to affect the position, rotation, and scale of their child nodes. Materials and textures also work similarly in Maya and in FBX. For example, in Maya, we can assign a phong material to a sphere to change the way it bounces light. This material has several properties, each of which can be assigned to a different texture. We can assign one texture to the Color property, to give it the basic appearance of an orange. We can assign another texture to the bump mapping property, to give the orange some dimples. In the case of our character, the chest, head, arms and legs have all been unwrapped in the same UV space, and have all been given the same “cubeManMat” material. The “cubeManMat” material’s “Color” property has been assigned to the cubeMan.png file. In the FBX SDK, each node stores the materials used by its connected node attribute. Each material has its own set of properties, although the names of these properties might differ slightly between Maya and FBX. For example, in Maya, the “Color” property of a Lambert material is referred to as the “Diffuse Color” property in FBX. Like in Maya, FBX material properties can also be connected to textures. In part 1 of this tutorial, we discovered that the hat.png texture was incompatible with our list of valid image dimensions. The filename of this texture reveals where in the scene it is being used, namely on the hat node. However, you can imagine a more complex scene including many textures whose filenames do not follow an obvious naming pattern. In such a case, it may be very tedious to manually identify which texture is being used by which node. To automate this task in our Python FBX program, the idea is to start at the root node, and to inspect each node in the scene’s parent-child hierarchy. For each node, we’ll check whether or not one of the material’s properties is connected to one of the invalid textures. If it is, we’ll print the path of that node in the hierarchy. To start, create a function called “findTexturesOnNodes”, which accepts a node, a dictionary of textures, and a currentPath list. We’ll use this list to keep track of the current node path in the scene graph. We’ll be building this function in small increments, so let’s start by printing the current path of nodes we’ve visited. Append the node’s name to currentPath, and print that path. Use a for-loop to access the children of the current node. Here, node.GetChildCount() returns the number of children of the current node node.GetChild( i ) returns the node’s child indexed at “i”. Outside the for-loop, call currentPath.pop() to remove the last element of the currentPath list. The paired calls to append() and pop() ensure the currentPath contains the correct node names for the given depth in the scene graph. Outside the function, call findTexturesOnNodes using the scene’s root node, and the dictionary of invalid textures we created in Part 1. When we run the program, the path of each node in the scene is printed to the console. Next, create a for-loop to iterate over the node’s materials. Print the material’s name to see which materials are bound to each node. Run the program. In the output, we can see that the character’s chest, head, arms and legs have the same cubeManMat material, while the hat node contains the hatMat material. To access a material’s properties, use the following for-loop. fbx.FbxLayerElement.sTypeTextureCount() provides the number of texture-based properties on materials. Call material.FindProperty() with the following parameter to access the material’s texture-based property with the given propertyIndex. Some material properties are nameless, so we’ll filter those out with a simple if-statement, and print the names of the remaining properties. Running the program now outputs the properties of each material. To iterate over the textures connected to a property, use the following for-loop: The connected texture is obtained with a call to property.GetSrcObject() using the FbxFileTexture ClassId, and the current texture index. Print the texture’s filename with texture.GetFileName() When we run the program, we can see that the textures are only connected to the DiffuseColor property. The next step is to identify the paths of invalid textures. Let’s get rid of our previous print statements, and only print the texture’s path if its filename is in the textureDictionary. When we run the program now, the scene path of the invalid texture is printed, including its material, and its connected property. You should now have a good idea of how to navigate the scene graph using the Python FBX SDK, and how to access a node’s material and texture information.