Python Tools - Session 13B
Scene Archiver Complete and LOD Start
2020.04.09 - Session 13B
Session Navigation
Overview
This session completes the Scene Archiver tool and introduces LOD (Level of Detail) generation. The archiver now saves a copy of the scene, copies all referenced textures to a relative path, creates a zip archive, and reverts back to the original scene. We also begin a simple LOD tool that duplicates meshes and applies polyReduce at increasing levels.
Key Concepts
- File operations with shutil - Copy files with
shutil.copy2and create zip archives withshutil.make_archive - Texture path retargeting - Find all file nodes, copy textures, and update paths to relative locations
- Scene save/restore - Save to a new location, then revert to the original scene
- Maya project management - Set and restore the Maya project directory with
mel.setProject - LOD generation - Duplicate meshes and reduce polygon count with
pm.polyReduce - LOD groups - Use Maya's
LevelOfDetailGroupto organize LOD meshes
Source Code - archiver.py (Complete Version)
"""
#############################################################################
filename archiver.py
author [author]
course [course]
Brief Description:
Scene Archive Tool (Part 2)
Project to cover the use of path manipulation and scene trawling
Session 13B - Apr 9 2020
#############################################################################
"""
import pymel.core as pm
import os
import shutil
def archive_scene():
"""Small utility to archive the current scene
This will:
- Save a copy of the current scene
- Copy all textures to a new location relative to the scene
- Zip up the result
- Revert back so it looks like nothing happened
"""
# Get the current project directory
current_wd = pm.workspace.getcwd()
# Get full file path
scene_path = pm.sceneName()
print 'Scene Path = ', scene_path
# Error check - bail if the scene isn't saved
if scene_path == None or scene_path == '':
print 'WARNING - Scene is not saved'
return
# Save the scene
pm.saveFile()
# Get the scene file name
scene_name_with_ext = os.path.basename(scene_path)
print 'Scene File = ', scene_name_with_ext
# Get the name without extension
scene_name = os.path.splitext(scene_name_with_ext)[0]
print 'Scene Name = ', scene_name
# Get scene directory
scene_dir = os.path.dirname(scene_path)
print 'Scene Dir = ', scene_dir
# Create the target archive directory
target_dir = os.path.join(scene_dir, scene_name)
print 'Target Dir = ', target_dir
# Exit if the target files exist
if os.path.exists(target_dir):
print 'WARNING - target exists, aborting'
return
# Create the target Maya scene path
new_file_name = os.path.join(target_dir, scene_name_with_ext)
print 'Target File = ', new_file_name
# Create the target texture directory
texture_dir = os.path.join(target_dir, 'textures')
print 'Texture Dir = ', texture_dir
# Ensure the directories exist
if not os.path.exists(texture_dir):
os.makedirs(texture_dir)
# Set the current project
pm.mel.setProject(target_dir)
# Save the file to the new location
pm.saveAs(new_file_name)
for file_node in pm.ls(type='file'):
# Get the texture path from the current file node
tex_path = file_node.fileTextureName.get()
# Check if the file exists on disk
if os.path.exists(tex_path):
# Assemble the path for the target texture
tex_file_name = os.path.basename(tex_path)
new_tex_path = os.path.join(texture_dir, tex_file_name)
# Check if the target file already exists
if not os.path.exists(new_tex_path):
print 'Copying %s to %s' %(tex_path, new_tex_path)
shutil.copy2(tex_path, new_tex_path)
# Set the new path to be relative
new_tex_rel_path = os.path.join('textures', tex_file_name)
file_node.fileTextureName.set(new_tex_path)
# Save the scene now we have the file path changes
pm.saveFile()
# Open the original file
pm.openFile(scene_path, force=True)
# Set the project back to what it was when we started
pm.mel.setProject(current_wd)
# Zip the new directory up to a zip file with the same name
shutil.make_archive(target_dir, 'zip', target_dir)
Source Code - lod_start.py
import pymel.core as pm
def create_lod_level(mesh_transform, reduction):
dupe = pm.duplicate(mesh_transform)[0]
print 'Reducing %s by %i percent' %(dupe, reduction)
pm.polyReduce(dupe, percentage=reduction)
return dupe
def make_lods(mesh_transform, lod_count, reduction):
all_meshes = [mesh_transform]
for i in range(1, lod_count):
new_lod = create_lod_level(mesh_transform, reduction)
all_meshes.append(new_lod)
mesh_transform = new_lod
pm.select(all_meshes)
pm.mel.LevelOfDetailGroup()
return all_meshes