Scripting Face Robot

Reading Existing Landmark Points

This script outputs the positions of all the picked landmark locations in three arrays (X, Y, and Z). We'll use the result from this script for the next automation example.


//
// Use this function to generate the position arrays code if you
// want to automate another head
// 
//

var namearray = ["NoseTip","LNostrilBulge","RNostrilBulge","LEyeCornerNear","REyeCornerNear","LEyeTop","REyeTop","LEyeCornerFar","REyeCornerFar","LEyeBottom","REyeBottom","LEyebrowPeak","REyebrowPeak","LTemple","RTemple","LEarlobeJoin","REarlobeJoin","LJawCorner","RJawCorner","LCornerUnderside","RCornerUnderside","LChinCorner","RChinCorner","LipLower","LipUpper","LMouthCorner","RMouthCorner","JawUnderside","AdamsAppleBottom","LNeckStrainMid","RNeckStrainMid","LNeckSideBottom","RNeckSideBottom","LBackDownFromEar","RBackDownFromEar","LBelowEar","RBelowEar","LEarSide","REarSide"];

GenerateLandmarkPositions( namearray ) ;

function GenerateLandmarkPositions( names )
{

	var aX = [], aY =[], aZ=[] ;

	var pickpoints = fr_sget("PickPoints");
	var sph;
	var lt = XSIMath.CreateVector3();
	for (var i=0; i<names.length; i++) {
	    sph = pickpoints.FindChild(names[i]);
	    lt = sph.LocalTranslation ; 
		aX.push( lt.X ) ;
		aY.push( lt.Y ) ;
		aZ.push( lt.Z ) ;
	    	    
	}
	
	var strX = "var posxarray = [" + aX.join() + "];" ;
	var strY = "var posyarray = [" + aY.join() + "];" ;
	var strZ = "var poszarray = [" + aZ.join() + "];" ;

	logmessage( "\n" + strX + "\n" + strY + "\n" + strZ + "\n" ) ;
}

Auto-Solving a Head

This script clears the scene, loads one of the example head models, and then takes it all the way to stage 5, all with no user intervention.
Notice how we use the saved pick point locations generated using the previous script to auto-pick the landmark points.

var root = XSIUtils.Environment.Item("FACEROBOTDATAROOT");

newscene(null,false) ;

// grab parameters from FaceConnections property page
var fconn = fr_sget("psets", "FaceConnections");
var fconn_mesh = fconn.parameters("Mesh");
var fconn_leye = fconn.parameters("LEye");
var fconn_reye = fconn.parameters("REye");
var fconn_uteeth = fconn.parameters("UpperTeeth");
var fconn_lteeth = fconn.parameters("LowerTeeth");

// grab parameters from FaceScale property page
var fscale = fr_sget("psets", "FaceScale");
var fscale_scale = fscale.parameters("Scale");

// grab parameters from FaceState property page
var fstate = fr_sget("psets", "FaceState");
var fstate_dna = fstate.parameters("DNA");
var fstate_valid = fstate.parameters("Valid");

// merge in Human Female 90291 model
ImportModel(XSIUtils.BuildPath(root, "Face", "Human_Female_90291.face.emdl"));
var importedmodel = ActiveSceneRoot.FindChild("Human_Female_90291_face");

// auto-pick meshes
fconn_mesh.value = importedmodel.FindChild("Head");
fconn_leye.value = importedmodel.FindChild("LEyeball");
fconn_reye.value = importedmodel.FindChild("REyeball");
fconn_uteeth.value = importedmodel.FindChild("TopTeeth");
fconn_lteeth.value = importedmodel.FindChild("BottomTeeth");

// auto-select DNA
fstate_dna.value = XSIUtils.BuildPath(root,"Dna","Human_Face_Symmetric.dna");

// apply DNA selection and diagnose mesh
fr_Diagnose();

// make sure stages 1 & 2 went OK
if (fstate_valid==false) {
    logmessage("Diagnosis failed.  Halting.", siFatal);
}

// define landmarks
var namearray = ["NoseTip","LNostrilBulge","RNostrilBulge","LEyeCornerNear","REyeCornerNear","LEyeTop","REyeTop","LEyeCornerFar","REyeCornerFar","LEyeBottom","REyeBottom","LEyebrowPeak","REyebrowPeak","LTemple","RTemple","LEarlobeJoin","REarlobeJoin","LJawCorner","RJawCorner","LCornerUnderside","RCornerUnderside","LChinCorner","RChinCorner","LipLower","LipUpper","LMouthCorner","RMouthCorner","JawUnderside","AdamsAppleBottom","LNeckStrainMid","RNeckStrainMid","LNeckSideBottom","RNeckSideBottom","LBackDownFromEar","RBackDownFromEar","LBelowEar","RBelowEar","LEarSide","REarSide"];
var nlandmarks = namearray.length;

// define landmark positions 
var posxarray = [0,0.43643723111780375,-0.43643723111780375,0.4614840485479661,-0.4614840485479661,0.9854289692399547,-0.9854289692399547,1.4219993973754636,-1.4219993973754636,1.0697540460457855,-1.0697540460457855,1.5009940376403907,-1.5009940376403907,1.681203195429413,-1.681203195429413,1.851607907177394,-1.851607907177394,1.5905018489171904,-1.5905018489171904,1.3861356309917987,-1.3861356309917987,0.3318579594675395,-0.3318579594675395,0,0,0.766661507820281,-0.766661507820281,0,0,0.7506467195295308,-0.7506467195295308,1.888950083102392,-1.888950083102392,1.3078872639818648,-1.3078872639818648,1.66023833161068,-1.66023833161068,2.665552362113223,-2.665552362113223];
var posyarray = [1.3391169100631597,1.2353495415446733,1.2353495415446733,2.295135360404384,2.295135360404384,2.580055978403209,2.580055978403209,2.3793574722483743,2.3793574722483743,2.1958008702395783,2.1958008702395783,3.107412967905077,3.107412967905077,3.920685344902605,3.920685344902605,0.7990047792856814,0.7990047792856814,-0.007574937313451713,-0.007574937313451713,-0.10024304660467642,-0.10024304660467642,-0.8747835391107341,-0.8747835391107341,0.053893708172985555,0.49102183345626926,0.21647103663998024,0.21647103663998024,-1.165866378191288,-2.4480958671172326,-1.4720159258379537,-1.4720159258379537,-1.7776564636161764,-1.7776564636161764,-0.12102370187010836,-0.12102370187010836,0.6793913475843802,0.6793913475843802,2.712839531904682,2.712839531904682];
var poszarray = [3.708215223045954,3.178963972442876,3.178963972442876,2.7031836534841122,2.7031836534841122,2.810833237755215,2.810833237755215,2.515795576052861,2.515795576052861,2.723081017324084,2.723081017324084,2.8182618247142024,2.8182618247142024,2.27929962115579,2.27929962115579,0.405917351737763,0.405917351737763,0.7228185392947228,0.7228185392947228,0.09039675775490785,0.09039675775490785,2.667461669156136,2.667461669156136,3.196763903836544,3.3634396341628996,2.7112533106631566,2.7112533106631566,0.9654054018578044,0.42115035198881223,0.22298111090338501,0.22298111090338501,-1.6678836777505168,-1.6678836777505168,-0.9004297380584791,-0.9004297380584791,-0.14413740499596805,-0.14413740499596805,-0.272357750785039,-0.272357750785039];

// make sure all the landmark information are in sync
if (nlandmarks!=posxarray.length || nlandmarks!=posyarray.length || nlandmarks!=poszarray.length) {
    logmessage("Error in defining landmark points.", siFatal);
}

// auto-pick landmarks
var pickpoints = fr_sget("PickPoints");
var sph;
var lt = XSIMath.CreateVector3();
for (var i=0; i<nlandmarks; i++) {
    sph = pickpoints.AddPrimitive("Sphere", namearray[i]);
    sph.parameters("radius").value = fscale_scale.value * 0.62;
    lt.set(posxarray[i],posyarray[i],poszarray[i]);
    sph.LocalTranslation = lt; 
}

// fit
FaceRobot("next");

// solve
FaceRobot("next");

// refresh layout
FaceRobot();  // fr_SwitchFaceLayout() would also work

An interesting variation would be to have the modeler provide the landmarks up-front by naming certain vertices according to some agreed-upon convention,
and then revising the above script slightly so that it grabs the landmark locations from those named vertices rather than from the hard-coded arrays as shown.
Note that the easiest way to name a vertex is to create a cluster containing just that one point.

Batch-Rendering Mocap Animations

Load a solved head, then point this script at a directory containing a bunch of prepared C3D files and run it, and it'll create a playblast of each animation.
It'll also skip over the already-rendered ones, and give you the opportunity to confirm the render list.


// specify the path to the C3D files
var path = "V:\\mtl_FaceRobot\\Data\\FaceRobot\\FaceAni";



// --------------------------------------------------
// secondary settings (don't change)
// --------------------------------------------------

// specify the extension to look for
var ext_motion = ".c3d";

// specify the movie extensions to skip if they already exist
var ext_movies = [".avi", ".mov"];



// --------------------------------------------------
// main program
// --------------------------------------------------

SpacedLog("I. File Processing");
var fnames = FindFiles(path, ext_motion, ext_movies);

var buttonPressed = XSIUIToolkit.Msgbox("Render these?", siMsgYesNo | siMsgQuestion, "Confirmation");
if (buttonPressed == siMsgYes) {
    SpacedLog("II. Batch Rendering");
    BatchRender(fnames, ext_motion);
    SpacedLog("*** Rendering completed. ***");
}
else {
    SpacedLog("*** Aborted by user. ***");
}



// --------------------------------------------------
// SpacedLog
// --------------------------------------------------

function SpacedLog(s) {
    logmessage(" ");
    logmessage(s);
    logmessage(" ");
}



// --------------------------------------------------
// isElementOf
// --------------------------------------------------

function isElementOf(elem, set) {
    var iselem = false;
    for (var i=0; i<set.length; i++) {
        if (elem==set[i]) {
            return true;
        }
    }
    return false;
}



// --------------------------------------------------
// FindFiles
// --------------------------------------------------

function FindFiles(path, ext_yes, exts_no) {
    // put the names of all the C3D and movie files into arrays
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var f = fso.GetFolder(path);
    var fc = new Enumerator(f.Files);

    var fnames_yes = [], fnames_no = [];
    var i_yes = 0, i_no = 0;
    for (; !fc.atEnd(); fc.moveNext()) {
        var fname = fc.item() + "";
        var flen = fname.length;
        if (flen > 4) {
            var ext = fname.substr(flen-4);
            if (ext==ext_yes) {
                fnames_yes[i_yes++] = fname.substr(0, flen-4);
            }
            else if (isElementOf(ext, exts_no)) {
                fnames_no[i_no++] = fname.substr(0, flen-4);
            }
        }
    }

    // filter out already rendered files
    logmessage( "\tFound these unrendered " + ext_yes + " files:");
    logmessage(" ");
    var fnames = [];
    var i = 0;
    for (i_yes=0; i_yes<fnames_yes.length; i_yes++) {
        var noexists = false;
        for (i_no=0; i_no<fnames_no.length; i_no++) {
            if (fnames_yes[i_yes]==fnames_no[i_no]) {
                noexists = true;
                break;
            }
        }
        if (!noexists) {
            fnames[i++] = fnames_yes[i_yes];
            logmessage("\t" + (i-1) + ": " + fnames[i-1] + ext_yes);
        }
    }

    return fnames;
}



// --------------------------------------------------
// BatchRender
// --------------------------------------------------

function BatchRender(fnames, ext) {
    // apply and render
    for (var i=0; i<fnames.length; i++) {
    	logmessage(fnames[i] + ext);

    	// apply C3D
    	fr_C3DToFaceRobot(fnames[i] + ext);

    	// set up render settings
    	SetValue("Passes.Default_Pass.RenderOptions.ImageFileName",		fnames[i] + ".#.pic");
    	SetValue("Passes.Default_Pass.RenderOptions.EndFrame",			GetValue("PlayControl.Out"));
    	SetValue("Passes.Default_Pass.RenderOptions.RenderEngine",		"OpenGL");
    	SetValue("Passes.Default_Pass.RenderOptions.CreateMovie",		true);
    	SetValue("Passes.Default_Pass.RenderOptions.MovieFormat",		"mov", null);
    	SetValue("Passes.Default_Pass.RenderOptions.MovieFileName",		fnames[i] + ".mov");
    	SetValue("Passes.Default_Pass.RenderOptions.MovieCodec",		"AAAAFnNwdGxTVlEzNQEBAAAYAAADAAAAABR0cHJsAAAD/wAd+FEAAAAYAAAAGGRyYXQAAWgAAAAAUwAAAQAAAAEAAAAACW1wc28AAAAADG1mcmEAAAAAAAAADHBzZnIAAAAAAAAACWJmcmEAAAAACm1wZXMAAAAAABxoYXJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKc2RuZQAAAAAADGNtZnJTTUkgAAAAAA==", null);
    	SetValue("Passes.Default_Pass.RenderOptions.DeleteOrgMovieImages",	true);

    	// perform render
    	RenderPass();
    }
}

This page was last modified 20:45, 6 Aug 2009.
This page has been accessed 3973 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy