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

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

ただいまの
回答率

91.05%

  • JavaScript

    13274questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Unity

    2795questions

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

Cubeの頂点の座標を取得したい

解決済

回答 1

投稿

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

qoooooo

score 5

前提・実現したいこと

Cubeの頂点の座標を取得したいです。
meshを利用しましたがどうしてこのように出力されるのかがわかりません。
mesh.vertices.Lengthが24の理由もわかりません。(勉強不足ですみません。)
Cubeでの位置ではなくglobalなPositionを出力させたいです。

エクセルに出力されたもの

0.5    0.5    0.5
-0.5    0.5    0.5
0.5    0.5    0.5
-0.5    0.5    0.5
0.5    -0.5    -0.5
-0.5    -0.5    -0.5
0.5    -0.5    -0.5
-0.5    -0.5    -0.5
0.5    0.5    0.5
-0.5    0.5    0.5
0.5    -0.5    -0.5
-0.5    -0.5    -0.5
0.5    -0.5    -0.5
0.5    0.5    0.5
-0.5    0.5    0.5
-0.5    -0.5    -0.5
-0.5    0.5    0.5
-0.5    0.5    0.5
-0.5    -0.5    -0.5
-0.5    -0.5    -0.5
0.5    -0.5    -0.5
0.5    -0.5    -0.5
0.5    0.5    0.5
0.5    0.5    0.5

該当のソースコード

//コードの一部です

for(var i=0; i<1; i++){
        Unit = Units[i];
        var mesh : Mesh = Unit.GetComponent.<MeshFilter>().mesh;
        for(var j = 0; j < mesh.vertices.Length ; j++) {
            Coordinatex[j] = mesh.vertices[j].x;
            Coordinatey[j] = mesh.vertices[j].y;
            Coordinatez[j] = mesh.vertices[j].z;
            sw.Write(mesh.vertices[j].x+" , "+mesh.vertices[j].z+" , "+mesh.vertices[j].z+" , ");
            sw.WriteLine();
            }
    }

補足情報(言語/FW/ツール等のバージョンなど)

CubeはPosition(0,0,0)、Scale(2,2,2)です。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • Bongo

    2018/01/04 18:47

    mesh.vertices.Lengthが24の件については、Cubeの構造が「一つの面が4頂点を繋いだ2枚の三角形でできていて、それが6面分」ということで4×6=24ということかと思います。これらのグローバル座標が欲しい場合はCubeのtransformのTransformPointを使って座標変換すればいいはずです。欲しい座標についてお伺いしますが、以前のご質問を拝見するとX・Z座標にしか注目されていないようですが、これはたとえば「CubeはY軸周りにだけ回転していて、Cubeの8頂点のうち、真上から見たときの4頂点のX・Z座標だけが分かれば十分」といったことでしょうか?

    キャンセル

  • qoooooo

    2018/01/05 10:22

    ありがとうございます。おっしゃる通りで、CubeはY軸周りにのみ回転し、真上から見たときの4頂点のxz座標が取得したいデータです。

    キャンセル

回答 1

checkベストアンサー

0

追記修正欄に記入しました条件を前提に、目的の4頂点の座標を調べる実験をしてみました。おそらく下記のような感じで頂点のワールド座標を得られるかと思いますが、いかがでしょうか?
Cubeの各頂点は法線の異なる3つの頂点が重複しているので、それを除外し8頂点に減らして、8頂点のうちモデル座標のYが正の4頂点だけを抜き出し(負の4頂点でも構わないと思います)、ワールド座標に変換して、X成分・Z成分だけを取り出すことにしました。
あいにくJavascriptは不慣れでして、変なコードになってしまったかもしれませんがご容赦ください。

#pragma strict

import System.Linq;

class CubeVertices extends MonoBehaviour {

    var cube : GameObject;

    function Start() {
        var mesh : Mesh = cube.GetComponent.<MeshFilter>().mesh;

        var vertices : Vector2[] = mesh.vertices // 全24頂点のうち...
        .Distinct.<Vector3>() // 位置が重複するものを除外(24→8頂点に)
        .Where.<Vector3>(function(p : Vector3) : boolean
        {
            return p.y > 0.0f; // Y座標が+のものだけを抽出(8→4頂点に)
        })
        .Select.<Vector3, Vector2>(function(p : Vector3) : Vector2
        {
            var worldPosition : Vector3 = cube.transform.TransformPoint(p); // モデル座標をワールド座標に変換
            return new Vector2(worldPosition.x, worldPosition.z); // 変換したワールド座標のうちX、ZだけをVector2として返す
        })
        .ToArray.<Vector2>(); // 以上の条件で得られた結果(Vector2型のデータ群)を配列に変換する

        var vertexCount : int = vertices.Length;

        for (var i : int = 0; i < vertexCount; i++)
        {
            Debug.Log(vertices[i]);
        }
    }
}

[追記]

もうすでにご自身で複数キューブの場合に書き換え済みかもしれませんが、ご参考までに例を追記します。
コメントで申し上げた、「最初に1回だけ頂点モデル座標を求めて、以後はワールド座標変換だけ行う」方式にしてみました。

#pragma strict

import System.Linq;

class CubeVertices extends MonoBehaviour {

    var Units : GameObject[];

    private static var CubeTopVertices : Vector3[];
    private static var CubeTopVerticesLength : int;

    private var Coordinatex : float[];
    private var Coordinatez : float[];
    private var UnitsLength : int;

    function Start() {
        UnitsLength = Units.length;

        if (UnitsLength == 0) {
            return;
        }

        InitCubeTopVertices(Units[0]); // オブジェクトを代表して、Units[0]からメッシュを取得しCubeTopVertices・CubeTopVerticesLengthを求める
        Coordinatex = new float[UnitsLength * CubeTopVerticesLength];
        Coordinatez = new float[UnitsLength * CubeTopVerticesLength];

        // 実験のため、各オブジェクトをランダムに移動・回転させる
        for (var i : int = 0; i < UnitsLength; i++) {
            var unitRigidbody = Units[i].GetComponent.<Rigidbody>();

            unitRigidbody.AddForce(Random.value * 2 - 1, 0, Random.value * 2 - 1, ForceMode.VelocityChange);
            unitRigidbody.AddTorque(0, Random.value * 2 - 1, 0, ForceMode.VelocityChange);
        }
    }

    function Update() {
        // スペースキー押下で一時停止、頂点ワールド座標を調べる
        if (Input.GetKeyDown(KeyCode.Space)) {
            if (Time.timeScale > 0) {
                Time.timeScale = 0;
                UpdateCoordinates();
                PrintCoordinates();
            } else {
                Time.timeScale = 1;
            }
        }
    }

    private function UpdateCoordinates() {
        // 各オブジェクトのtransformでキューブの頂点モデル座標をワールド座標に変換し、Coordinatex・Coordinatezを更新する
        for (var i : int = 0; i < UnitsLength; i++) {
            var unitTransform : Transform = Units[i].transform;
            var offset : int = i * CubeTopVerticesLength;

            for (var j : int = 0; j < CubeTopVerticesLength; j++) {
                var worldPosition : Vector3 = unitTransform.TransformPoint(CubeTopVertices[j]);

                Coordinatex[offset + j] = worldPosition.x;
                Coordinatez[offset + j] = worldPosition.z;
            }
        }
    }

    private function PrintCoordinates() {
        // Coordinatex・Coordinatezの内容をコンソールに表示してみる
        Debug.Log("Coordinates:");
        for (var i : int = 0; i < UnitsLength; i++) {
            var offset : int = i * CubeTopVerticesLength;

            Debug.LogFormat(Units[i],
                "Unit {0} ({1}) ... ({2:F4}, {3:F4}), ({4:F4}, {5:F4}), ({6:F4}, {7:F4}), ({8:F4}, {9:F4})",
                i, Units[i].name,
                Coordinatex[offset + 0], Coordinatez[offset + 0],
                Coordinatex[offset + 1], Coordinatez[offset + 1],
                Coordinatex[offset + 2], Coordinatez[offset + 2],
                Coordinatex[offset + 3], Coordinatez[offset + 3]);
        }
    }

    private static function InitCubeTopVertices(meshSource : GameObject) {
        // 上面の頂点抽出までをあらかじめやっておく
        if (CubeTopVertices == null) {
            CubeTopVertices = meshSource.GetComponent.<MeshFilter>().sharedMesh.vertices
            .Distinct.<Vector3>()
            .Where.<Vector3>(function(p : Vector3) : boolean {
                return p.y > 0.0f;
            })
            .ToArray.<Vector3>();
            CubeTopVerticesLength = CubeTopVertices.length;
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/05 11:48

    ありがとうございます!できれば、Cubeが複数になったときのコードも作っていただけたら嬉しいのですが、、可能でしょうか?

    キャンセル

  • 2018/01/05 12:13

    すみません、これから私用で出かけるところでして、しばらくUnityをいじれないのです...

    複数のキューブの場合でも同じことでして、mesh.verticesに入っているのはローカル座標での各頂点の位置ですので、たとえば全キューブについてループさせ、各ループ内で頂点座標をローカルからワールドに変換するときに「Unit.transform.TransformPoint(...」とすれば、その時のUnitに関するワールド座標が得られるかと思います。

    一つ補足しますと、各キューブはメッシュ自体の形状は同一で、ワールド空間内の位置・回転・拡縮が違うだけなのではないかと想像します。ですので「mesh.vertices」で出てくる24頂点の座標はどのキューブについても毎回同じなのではないでしょうか?
    もし余力がありましたら、「キューブメッシュ上面4頂点のローカル座標を取り出す」ところまでをStart内などで1回だけ行うようにして、それ以降頂点のワールド座標が必要になった時は、あらかじめ取り出した4頂点について「各キューブのtransformで4頂点をワールド座標に変換し、そのxとzを調べる」だけにするよう書き換えてみるのもいいと思います。
    この方が計算量が削減されて、動作が少し軽くなるかもしれません。

    キャンセル

  • 2018/01/08 11:26

    追記ありがとうございます!実はもうCubeは動く前提で、10秒後の頂点(Coordinatex[],Coordinatez)を取得したいだけなのです。ファイルに出力するコードも作ってあるので、頂点取得の部分だけ入れ込みたいのですが、その場合、追記のコードで必要なのはStart,Update,UpdateCoordinatesの3つの一部で間違い無いでしょうか?

    キャンセル

  • 2018/01/08 11:34

    はい、PrintCoordinatesやStart内のキューブランダム移動は、動きの確認のために入れてみたものですので不要です。InitCubeTopVerticesとUpdateCoordinatesを適宜組み合わせればいいかと思います。

    キャンセル

  • 2018/01/08 11:41

    ありがとうございます。頑張って組み込んでみます!

    キャンセル

  • 2018/01/09 11:38

    なんども失礼します。function InitCubeTopVertをそのまま使わせていただいたのですが、'Distinct' is not a member of 'UnityEngine.Vector3[]'というエラーが出てしまいました。その他の場所にミスがあるのでしょうか?

    キャンセル

  • 2018/01/09 12:24

    「Distinct」や「Where」を使うには、例示しましたコードの頭の方にある「import System.Linq;」が必要なのですが、記入されていますでしょうか?
    もし書いてあるのにダメだとなると、ちょっとすぐには原因が思いつきません...
    LINQの機能を使ったのは、この方がコードがシンプルになるかと思ってのことでして、LINQに頼らなくとも自前でループを回して頂点を比較抽出することも可能なはずですので、ダメな場合はそのような形に書き換える必要があるかもしれません。

    キャンセル

  • 2018/01/09 14:13

    importし忘れていましたすみません。。うまく組み込んでコードを完成することができました!何度もご親切に回答していただき、本当にありがとうございました!

    キャンセル

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

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

関連した質問

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

  • JavaScript

    13274questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Unity

    2795questions

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