Files
2025-09-29 00:52:08 +02:00

155 lines
11 KiB
Python
Executable File

# This script will modify copies .material and .scene files, import poses,
# a template, and get a fresh evolver character prepared for use in FaceFX Studio.
#
# Requirements:
# - FaceFX 2010 or above
# - The script will let you browse to a fresh evolver .mesh file. Should have
# corresponding .skeleton & .material files.
# - The sample files that ship with a fresh installation of FaceFx Studio.
# - Texture files should be in the same directory as the .MESH file. The diffuse
# texture must be referenced in the material file, and the specular and normal
# map files should have similar filenames with the _spec.jpg and _mid_nm.jpg
# extensions. These are standard evolver names.
# - The files in the "Files" section below exist on your computer in the
# specified locations. You need a .facefx to specify bone poses, a
# template file, and a reference .scene and .material file.
from FxStudio import *
from FxAnimation import *
import sys, os, time, math, re
from time import gmtime, strftime
# -----------------------------------------------------------------
# Files/Directories -
# Update these to where they exist on your system.
# -----------------------------------------------------------------
# This is the full path to a file that contains bone poses from
# another evolver charater. The skeleton type must be an exact
# match and the reference poses must be an exact match (T-Pose
# is easiest). Some poses might not look right if the poses
# have body-parts touching (hands-on-hips, etc) because the
# different evolver mesh and bone positions can cause collisions
# or parts that should be touching to no-longer touch.
pathToBonePoses = "./Samples/Evolver-FaceFX-Sample.facefx";
# This template contains face graph connections so the character's
# head moves properly with gesture curves and lip-synch targets are
# connected to the mapping.
pathToTemplate = "./Samples/Src/Evolver-FaceFx-Sample.fxt";
# The default scene files have lights too bright, and shadows turned
# on. We need to reposition the lights and rewrite the scene.
pathToReferenceScene = "./Ogre/Resources/Scenes/Evolver-FaceFX-Sample.SCENE";
# An empty actor file because no-save versions can't save a new file.
# The copy command didn't like forward slashes, so changed to backslashes.
emptyActorFile = ".\Samples\Src\EmptyActor.facefx";
# We want to use our special evolver materials to show off specular
# and normal maps.
pathToReferenceMaterial = "Ogre/Resources/Materials/Scripts/Evolver-FaceFX-Sample.MATERIAL";
# Boneweights are not copied over via template, adn neither are the full body ogre animations.
if 'no' == displayYesNoBox("This script creates a copy of your evolver content that works like the Evolver-FaceFX-Sample content, but without full body Ogre animations. Your content should use a Darwin Default skeleton with the facial bone rig. This script needs to load files and will close any existing files. Should I continue? If you need to save changes first, select no."):
raise RuntimeError, "User canceled."
requiredInstalledFiles = [pathToBonePoses, pathToReferenceScene, pathToReferenceMaterial, pathToTemplate, emptyActorFile]
for file in requiredInstalledFiles:
if 0 == os.path.exists(file):
errorBox("This script uses the Evolver-FaceFX-Sample files (.mesh, .scene, and .facefx) which were installed with FaceFX Studio. I can't find them now, so I'm exiting.")
raise RuntimeError, "Required installation file: " + file + "was not found."
evolverMeshFileReturn = displayFileOpenDialog("Select your evolver .mesh file.", file_must_exist=True, wildcard="*.MESH")
if None == evolverMeshFileReturn:
raise RuntimeError, "Must select a mesh file."
evolverMeshFile = str(evolverMeshFileReturn)
evolverMeshFile = evolverMeshFile.lower()
requiredExtensions = [".material", ".skeleton"]
for ext in requiredExtensions:
if 0 == os.path.exists(evolverMeshFile.replace(".mesh", ext)):
errorBox("This script requires that your evolver .mesh, .material, and .skeleton files share the same name. Normally this is the case, but I can't find one of these files, so I'm exiting.")
raise RuntimeError, "Required file: " + evolverMeshFile.replace(".mesh", ext) + "was not found."
# We are going to modify the .facefx, .scene, and .material file.
# Copy them to a temporary directory, and modify the copied files.
timestring = strftime("%Y_%m_%d_%H_%M_%S", gmtime());
baseDir = os.path.dirname(evolverMeshFile)
baseFileName = os.path.basename(evolverMeshFile)
outputDirectory = baseDir + "\\" + timestring + "-prepareEvolver_ScriptGenerated\\";
# Create the output directory.
os.system("mkdir " + "\"" + outputDirectory + "\"")
os.system("copy " + "\"" + evolverMeshFile + "\" \"" + outputDirectory + "\"")
os.system("copy " + "\"" + evolverMeshFile.replace(".mesh", ".skeleton") + "\" \"" + outputDirectory + "\"")
actorFileNameBase = os.path.split(evolverMeshFile)[1].replace(".mesh", "")
# If there is a .facefx file with the correct name in the .Mesh folder, use it. Otherwise, start with a clean one.
if 0 == os.path.exists(evolverMeshFile.replace(".mesh", ".facefx")):
os.system("copy " + "\"" + emptyActorFile + "\" \"" + outputDirectory + actorFileNameBase + ".facefx" + "\"")
else:
os.system("copy " + "\"" + evolverMeshFile.replace(".mesh", ".facefx") + "\" \"" + outputDirectory + "\"")
materialFile = open(evolverMeshFile.replace(".mesh", ".material"),"r");
referenceSceneFile = open(pathToReferenceScene,"r");
newSceneFileContents = re.sub("Evolver-FaceFX-Sample", actorFileNameBase, referenceSceneFile.read())
newSceneFile = open(outputDirectory + "\\" + actorFileNameBase + ".SCENE","w");
newSceneFile.writelines(newSceneFileContents)
newSceneFile.close()
referenceMaterialFile = open(pathToReferenceMaterial,"r");
materialFileContents = materialFile.read()
match = re.search("texture \S+\.jpg", materialFileContents)
displayTextureWarning = 0;
if match != None:
# notice the "+8" to get rid of "texture "
diffuseTexture = materialFileContents[match.start()+8:match.end()]
diffuseTexturePath = baseDir + "\\" + diffuseTexture
if 0 == os.path.exists(diffuseTexturePath) or 0 == os.path.exists(diffuseTexturePath.replace("_color.jpg", "_spec.jpg")) or 0 == os.path.exists(diffuseTexturePath.replace("_color.jpg", "_mid_nm.jpg")):
displayTextureWarning = 1
os.system("copy " + "\"" + diffuseTexturePath.replace("_color.jpg", "*.jpg") + "\" \"" + outputDirectory + "\"")
diffuseTextureBaseName = re.sub("_color.jpg", "", diffuseTexture)
newMaterialFileContents = re.sub("Evolver-FaceFX-Sample.MESH", actorFileNameBase + ".MESH", referenceMaterialFile.read())
newMaterialFileContents = re.sub("Evolver-FaceFX-Sample", diffuseTextureBaseName, newMaterialFileContents)
newMaterialFile = open(outputDirectory + "\\" + actorFileNameBase + ".MATERIAL","w");
newMaterialFile.writelines(newMaterialFileContents)
newMaterialFile.close()
# disable pop-ups.
setConsoleVariable( "g_unattended", 1);
# We have all our files copied over. Let's load them up!
issueCommand('loadActor -file "%s";'%(outputDirectory + "\\" + actorFileNameBase + ".facefx"));
if isNoSave():
setConsoleVariable( "g_unattended", 0);
warnBox("The bonepose -transfer command can not be run from the no-save version of FaceFX Studio. No bone poses will be created. Keep in mind that you can use the evaluation plugins to create bone poses and save a .facefx file in the same folder as your .mesh file. This script will find it, and you will be able to animate with those poses.");
setConsoleVariable( "g_unattended", 1);
else:
# This command exports a reference pose from the OGRE skeleton.
# It is avialable in FaceFX version 2010 and up.
issueCommand('bonepose -ref "Hips|Spine|Spine1|Spine2|Spine3|Spine4|Neck|Neck1|Head|HeadEnd|RightEye|LeftEye|Jaw|TongueR|TongueF|LipLowerR|LipLowerL|Nostrils|LipUpperR|LipUpperL|LipCornerR|LipCornerL|BrowInnerR|BrowInnerL|BrowOuterR|BrowOuterL|UpperLidR|UpperLidL|LowerLidR|LowerLidL|CheekR|CheekL|RightShoulder|RightArm|RightArmRoll|RightForeArm|RightForeArmRoll|RightHand|RightFingerBase|RightHandThumb1|RightHandThumb2|RightHandThumb3|RightHandThumb4|RightHandIndex0|RightHandIndex1|RightHandIndex2|RightHandIndex3|RightHandIndex4|RightHandMiddle1|RightHandMiddle2|RightHandMiddle3|RightHandMiddle4|RightHandRing1|RightHandRing2|RightHandRing3|RightHandRing4|RightHandPinky0|RightHandPinky1|RightHandPinky2|RightHandPinky3|RightHandPinky4|LeftShoulder|LeftArm|LeftArmRoll|LeftForeArm|LeftForeArmRoll|LeftHand|LeftFingerBase|LeftHandThumb1|LeftHandThumb2|LeftHandThumb3|LeftHandThumb4|LeftHandIndex0|LeftHandIndex1|LeftHandIndex2|LeftHandIndex3|LeftHandIndex4|LeftHandMiddle1|LeftHandMiddle2|LeftHandMiddle3|LeftHandMiddle4|LeftHandRing1|LeftHandRing2|LeftHandRing3|LeftHandRing4|LeftHandPinky0|LeftHandPinky1|LeftHandPinky2|LeftHandPinky3|LeftHandPinky4|Spine4Right|Spine4RightEnd|Spine4Left|Spine4LeftEnd|Spine2V|Spine2VEnd|Spine1V|Spine1VEnd|SpineV|SpineVEnd|RightUpLeg|RightUpLegRoll|RightLeg|RightLegRoll|RightFoot|RightToeBase|RightFootExtraFinger1|RightFootExtraFinger2|RightFootExtraFinger3|RightFootIndex1|RightFootIndex2|RightFootIndex3|RightFootMiddle1|RightFootMiddle2|RightFootMiddle3|RightFootRing1|RightFootRing2|RightFootRing3|RightFootPinky1|RightFootPinky2|RightFootPinky3|LeftUpLeg|LeftUpLegRoll|LeftLeg|LeftLegRoll|LeftFoot|LeftToeBase|LeftFootExtraFinger1|LeftFootExtraFinger2|LeftFootExtraFinger3|LeftFootIndex1|LeftFootIndex2|LeftFootIndex3|LeftFootMiddle1|LeftFootMiddle2|LeftFootMiddle3|LeftFootRing1|LeftFootRing2|LeftFootRing3|LeftFootPinky1|LeftFootPinky2|LeftFootPinky3";');
# Here is an export refpose command with only the head bones. Comment out the above line and use this one instead if you only care about the head on up.
#issueCommand('bonepose -ref "Head|HeadEnd|RightEye|LeftEye|Jaw|TongueR|TongueF|LipLowerR|LipLowerL|Nostrils|LipUpperR|LipUpperL|LipCornerR|LipCornerL|BrowInnerR|BrowInnerL|BrowOuterR|BrowOuterL|UpperLidR|UpperLidL|LowerLidR|LowerLidL|CheekR|CheekL";');
issueCommand('saveActor -file "%s";'%(getActorPath()));
issueCommand('bonepose -transfer -src "%s" -dst "%s";'%(pathToBonePoses, getActorPath()));
# reload the actor file for the bone poses to show up.
issueCommand('loadActor -file "%s";'%(getActorPath()));
# sync to template.
issueCommand('template -sync -file "%s" -all;'%(pathToTemplate));
if not isNoSave():
issueCommand('saveActor -file "%s";'%(getActorPath()));
setConsoleVariable( "g_unattended", 0);
if displayTextureWarning == 1:
warnBox("One or more of the Normal map, specular and diffuse textures were not found in the .MESH folder. If you have these files, copy them to the output directory in order to get the content to display correctly.")