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()andos.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")