MSFS の隠面処理について


隠面処理の概要

ここでは MSFS の隠面処理について説明します。

最初にお断りしておきますが、この章で述べることはかなり私の推測が 交じっているので、もしかすると嘘が交じっているかもしれません。 あらかじめご了承ください。

MSFS での隠面処理は基本的に以下の3つにより行われています。

  1. RefPoint の距離による判定
  2. 面の表裏の判定
  3. シーナリ作成者が明示的に指定した描画順序の判定
順に説明しましょう。まず、1番目についてですが、これは前の方でも 説明したとおり、遠くの RefPoint から順に描画するというものです。

次に、面の表裏の判定です。MSFS で描画される面(ビルの面とか)には 表裏の属性があります。で、表から見ると面が表示され、裏から見ると 面が見えない、というように処理するんですね。

表裏の属性ですが、 面の法線ベクトルと、RefPoint からの面への垂直距離で指定します。 んが、SCASM は賢いので、普通はこれは自動的に計算してくれます。 普通じゃないときはシーナリ作成者が計算しないといけません。ま、 これはあとで説明しましょう。

最後の明示的に描画順序を指定するものですが、これは凹型をしたような 複雑な物体を描くときに必要になります。この場合、見る位置によって物体 の描画順序を適宜変更しなければなりません。これはちょいとムズイし、面倒 ですが、丁寧にやればちゃんとできます。

ちなみに、Flight Shop で機体を作成した人なら知っていると思いますが、 Glue Template というのがまさにこれと同じ役割を果たしています。


RefPoint の距離による隠面処理

これは先に説明した通りです。

この例では左のビルを右のビルより先に描画することにより隠面処理を行います。 つまり、オブジェクトの参照点の距離が遠い方から順に描画するわけですね。

でも、実はこの方法ではうまくいかないことがあります。RefPoint が遠くにある 物体が RefPoint の近い方にある物体を隠すこともあるのです。これは、物体同士 がかなり近くにあり、かつ、物体の長さが長かったり、物体が凹型だったりすると 起こります。たとえば、名古屋シーナリでテレビ塔にむけてレーザービームが伸びています が、これと近くのビルの描画順序が逆転することがあります。

まあ、でも細かいことはこの際気にしないことにしましょう。気になる人はあとの 方で述べることを良く読んでください。


表と裏の判別

自動的な表裏の判別

SCASM を使う場合、面の表裏の判別は自動でできます。たとえば Poly 命令を使うとき、 などというように、'a' を指定すれば自動になります。この場合、いかに示すように RefPoint と反対の位置から面が見え、RefPoint の側からは見えなくなります。

普通は RefPoint は物体の中央にくるように物体を作るはずなので、普通は自動で OK のはずです。

んが、これを逆にしたい時もあるはずです。たとえば凹型の物体を定義したとき に、内側の面で逆にしたくなるはずですね。そういう場合は

のようにすれば逆方向から見えるようになります。

ベクトル演算(うげ)

さて、ここではこの表裏の判定がどのようになされているのか、数学的に 考察してみましょう。高校程度の数学の知識で理解できるはずです。あ、そこのあなた、 逃げないように (^^)

表裏の判別で必要になるパラメータは以下の2つです。

以下の図を見てください。

nが法線ベクトル、d が RefPoint から面への垂直距離、r は視線ベクトル(RefPoint から視点へむけたベクトル)です。

さて、ここで内積 r・n を計算します。そうするとこれは参照点 から点 A までの距離になります。点 A は視点から面の法線へ垂直に 降ろした交差点です。そして、この値と d を比較すれば、視点が面の どちら側にあるか、つまり面が見えるかどうかが判定できます。 すなわち、

ということになるわけです。 おわかりいただけたでしょうか?

なお、この場合は面の右側から見える場合の説明をしましたが、これが 逆、つまり参照点の側から見えるようにする場合は以下のようにします。

これで OK です。なぜこうなるのかは考えてみてください(逃げ ^^;)

なお、SCASM ではこの法線ベクトルと d の値を明示的に指定することが できます。ただ、法線ベクトルの各成分は 32767 倍しなければなりません。 この理由については以下に続く。


ベクトル演算のヨタ話

ここはヨタ話なので、興味のないひとは飛ばしてください。

MSFS のシーナリファイルでは法線ベクトルは 32767倍 した値で計算されます。 なぜでしょう?普通は長さが1のベクトルをそのまま使えばいいはずです。 法線ベクトルを 32767 した場合、さきほどの内積計算をしたあと、32767 で割ってやらないといけないのです。

おそらくこれは、計算速度をあげるための措置だと考えられます。 法線ベクトルは長さが1なので、通常法線ベクトルの各成分は -1 から 1 の 値になります。これをそのまま計算に使う場合、浮動小数点演算をしなけれ ばなりません。でも、これだと時間がかかってしょうがありません。

これをさけるため、MSFS では法線ベクトルの各成分を 32767 倍して小数点以下 を切り捨てたものを使って計算を行っているようなのです。これなら整数演算 になるので、計算が早くなるというわけです。

ただ、この場合、計算結果を 32767 で割ってやらないといけません。 でも割り算は結構時間のかかる計算なので嬉しくありません。何とかしたいですね。

ここで、32767 という数値が意味を持ってくるのです。私の推測では、恐らく ここでは 32768 で割り算をしていると思います。32768 は 2 の 15 乗ですから、 32768 で割るのは単なるビットシフト演算ですむのです。(たとえば、32986.52 という 数値を 1000 で割るときにいちいち筆算する人はいませんよね。小数点の位置を ずらして 32.98652 を答えとします。これと同じことです)

もちろん、この場合、計算結果は 32767/32768 倍になる(1ではない)ので、 誤差がでるわけですが、まあこの程度の誤差なら許してね、ということなんでしょう。

それじゃ、32767 じゃなくて 32768 倍しときゃいいじゃないか、という 意見もあるかもしれません。でも法線ベクトルの各成分は最大で 1 になる可能性 があるので、32768 倍してしまうと 16 ビットで納まらなくなってしまうんですね。 で、32767 にしたと。

まあ、そういった理由で 32767 倍した値を使っているんだと思いますよ。きっと。 責任は持ちませんが (^^;)


ユーザー指定の隠面判定

ここではシーナリ作成者が描画順序を明示的に指定しなければならない 場合を説明しましょう。

描画順序が一意に決まる場合

まずは、描画順序が一意に決まる場合です。

下の図を見てください。かなりアバウトな図ですが気にしないように。

ここで、A の面と B の面に注目してください。この場合、B の面は A の 面の一部を隠していますね。でも A の面が B の面を隠すことは絶対に ありませんね。(よく考えてみてください)

つまり、この場合は A の面から先に描くようにしておけばいい、というわけ です。つまり、A の描画命令(Poly とか) を B の描画命令の前におけば いいことになります。逆にすると変なことになりますよ。

なお、この場合は内側の3つの面を全部先に描画してください。ほかはどんな 順序で描画しても OK です。

この例に限らず、凹型の物体を描くときは、

というのが鉄則です。ま、たまにそううまくいかないこともありますけどね。

描画順序が一意に決まらない場合

上の例では描画順序が一意に決まるのですが、上手く決まらないこともあります。

以下の例を見てください。

名古屋シーナリのテレビ塔の描画に使っている方法を示しましょう。 (注:これは古いバージョンのもので、新しいバージョンの名古屋シーナリでは そうなっていません)

このテレビ塔では描画順序が一意に決まりません。下から順に描く場合、 たとえば視点が E の位置にあったらどうなるでしょうか?下側の階(黒くぬった 部分)により一番したの鉄骨が隠れてしまいますね。上から順に描く場合、 視点が A の位置にあるとやっぱりだめです。(考えてみてください)

この場合は描画順序を臨機応変に切り替えないとだめです。 ここで登場するのが VectorJump 命令です。名古屋シーナリの中で以下のように 使っています。

これは、4, 5, 6, 7 番の点で定義される面を境にして、RefPoint の側に 視点がある場合に :p1 にジャンプする、という意味です。ここで、4,5,6,7 番の点は上の図の D と E の境目の点です。ですから、この場合、 視点が E の位置にあるときに :p1 にジャンプするわけです。 同様に A, B, C, D の場合分けをして、それぞれの場合別に描画順序を 変えれば良いわけです。詳しくは名古屋シーナリに付属しているソースの nagtvtow.scm を見てください。

なお、これは Flight Shop の機体作成時にでてくる Glue Template と 同じ役割を果たしている(というか、実はまったく同じもの)のです。


[次ページ] [目次]