// Export Animation to Shake // // After you source the script, simply select a camera, then the object (which has the animation you wish // to export) and run bakeSelectedObj2dPos. It often helps to stick the command on a shelf button (middle mouse // button drag the text to the shelf). The shake tracker data will come up in the script editor and you can // copy and paste it straight into the shake UI. // // You may encounter problems if the resolution and camera gate have different aspect ratios. // // jeremy@thereisnoluck.com global proc float round( float $x, int $decimalPlaces ) { $xx = $x * pow( 10, $decimalPlaces ); return ( (($xx-floor($xx))>0.5) ? ceil($xx) : floor($xx) ) / pow( 10, $decimalPlaces ); } global proc vector worldPos( string $obj ) { if ( `objectType $obj` != "transform" ) { string $parent[] = `listRelatives -p $obj`; $obj = $parent[0]; } float $worldPf[] = `xform -q -ws -t $obj`; return << $worldPf[0], $worldPf[1], $worldPf[2] >>; } global proc vector worldToObj ( vector $p, string $obj ) { float $wm[16] = `getAttr ($obj + ".worldInverseMatrix")`; return <<(( $wm[0] * $p.x ) + ( $wm[4] * $p.y ) + ( $wm[8] * $p.z ) + $wm[12]), (( $wm[1] * $p.x ) + ( $wm[5] * $p.y ) + ( $wm[9] * $p.z ) + $wm[13]), (( $wm[2] * $p.x ) + ( $wm[6] * $p.y ) + ( $wm[10] * $p.z ) + $wm[14]) >>; } global proc vector calcCameraBackLocation( string $obj, string $cam ) { vector $worldP = worldPos( $obj ); vector $cameraP = worldToObj( $worldP, $cam ); // if the render ratio and the camera gate do not match, the width and height will have to be // scaled... but only horizontal fitting is implemented at the moment float $vertFitRatio = 1.0; float $renderAspect = `getAttr defaultResolution.deviceAspectRatio`; float $cameraGateAspect = `camera -q -ar $cam`; if ( ( $renderAspect - $cameraGateAspect ) > 0.001 ) { print( "Render aspect (" + $renderAspect + ") is not equal to camera gate aspect (" + $cameraGateAspect + "), assuming \"horizontal\" fit.\n" ); $vertFitRatio = $cameraGateAspect / $renderAspect; } // calculate height and width in camera perspective float $vfw = `camera -q -vfv $cam`; float $height = 2.0 * tan( deg_to_rad( $vfw / 2.0 ) ) * abs( $cameraP.z ) * $vertFitRatio; float $hfw = `camera -q -hfv $cam`; float $width = 2.0 * tan( deg_to_rad( $hfw / 2.0 ) ) * abs( $cameraP.z ); // calculate in render resolution float $cameraXRes = `getAttr defaultResolution.width`; float $cameraYRes = `getAttr defaultResolution.height`; float $x = ( $cameraP.x / $width + 0.5 ) * $cameraXRes; float $y = ( $cameraP.y / $height + 0.5 ) * $cameraYRes; return << $x, $y, 0 >>; } global proc bakeObj2dPos( string $obj, string $cam, int $startFrame, int $endFrame ) { /*$fileId = `fopen $exampleFileName`; fwrite $fileId "Hello there\n"; fclose $fileId;*/ // calculate screen space (X,Y) tracking data as seen from $cam float $camPosX[]; float $camPosY[]; for ( $frame = $startFrame; $frame <= $endFrame; $frame++ ) { currentTime $frame; vector $camPos = calcCameraBackLocation( $obj, $cam ); $camPosX[$frame] = $camPos.x; $camPosY[$frame] = $camPos.y; } // build the shake X and Y animation curves string $shakeXPosCurve = "Linear( 0 "; string $shakeYPosCurve = "Linear( 0 "; int $lineLengthMax = 80; int $lineLength = 0; for ( $frame = $startFrame; $frame <= $endFrame; $frame++ ) { $shakeXPosCurve += ", "; $shakeYPosCurve += ", "; $lineLength += 10; // hmm it's kindy arbitrary anyway if ( $lineLength > $lineLengthMax ) { $shakeXPosCurve += "\n"; $shakeYPosCurve += "\n"; $lineLength = 0; } $shakeXPosCurve += ( round( $camPosX[$frame], 2 ) + "@" + $frame ); $shakeYPosCurve += ( round( $camPosY[$frame], 2 ) + "@" + $frame ); } $shakeXPosCurve += " )"; $shakeYPosCurve += " )"; // build a shake "tracker" node to store the above animation data float $height = `getAttr defaultResolution.height`; float $trackBoxSize = $height / 30.0; float $trackBoxSearchSize = $height / 15.0; print( "Copy and then paste the following line into the shake node view window.\n" ); print( "Tracker(0, \"1\", \"1/16\", \"luminance\", 0.75, \"use start frame\", 0.5, \"stop\", 1, 1, " ); print( "\"" + $obj + "\",\n" + $shakeXPosCurve + ",\n" + $shakeYPosCurve + ",\n1, " ); //print( "width/2-height/30, width/2+height/30, height/2-height/30, height/2+height/30, "); print( $camPosX[$startFrame] - $trackBoxSize + ", " ); print( $camPosX[$startFrame] + $trackBoxSize + ", " ); print( $camPosY[$startFrame] - $trackBoxSize + ", " ); print( $camPosY[$startFrame] + $trackBoxSize + ", " ); //print( "width/2-height/15, width/2+height/15, height/2-height/15, height/2+height/15, " ); print( $camPosX[$startFrame] - $trackBoxSearchSize + ", " ); print( $camPosX[$startFrame] + $trackBoxSearchSize + ", " ); print( $camPosY[$startFrame] - $trackBoxSearchSize + ", " ); print( $camPosY[$startFrame] + $trackBoxSearchSize + ",\n" ); print( $shakeXPosCurve + ",\n" + $shakeYPosCurve + ", 1, 1 );\n" ); } global proc bakeSelectedObj2dPos() { string $objs[] = `ls -sl`; if ( size( $objs ) != 2 ) error "Please select a camera and then a locator"; else { bakeObj2dPos( $objs[1], $objs[0], `getAttr defaultRenderGlobals.startFrame`, `getAttr defaultRenderGlobals.endFrame` ); } }