Python Tools - Session 5B

Photo Wall Creation

February 6, 2020

Session Navigation

Overview

This session brings together file I/O, material creation, and grid-based tiling to build a photo wall in Maya. You'll scan a directory for images using Python's os module, create a Blinn material with a file texture for each image, and lay out textured planes in a grid. This exercise demonstrates the full pipeline of connecting file nodes to materials to shading groups, and dynamically building a scene from external data.

Key Concepts

  • Material creation — creating Blinn shaders and shading groups programmatically
  • Node connections — using pm.connectAttr() to wire file nodes to materials and shading groups
  • Directory listing — using os.listdir() and os.path.join() to build file paths
  • Grid tiling — using modulo (math.fmod()) to wrap tiles into rows
  • Material assignment — applying materials to geometry with pm.hyperShade()
  • Kwargs — using keyword arguments with default values for flexible function signatures

Code

This script creates a wall of photo tiles by loading every image from a source directory, creating a material for each, and positioning textured planes in a grid.

"""
#############################################################################
filename    session_5b_code_commented.py
author      Matt Osbond
course      CS115
Brief Description:
    Video for missed session - class exercise - create a wall of photos
    Thursday Feb 6th 2020
#############################################################################
"""

# Import required packages
import pymel.core as pm
import os
import math

# Force new scene (commented out for safety)
#pm.newFile(force=True)

def create_material(image_path):
    """
    Function to create a new material using the supplied image

    Args:
        image_path: path on disk to the image to use
    """

    # Create a file node and assign the texture
    file_node = pm.createNode("file")
    file_node.fileTextureName.set(image_path)

    # Create a blank blinn material
    material = pm.createNode("blinn")

    # Create a blank shading group
    sg = pm.sets(renderable=True, noSurfaceShader=True, empty=True)

    # Connect the output from the file node to the input on the material
    pm.connectAttr((file_node + ".outColor"), (material + ".color"), force=True)

    # Connect the output of the material to the input on the shading group
    pm.connectAttr((material + ".outColor"), (sg + ".surfaceShader"), force=True)

    # Return our new material instance
    return material

def create_tile(image_path, x, z, size):
    """
    Function to create a single tile

    Args:
        image_path: image to use for the tile
        x: x position
        z: z position
        size: the size of the tile
    """
    # Get our new material from our material function
    new_material = create_material(image_path)

    # Create the plane and move it
    tile = pm.polyPlane(width=size, height=size)[0]
    pm.move(tile, [x, 0.0, z])

    # Assign the material to our plane
    pm.hyperShade(assign=new_material)

def create(source_directory, tile_size=10):
    """
    Main function to start the construction of the photo wall

    Args:
        source_directory: path on disk to a folder of images

    Kwargs:
        tile_size: size of each tile in 3D space (default = 10)
    """

    # Get all the images
    all_images = os.listdir(source_directory)

    x_pos = 0
    z_pos = 0
    for i in range(0, len(all_images)):
        # Join the directory path to the file name, to get the full file path
        file_path = os.path.join(source_directory, all_images[i])

        # Make sure we don't run on a directory!
        if os.path.isfile(file_path):

            # Run the tile creation function
            create_tile(file_path, x_pos, z_pos, tile_size)

            # If current iteration is divisible by 4 (and not 0) then reset
            if i != 0 and math.fmod(i, 4) == 0:
                x_pos = 0
                z_pos = z_pos + tile_size
            else:
                x_pos = x_pos + tile_size

# Run with a path to a folder of images on your local drive
create(r"C:\path\to\your\image\folder")
← Session 5A Next: Session 6A →