質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2096閲覧

nearClipPlaneと境界

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2018/06/15 13:23

編集2018/06/15 13:23

前提・実現したいこと

3Dでゲームオブジェクトの画面外判定ができるようになりたいと思い調べていた所、
おそらくカメラのnearClipPlaneを使わなければならないという情報を
こちらのサイトで知りました。
しかし、このnearClipPlaneというものがどういうものなのかわかりません。
参考にしているサイトの図だと、カメラからアバウトな距離にこのnearClipPlaneというものがあるみたいですが、
そのことだけしかわかっていないです。
例えば、nearClipPlaneの前に(よりカメラに近い位置に)ゲームオブジェクトを配置しても、
そのオブジェクトはゲーム画面に映るはずなので、カメラとnearClipPlaneの距離は何なのかということもわかっていません。
似たようなものにfarClipPlaneというものもあるみたいですが、同様にわかりません。

ともかく、画面外判定をする為に、まずは画面の境界にゲームオブジェクトを配置することを目的に
nearClipPlaneを使ったコードと使っていないコードを2つ試してみましたが、
どちらも意図しない所に(画面の境界じゃない所)に配置されました。

・これらは何故、このような場所に配置されてしまったのかということ、
・画面の境界(今回は(0,0)の左下)に配置する方法、
・そしてnearClipPlaneについて(farClipPlaneは画面外判定に必要ないのか?という疑問も含めて)

を教えていただきたいです。
ご教授のほど宜しくお願い致します。

※ちなみにゲームオブジェクトは、現在の(ゲーム実行前のシーン上の)カメラとゲームオブジェクトの奥行の距離を保ったまま、
(0,0)の左下の境界の位置に配置したいです。

試したこと

ゲーム実行前に下記のようにゲームオブジェクトを配置しておきました。
上がシーンビューで下がゲーム画面です。

イメージ説明

・まず、nearClipPlaneを使わないで(0,0)の配置を試みました。

C#

1 void Start () { 2 Vector2 min = Camera.main.ViewportToWorldPoint(new Vector2(0, 0)); 3 this.transform.position = min; 4 }

ゲーム実行結果、意図しない配置になりました。
イメージ説明

・続いて、nearClipPlaneを使って(0,0)の配置を試みました。

C#

1 void Start () { 2 float myZ = this.transform.position.z; 3 Vector3 min = Camera.main.ViewportToWorldPoint(new Vector3 (0.0f, 0.0f, Camera.main.nearClipPlane)); 4 this.transform.position = new Vector3(min.x, min.y, myZ); 5 6 }

ゲーム実行結果、やはり意図しない配置になりました。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

おそらく意図する動きは、

C#

1 void Start() 2 { 3 // キューブのワールド座標をメインカメラから見たビューポート座標に直す 4 Vector3 viewportPosition = Camera.main.WorldToViewportPoint(this.transform.position); 5 6 // xとyを0に書き換える 7 // zにはメインカメラから見たキューブのカメラZ方向の位置...つまり奥行きの距離が入っているはずなので、書き換える必要はない 8 viewportPosition.x = 0.0f; 9 viewportPosition.y = 0.0f; 10 11 // ビューポート座標をワールド座標に直し、キューブの位置をそこに設定する 12 this.transform.position = Camera.main.ViewportToWorldPoint(viewportPosition); 13 }

プレビュー

でいけるかと思うのですが、ご質問者さんの実験結果がちょっと妙ですので、なにか他の問題があるかもしれません。
スクリプトがちゃんと目的のキューブにアタッチされているか(こちらは気づきやすいので間違ってはいないかと思いますが...)、カメラのタグが「MainCamera」になっているか、といった点を確認してみる必要がありそうです。
※下に追記しましたが、実験結果について説明が付きそうでしたので、この部分は取り下げます。

ViewportToWorldPointの日本語版リファレンスでは、英語版リファレンスに載っている詳しい解説がかなり欠落しているようです。

public Vector3 ViewportToWorldPoint(Vector3 position);

Parameters
position The 3d vector in Viewport space.

Returns
Vector3 The 3d vector in World space.

Description
Transforms position from viewport space into world space.

Viewport space is normalized and relative to the camera. The bottom-left of the viewport is (0,0); the top-right is (1,1). The z position is in world units from the camera.

Note that ViewportToWorldPoint transforms an x-y screen position into a x-y-z position in 3D space.

Provide the function with a vector where the x-y components of the vector are the screen coordinates and the z component is the distance of the resulting plane from the camera.

多少表現を補って解釈すると、下記のような内容かと思います。

public Vector3 ViewportToWorldPoint(Vector3 position);

パラメーター
position ビューポート空間における3Dベクトル

戻り値
Vector3 ワールド空間における3Dベクトル

説明
ビューポート空間におけるpositionをワールド空間における座標に変換します。
ビューポート空間は正規化された、カメラに対して相対的な座標系となります。ビューポートの左下は(0,0)、右上は(1,1)です。z位置はワールド座標系単位でのカメラからの位置です。
注意:ViewportToWorldPointはx-yからなるビューポート位置をx-y-zからなる三次元空間上の位置に変換します。引数として与えるベクトルはx-y成分にビューポート座標を、z成分に変換先平面のカメラからの距離を指定してください。

追記

nearClipPlane、farClipPlaneについてですが、これらはカメラのインスペクタの「Clipping Planes」の「Near」と「Far」に対応していて、カメラに対して前後にこの範囲を外れた部分はスッパリ切断されたように描画されなくなってしまいます。描画の都合上、カメラに極めて近い部分や無限に遠い部分を表示することはできないため、これらに適切な値を入れて前後方向の描画範囲を制限してやる必要があります(参考:【Unity】【数学】視錐台(Frustum)について(第1回) – 株式会社ロジカルビート)。
ご質問者さんの参考にされたサイトでzにnearClipPlaneを使っているのは多分「nearClipPlaneの位置が視錐台前後方向の手前側の境界だから」といった理由ではないでしょうかね。
今回重要なのは水平垂直方向の境界がワールド空間ではどの位置にあるかということであって、zについては本来のオブジェクトの位置を維持したいということなので、上に例示したコードのように元のビューポート座標のzをそのまま使えばいいかと思います。

さらに追記

ご質問者さんのコードをあらためて見直してみたところ、実験結果はこのように説明できそうでした。

  • nearClipPlaneを使わないで(0,0)の配置を試みた場合

カメラのワールド座標を(cx, cy, cz)とする。
Camera.main.ViewportToWorldPoint(new Vector2(0, 0))は型変換によってzが補われ、Camera.main.ViewportToWorldPoint(new Vector3(0, 0, 0))と解釈される。
得られるVector3は、引数として与えたビューポート座標のzが0なので、カメラを頂点とする四角錐の頂点...つまりカメラ自身の座標(cx, cy, cz)となる。
これを一旦Vector2型のminに代入したため型変換が起こり、czは欠落する。
minをVector3であるthis.transform.positionに代入する際にまた型変換が起こり、z座標が補われた結果キューブの座標は(cx, cy, 0)に移動する...つまりワールドX、ワールドYはカメラの位置と同じで、ワールドZは0となる。

  • nearClipPlaneを使って(0,0)の配置を試みた場合

移動前のキューブのワールド座標を(ox, oy, oz)とする。このうちozを変数に保管しておく。
Camera.main.ViewportToWorldPoint(new Vector3 (0.0f, 0.0f, Camera.main.nearClipPlane))の結果はニアクリップ面矩形の左下隅...つまりシーンビュー上に表示されているカメラ描画範囲の、カメラに近い側の四角形の左下隅のワールド座標となる。この座標を(nx, ny, nz)とする。
得られた座標のX、Yと、保管しておいたozを組み合わせて新たなVector3とし、これをthis.transform.positionに代入する。
結果、キューブの座標は(nx, ny, oz)に移動する...つまりニアクリップ面矩形の左下隅をZ軸方向に動かしていき、ozの位置に合わせたのと同等な位置となる。

こう考えれば、キューブの位置がご提示いただいた図のような位置になりそうです。ですので、先の回答で申し上げたカメラのタグ確認などは不要そうでしたね。お手間を取らせすみませんでした。

投稿2018/06/15 21:47

編集2018/06/15 23:58
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/06/16 10:13

ご回答ありがとうございます。 詳細なご解説ありがとうございます。 ビューポート空間のz位置が、ワールド座標系単位でのカメラからの位置であることを理解していませんでした。(XY平面は0-1の範囲なのに、Z位置だけワールド座標系単位という、不思議な定義の空間なのですね。) また、nearClipPlaneとfarClipPlaneのご解説や、自分の検証コードが間違っている理由、その過程を詳細にご教示いただきありがとうございます。 ViewportToWorldPointの日本語訳もご教示いただき、理解が深まりました。 疑問点や分からなかったことが全て理解できました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問