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

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

ただいまの
回答率

90.52%

  • Unity

    3989questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

nearClipPlaneと境界

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 147

tkmnusr

score 162

 前提・実現したいこと

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

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

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

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

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

 試したこと

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

イメージ説明

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

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


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

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

    void Start () {
        float myZ = this.transform.position.z;
        Vector3 min = Camera.main.ViewportToWorldPoint(new Vector3 (0.0f, 0.0f, Camera.main.nearClipPlane));
        this.transform.position = new Vector3(min.x, min.y, myZ);

    }


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

    void Start()
    {
        // キューブのワールド座標をメインカメラから見たビューポート座標に直す
        Vector3 viewportPosition = Camera.main.WorldToViewportPoint(this.transform.position);

        // xとyを0に書き換える
        // zにはメインカメラから見たキューブのカメラZ方向の位置...つまり奥行きの距離が入っているはずなので、書き換える必要はない
        viewportPosition.x = 0.0f;
        viewportPosition.y = 0.0f;

        // ビューポート座標をワールド座標に直し、キューブの位置をそこに設定する
        this.transform.position = Camera.main.ViewportToWorldPoint(viewportPosition);
    }

プレビュー

でいけるかと思うのですが、ご質問者さんの実験結果がちょっと妙ですので、なにか他の問題があるかもしれません。
スクリプトがちゃんと目的のキューブにアタッチされているか(こちらは気づきやすいので間違ってはいないかと思いますが...)、カメラのタグが「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/16 19:13

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

    キャンセル

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

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Unity

    3989questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。