動画の位置と寸法の中間値を作成するアニメーションテンプレート



	コマ割りエクスプレッションセット

	タイムリマップされたレイヤの位置と寸法の中割を補助します。

	アニメーションテンプレートを適用するレイヤのすぐ上に
	トレーサ用のレイヤを設定してセル(動画)の動きをトレースします。

	このアニメーションテンプレートは、トレーサの動きを追跡します。
	トランスフォームエフェクトのanchorPoint,position,scale およびrotationを制御して
	タイムリマップにキーのないフレームにキー位置から計算した中間の位置と寸法、傾きを
	レイヤに適用します。

	このエクスプレッションを使用するレイヤには、タイムリマップにキーが必須です。
	キーのあるフレームのジオメトリは保持されます。

	ネストの必要がある場合は、対象レイヤをあらかじめプリコンポするか、
	またはトランスポートエフェクトの値をエクスプレッション等で参照してください。
	
2007/09/08	nekomataya kiyo


以下は簡易版ソース
位置のオフセットのみを処理するので動作は軽快です。
セルごとのサイズや角度の差が大きい時はフルスペック版を推奨

/*
	即席版コマ割りエクスプレッション
	タイムリマップされたレイヤの位置の中割をします。
	このエクスプレッションは、ポジションまたはオフセットに適用してください。
	トランスフォームエフェクトのポジションもOK
	トレーサー用のレイヤを設定してそのレイヤでセルの動きをトレースします。
	このエクスプレッションはトレーサの動きを追跡します。
	タイムリマップにキーのある位置は保持されます。
2007/09/01	nekomataya kiyo
*/
	var myTracer=thisComp.layer(index-1);
	var baseTime=0;

//直前のタイムリマップキーの時間を取得
	if(this.timeRemap.numKeys>1){
if(this.timeRemap.nearestKey(time).time>time)
{
	baseTime=this.timeRemap.key(this.timeRemap.nearestKey(time).index-1).time;
}else{
	baseTime=this.timeRemap.nearestKey(time).time;
}
	}else{
if(this.timeRemap.numKeys==1 && this.timeRemap.key(1).time<time){
	baseTime=this.timeRemap.key(1).time;
}
	}

//直前キーの時間と現在のフレーム差を取得
var mySliceOffset=(time-baseTime)/thisComp.frameDuration;
//トレースレイヤのbaseTime位置と現在位置の差分を本体レイヤの位置に反映する。
add(this.value,sub(myTracer.position.valueAtTime(time),myTracer.position.valueAtTime(baseTime)));


以下はフルスペック版ソース
トランスポートエフェクトのanchorPoint,Position,scale,rotation に対して適用してください。



/****** for anchorPoint *******/
//各プロパティ共通部分
	var myTracer=(index>2)?thisComp.layer(index-1):thisComp.layer(1);//ひとつ上のレイヤを設定
	var baseTime=0;
//直前のタイムリマップキーの時間を取得
	if(this.timeRemap.numKeys>1){
if(this.timeRemap.nearestKey(time).time>time)
{	baseTime=(this.timeRemap.nearestKey(time).index>2)?this.timeRemap.key(this.timeRemap.nearestKey(time).index-1).time:0;
//ケースによって直前キーが存在しない場合例外処理として0を設定
}else{	baseTime=this.timeRemap.nearestKey(time).time;
}	}else{
if(this.timeRemap.numKeys==1 && this.timeRemap.key(1).time<time)
{	baseTime=this.timeRemap.key(1).time;
}	}
//各プロパティ共通部分オワリ


//アンカーポイントをトレーサの位置をレイヤローカル座標に変換して置き替え
if(myTracer.position.value.length==2){
	myTracer.position.valueAtTime(baseTime);
}else{
//スケール
//トレースレイヤの表示比率取得 AE6.5以降版
//デフォルトカメラの値を設定(推測ナノデはずれてたら御免)
	var myZoom=Math.tan(degreesToRadians((180-39.5980)/2))*(thisComp.width/2);
	var cameraPosition=[thisComp.width/2,thisComp.height/2,-myZoom];
//レイヤにカメラがあるかチェックする
var hasCamera=false;
for(idx=1;idx<=thisComp.numLayers;idx++){
	if((thisComp.layer(idx) instanceof Camera)&&(thisComp.layer(idx).active)){hasCamera=true;break;}else{continue;}
}
//カメラレイヤがあればアクティブカメラを使う(アクティブカメラがない場合はエラー)
if(hasCamera){
	myZoom=thisComp.activeCamera.zoom;
	cameraPosition=thisComp.activeCamera.position;
}
//視点からレイヤまでの距離を出して比の逆数で計算
//var myBaseDistance=length(cameraPosition,myTracer.position.valueAtTime(baseTime));//カメラ位置からキー位置のトレーサまで距離
var myBaseDistance=Math.abs(cameraPosition[2]-myTracer.position.valueAtTime(baseTime)[2]);
var myDistance=Math.abs(cameraPosition[2]);//カメラ位置から投影面中央まで距離

//zoom動作とanchorオフセットを考慮した計算
//var myScale=(myZoom/myBaseDistance)*myBaseDistance/length(sub(myDistance,cameraPosition));
var myScale=(myDistance/myBaseDistance);

	toComp(
		add(mul(
			sub(fromComp(
				myTracer.position.valueAtTime(baseTime)
			),[width/2,height/2]),myScale
		),[width/2,height/2])
	);//	3D処理
}

/****** for position *******/
//各プロパティ共通部分
	var myTracer=(index>2)?thisComp.layer(index-1):thisComp.leyer(1);//ひとつ上のレイヤを設定
	var baseTime=0;
//直前のタイムリマップキーの時間を取得
	if(this.timeRemap.numKeys>1){
if(this.timeRemap.nearestKey(time).time>time)
{	baseTime=(this.timeRemap.nearestKey(time).index>2)?this.timeRemap.key(this.timeRemap.nearestKey(time).index-1).time:0;
//ケースによって直前キーが存在しない場合例外処理として0を設定
}else{	baseTime=this.timeRemap.nearestKey(time).time;
}	}else{
if(this.timeRemap.numKeys==1 && this.timeRemap.key(1).time<time)
{	baseTime=this.timeRemap.key(1).time;
}	}
//各プロパティ共通部分オワリ

//トレーサの位置をコンポ内の座標に変換して置き替え
if(myTracer.position.value.length==2){
	myTracer.position.valueAtTime(time);//	2D処理
}else{
//スケール
//トレースレイヤの表示比率取得 AE6.5以降版
//デフォルトカメラの値を設定(推測ナノデはずれてたら御免)
	var myZoom=Math.tan(degreesToRadians((180-39.5980)/2))*(thisComp.width/2);
	var cameraPosition=[thisComp.width/2,thisComp.height/2,-myZoom];
//レイヤにカメラがあるかチェックする
var hasCamera=false;
for(idx=1;idx<=thisComp.numLayers;idx++){
	if((thisComp.layer(idx) instanceof Camera)&&(thisComp.layer(idx).active)){hasCamera=true;break;}else{continue;}
}
//カメラレイヤがあればアクティブカメラを使う(アクティブカメラがない場合はエラー)
if(hasCamera){
	myZoom=thisComp.activeCamera.zoom;
	cameraPosition=thisComp.activeCamera.position;
}
//視点からレイヤまでの距離を出して比の逆数で計算
//var myBaseDistance=length(cameraPosition,myTracer.position.valueAtTime(baseTime));//カメラ位置からキー位置のトレーサまで距離
var myBaseDistance=Math.abs(cameraPosition[2]-myTracer.position.valueAtTime(time)[2]);
var myDistance=Math.abs(cameraPosition[2]);//カメラ位置から投影面中央まで距離

//zoom動作とanchorオフセットを考慮した計算
//var myScale=(myZoom/myBaseDistance)*myBaseDistance/length(sub(myDistance,cameraPosition));
var myScale=(myDistance/myBaseDistance);

	toComp(
		add(mul(
			sub(fromComp(
				myTracer.position.valueAtTime(time)
			),[width/2,height/2]),myScale
		),[width/2,height/2])
	);//	3D処理
}
/****** for scale *******/
//各プロパティ共通部分
	var myTracer=(index>2)?thisComp.layer(index-1):thisComp.leyer(1);//ひとつ上のレイヤを設定
	var baseTime=0;
//直前のタイムリマップキーの時間を取得
	if(this.timeRemap.numKeys>1){
if(this.timeRemap.nearestKey(time).time>time)
{	baseTime=(this.timeRemap.nearestKey(time).index>2)?this.timeRemap.key(this.timeRemap.nearestKey(time).index-1).time:0;
//ケースによって直前キーが存在しない場合例外処理として0を設定
}else{	baseTime=this.timeRemap.nearestKey(time).time;
}	}else{
if(this.timeRemap.numKeys==1 && this.timeRemap.key(1).time<time)
{	baseTime=this.timeRemap.key(1).time;
}	}
//各プロパティ共通部分オワリ

if(myTracer.position.value.length==2){
//	2D処理
//スケール
	100*myTracer.scale.valueAtTime(time)[0]/myTracer.scale.valueAtTime(baseTime)[0];
}else{
//	3D処理
//スケール
//トレースレイヤの表示比率取得 AE6.5以降版
//デフォルトカメラの値を設定(推測ナノデはずれてたら御免)
	var myZoom=Math.tan(degreesToRadians((180-39.5980)/2))*(thisComp.width/2);
	var cameraPosition=[thisComp.width/2,thisComp.height/2,-myZoom];
//レイヤにカメラがあるかチェックする
var hasCamera=false;
for(idx=1;idx<=thisComp.numLayers;idx++){
	if((thisComp.layer(idx) instanceof Camera)&&(thisComp.layer(idx).active)){hasCamera=true;break;}else{continue;}
}
//カメラレイヤがあればアクティブカメラを使う(アクティブカメラがない場合はエラー)
if(hasCamera){
	myZoom=thisComp.activeCamera.zoom;
	cameraPosition=thisComp.activeCamera.position;
}
//視点からレイヤまでの距離を出して比の逆数で計算
var myBaseDistance=length(cameraPosition,myTracer.position.valueAtTime(baseTime));//カメラ位置からキー位置のトレーサまで距離
var myDistance=length(cameraPosition,myTracer.position.valueAtTime(time));//カメラ位置から現在のトレーサまで距離

//zoom動作とanchorオフセットを考慮した計算
//var myScale=(myZoom/myBaseDistance)*myBaseDistance/length(sub(myDistance,cameraPosition));
var myScale=(myBaseDistance/myDistance);

100*myScale*(myTracer.scale.valueAtTime(time)[0]/myTracer.scale.valueAtTime(baseTime)[0]);

//この値はスケールの比が1:1でロックされていることが前提です。
//トレーサ・適用セルともにスケールの連動プロパティを固定してください。
}

/****** for rotation *******/
//各プロパティ共通部分
	var myTracer=(index>2)?thisComp.layer(index-1):thisComp.leyer(1);//ひとつ上のレイヤを設定
	var baseTime=0;
//直前のタイムリマップキーの時間を取得
	if(this.timeRemap.numKeys>1){
if(this.timeRemap.nearestKey(time).time>time)
{	baseTime=(this.timeRemap.nearestKey(time).index>2)?this.timeRemap.key(this.timeRemap.nearestKey(time).index-1).time:0;
//ケースによって直前キーが存在しない場合例外処理として0を設定
}else{	baseTime=this.timeRemap.nearestKey(time).time;
}	}else{
if(this.timeRemap.numKeys==1 && this.timeRemap.key(1).time<time)
{	baseTime=this.timeRemap.key(1).time;
}	}
//各プロパティ共通部分オワリ

//Z軸の回転のみ処理
if(myTracer.position.value.length==2){

	myTracer.rotation.valueAtTime(time)-myTracer.rotation.valueAtTime(baseTime);//2D
}else{
	myTracer.rotation.valueAtTime(time)-myTracer.rotation.valueAtTime(baseTime)+myTracer.orientation.valueAtTime(time)[2]-myTracer.orientation.valueAtTime(baseTime)[2];//3D
};


