ここでは、ユーザが Z 軸に沿ってオブジェクトを移動させ、指定されたサーフェスに合わせる方法について説明します。このスクリプトを使用して、地面の上に樹木やポールなどを自動的に配置することができます。
関連トピック:
全体の流れ:
ボタン、メニュー項目またはショートカットとして使用できる macroScript としてコードをパッケージ化します。
オブジェクトを Z 軸のサーフェスに下方向へ移動するカスタム関数を定義します。
ターゲット オブジェクトに移されるオブジェクトの位置から始めて、-Z に沿って交差を検出します。
交差が検出できない場合は、オブジェクトの位置を Z まで投影し、再び -Z 軸まで交差させます。
交差を関数の結果として返します。
オブジェクトが選択されているときにのみ、macroScript を有効にします。
macroScript が実行されているときに、ユーザにターゲット オブジェクトを選択してもらいます。
Geometry オブジェクトのみが選択されるように、選択にフィルタを適用します。
有効なオブジェクトが選択された場合は、アンドゥ コンテキストを有効にします。
すべてのオブジェクトを巡回し、それぞれに対して交差の関数を呼び出します。
交差が未定義でないかぎり、オブジェクトを交差に移動します。
MAXScript
macroscript MoveToSurface category: "HowTo" ( fn g_filter o = superclassof o == Geometryclass fn find_intersection z_node node_to_z = ( local testRay = ray node_to_z.pos [0,0,-1] local nodeMaxZ = z_node.max.z testRay.pos.z = nodeMaxZ + 0.0001 * abs nodeMaxZ intersectRay z_node testRay ) on isEnabled return selection.count > 0 on Execute do ( target_mesh = pickObject message:"Pick Target Surface:" filter:g_filter if isValidNode target_mesh then ( undo "MoveToSurface" on ( for i in selection do ( int_point = find_intersection target_mesh i if int_point != undefined then i.pos = int_point.pos )--end i loop )--end undo )--end if )--end execute )--end script
macroscript MoveToSurface category:"HowTo"
(
macroScript は MoveToSurface
と呼ばれます。スクリプトを使用する場合は、[カスタマイズ] (Customize)に移動してスクリプトを[HowTo]カテゴリからツールバー、メニュー、またはクアッド メニューにドラッグするか、キーボード ショートカットを割り当てることができます。
fn g_filter o = superclassof o == Geometryclass
このカスタム関数は、ジオメトリ オブジェクトに対するフィルタとして使用されます。この関数はパラメータとしてオブジェクトを受け取り、そのオブジェクトが Geometry スーパークラスの場合は true、それ以外の場合は false を返します。
fn find_intersection z_node node_to_z =
(
このカスタム関数は、実際のレイの交差を行います。この関数はパラメータとしてオブジェクトを受け取り、そのオブジェクトが Geometry スーパークラスの場合は true、それ以外の場合は false を返します。
local testRay = ray node_to_z.pos [0,0,-1]
ここで、移動されるオブジェクトの開始位置と -Z 軸に沿った方向で、カスタムの Ray 値を定義します。
local nodeMaxZ = z_node.max.z
また、サーフェスが交差する max.Z 座標も取得します。
testRay.pos.z = nodeMaxZ + 0.0001 * abs nodeMaxZ
次に、レイの Z 位置を交差するサーフェスの最も高い Z 位置よりやや上に移動します。このようにして、レイが -Z 軸に沿ってサーフェスにヒットする機会があることを確認します。
intersectRay z_node test_ray
組み込み intersectRay 関数は、ノードとレイ (開始ポイントと方向付きの間隔ベクトル) を指定され、レイがノードのサーフェスをヒットしたときはスペース内のそのポイントを返し、交差がない場合は undefined を返します。この交差の結果も、計算された最後の値であるため、関数の戻り値です。
)
on isEnabled return selection.count > 0
少なくとも 1 つのオブジェクトが選択されている場合にのみ、このスクリプトには意味があります。シーン内に選択されたオブジェクトがない場合、スクリプトは無効になります。'on isEnabled' ハンドラは、'return' ステートメントの後の式を評価して、有効状態をコントロールします。結果が false
の場合、スクリプトのボタン応答メニュー項目は淡色表示され、アクティブにすることはできません。
Macroscript_Body_Event_Handlers
on Execute do (
このスクリプトの本体は、「on Execute」ハンドラに含まれています。これは、ボタンを押したり、メニュー項目を選択したり、割り当てられているショートカット キーを押したりすることでスクリプトが起動すると実行されます。
Macroscript_Body_Event_Handlers
target_mesh = pickObject message:"Pick Target Surface:" filter:g_filter
pickObject 関数によって、ユーザがシーン内でオブジェクトを選択できるようになります。ここに提供したフィルタ関数によって、Geometry オブジェクトのみを選択できるようにします。マウスが Lights、Helpers などの他のオブジェクトの上に移動しても、それらのオブジェクトは登録されません。結果は、ユーザ変数の target_mesh に書き出されます。選択が取り消された場合、この変数には選択したノードまたは undefined のいずれかが含まれます。
if isValidNode target_mesh then
(
選択されたオブジェクトが有効なオブジェクトの場合(つまり、ユーザが実際にオブジェクトを選択して、取り消しのために[Esc]キーを押したり、マウスを右クリックしたりしなかった場合)
undo "MoveToSurface" on
(
必要に応じてすべてのオブジェクトを元の状態に戻すことができるようにするアンドゥ コンテキストを定義します。
for i in selection do
(
さらに、現在の選択内のすべてのオブジェクトを巡回するループを作成します。ループの反復ごとに、変数 i には選択からの別のオブジェクトが含まれます。
int_point = find_intersection target_mesh i
ここで、定義したユーザ関数を呼び出し、ユーザによって選択された target_mesh オブジェクトと、選択を巡回するループ内の現在のオブジェクトを渡します。結果は、undefined または交差のポイント、つまり -Z に沿ったターゲット オブジェクトのサーフェス上にあるオブジェクトの位置の投影です。
if int_point != undefined then i.pos = int_point.pos
交差が実際に存在する場合は、現在のオブジェクトの位置をそのポイントに設定するだけです。存在しない場合、つまり交差が undefined の場合は、このステップをスキップします。
)--end i loop
)--end undo
)--end if
)--end execute
)--end script
スクリプトを評価します。スクリプトを使用する場合は、[カスタマイズ] (Customize)を使用して、スクリプトを[HowTo]カテゴリからツールバー、メニュー、またはクアッド メニューにドラッグするか、キーボード ショートカットを割り当てることができます。
サーフェスに移動するオブジェクトを任意の数だけ選択します。スクリプトを起動し、移動するオブジェクトを選択します。
このスクリプトを起点として、任意のワールドで、またはローカルな方向で位置合わせができる軸コントロールを追加することができます。
戻る