3dsMAXで、シーンの合成をすると異常に重くなったり、フリーズして落ちる場合の対処法

 

久しぶりの3Dネタです。
仕事で、シーンファイルの合成をすると必ず落ちる不具合が発生しました。不具合が発生したシーンのオブジェクトを、正常なファイルに1つでも合成すると、正常なファイルでも不具合が起きて直らなくなるという。まさにウイルスの様なバグ。

原因と対処法を探しましたので、メモしておきます。

 

不具合内容

3dsMAXで、「合成」をすると極端に重くなる。またはフリーズする。または3dsMAXが落ちる。この現象が起きたファイルは、ファイルサイズが異常に大きくなる。その状態のファイルを正常なファイルに合成すると、正常なファイルも同様の症状が発生。シーン内の全てのオブジェクト、マテリアルを削除しても直らない。正にウイルス…!

 

不具合が起きたファイルから全オブジェクトノードを削除し、ボックスを1個置いたシーンがこちら。

03

 

頂点数8でポリゴン数12ってのが謎ですが…。まぁいいか。

【2015/10/18追記】壮大な勘違いでした。頂点数8のボックスのメッシュオブジェクトのポリゴン数は12で合っています。3dsMAXは「面」「メッシュ」「ポリゴン」を混同しがちなので、気をつけないとダメですね。非平面は3D空間に描画できないので、面は必ず3頂点で構成されます。ボックスのポリゴンは6つで、4頂点で構成されるポリゴンは2つの面でできています。なので、12面。メッシュオブジェクトではポリゴンと面を同じものとして扱うので、シーン情報のメッシュ総数は頂点8、ポリゴン数12で合っている訳です。【追記ここまで】

ファイル名のつづりが間違ってるのも気にせんといてください。
中身は頂点数8のボックス1個なのに、ファイルサイズを見ると9MB近くもあるで…!

01

 

原因

ワールド直下のトラックビューノードにゴミがたまっているのが原因です。ゴミの正体はコントローラーノードで、何らかの理由で生成されたトラックビューノードが、ファイル合成を繰り返す事で蓄積されてしまいます。シーンが徐々に重くなり、気づいた頃にはファイル合成で落ちるほどのノード数になっています。

ちなみに、ワールド直下にくっついてるトラックビューノードはシーン内の全オブジェクトを削除しても消えません。しかも、見えません。

 

対策方法

スクリプトを使って、不要に溜まったトラックビューノードのコントローラーを削除します。主に、リタイマー、アニメーションレイヤーが原因の様なので、この2つを削除します。問題を認識した時点ですでに大量に生成されているはずなので、3dsMAXのGUI上で未使用のコントローラーを選別して削除するのは困難です。そこで、スクリプトでキーが設定されていないコントローラーを選別して削除します。

3dsMAX 2008以降でAutodeskに類似の不具合報告があります。
このバグではモーションクリップを削除していますが、リタイマーやアニメーションレイヤーでも動揺の症状が発生する様です。

http://tech.autodesk.jp/faq/faq/adsk_result_dd.asp?QA_ID=6445

 

スクリプト 「リタイムクリーナーさん」

=========================
RTC_Cleaner3.ms_.zip
=========================

※ MITライセンス(動作無保証です)
※Macで圧縮してるので、widnowsで解答すると文字化けするかもしれません。

 

スクリプト起動して、ゴミを削除するとファイルサイズが正常に戻ります。

02

 

スクリプトの内容について

このスクリプトは、3dsMAX 2014以降に対応しています。
下記スクリプトを実行すると、3段階の確認ダイアログが表示されます。

削除処理が始まるとフリーズした様に見えるかもしれませんが、10分ほど待つと完了画面が表示されます。

/* ================================
RTC Cleaner v1.0
License is MIT. (c)DENSHIs / yuki
================================ */
if querybox "[1/3]  不自然に生成されたリタイマーのゴミを削除します" title:"RTC_Cleaner" do(
	tv = trackviewnodes
	rtm = tv[#Retimer_Manager]
	if rtm != undefined do (
		deleteTrackViewController tv rtm.controller
	gc()
	)
)

if querybox "[2/3]  不自然に生成されたアニメーションレイヤーのゴミを削除します" title:"RTC_Cleaner" do(
	tv = trackviewnodes
	alc = tv[#Anim_Layer_Control_Manager]
	if alc != undefined do (
		deleteTrackViewController tv alc.controller
	gc()
	)
)

count = RetimerMan.numRetimers

if querybox ("[3/3]  " + count as string + "個のリタイムコントローラーが見つかりました。¥n使用されていないコントローラーを削除します。¥nこの処理に5分〜15分ほど掛かる場合があります" title:"RTC_Cleaner") do(
	progressstart "リタイムコントローラーを掃除中"
	
	/* reference method */
	get_rt = RetimerMan.GetNthRetimer
	del_rt = RetimerMan.DeleteRetimer
	
	undo off
	/* remove roop*/
	for i = 1 to count where (rtc = get_rt (count-i+1); rtc != undefined and rtc.nummarkers==0) do(
		progressupdate (i/count )
		del_rt (count-i+1)
	)
	
	/* end  */
	gc()
	progressend()
	undo on
	
	/* repot message */
	new_count = count - RetimerMan.numRetimers
	messagebox ("シーンから未使用の " + new_count as string + "個のコントローラーを削除しました。" title:"正常に終了しました")
)