4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Unity]3点から得られる平面にQuad/Planeオブジェクトを移動する

Posted at

小ネタ。

表題の問題を解こうとネットを検索するとたいてい平面の数式に遭遇し、オブジェクトの回転に変換する方法を見つけにくいので書いてみる。大した話ではなく、メモ程度。

要件として

ここでは
「ある物体の角度に応じて、その物体の正面の障害物を壁で覆うようにQuadオブジェクトを配置したい」
とする。
なお Plane を使う場合は面の方向が90度異なるので、以下の説明に補正が必要になる。「正面」でない場合も同様。

作戦は

「物体から正面に3点のレイキャストを発行し、ぶつかった3点に沿うように Quad オブジェクトを移動する」
としよう。このとき、検出された3点に沿うように矩形オブジェクトの姿勢を指定するのが今回のテーマ。

外積から法線を得る

3点あると三角形ができるが、そのうちの二辺のベクトルで外積を作ると、平面に垂直なベクトルを得られる。じっさい平面の式というのは法線ベクトルそのものなので、これを知ってればこの問題は解けたも同然。

LookRotation

Unity にはベクトルに向かうための Quaternion.LookRotation という関数があるので、先程の法線に適用すれば完成。なお安定性のため、第二引数の up ベクトルも指定する。法線ベクトルとワールド空間の右ベクトルの外積で fwd というベクトルを作っておく(状況に応じて対応は分かれる)。

code

以下。Quadのpositionは3点の重心とした。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Wall : MonoBehaviour
{
    public Transform Target;

    void FixedUpdate()
    {
        var orgPoints = new Vector3[] {
            new Vector3( 1f, 1f, 0f),
            new Vector3(-1f, 1f, 0f),
            new Vector3( 0f,-1f, 0f),
        };
        var hitPoints = new Vector3[3];
        bool existsCollider = true;
        for (var i = 0; i < orgPoints.Length; ++i) {
            var org = Target.TransformPoint(orgPoints[i]);
            var dir = Target.TransformDirection(Vector3.forward);
            RaycastHit hit;
            if (Physics.Raycast(org, dir, out hit, Mathf.Infinity, 1 << 3 /* layerMask */)) {
                hitPoints[i] = hit.point;
            } else {
                existsCollider = false;
            }
        }
        if (existsCollider) {
            var norm = Vector3.Cross(hitPoints[1] - hitPoints[0], hitPoints[2] - hitPoints[0]).normalized;
            var up = Vector3.Cross(norm, Vector3.right);
            var center = (hitPoints[0] + hitPoints[1] + hitPoints[2])/3f;
            var rot = Quaternion.LookRotation(norm, up);
            transform.position = center;
            transform.rotation = rot;
        }
    }
}

このスクリプトを Quad オブジェクトに適用し、Target には判定するためのプレイヤーなどの物体を入れておく。レイキャストを投じる対象はレイヤー3を指定。

以上です。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?