夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

UnityでMeshクラスを使用して3Dモデルの原点調整を行う その①

本日はUnity枠です。

 UnityではBlenderやMayaなどのDCCツールと異なり、あくまでゲームエンジンであるため3Dメッシュの編集等のモデリング機能はデフォルトでサポートされていません。

 そのためメッシュ等に不備がある場合はDCCツールに戻り、作業をすることがありますが、特によくあるシチュエーションとして3Dオブジェクトの原点がずれていることでゲームエンジン側で扱いにくいことがあります。

 今回はUnityでMeshクラスを用いて3Dモデルの原点を任意に変更する実装を行います。

〇環境

・Windows11PC

・Unity2022.3.26f1

〇原点調整を行う

今回はつぎのようなシーンを用意しました。

UnityのプリミティブCubeはキューブの中心が原点となっています。

今回は底面が原点となるように処理を行います。

 処理前ではスケールを変更させた場合原点を中心に均一にスケールが変化するようになります。

〇コード

今回は以下のようなコードを書きました。

using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class AdjustPivotPoint : MonoBehaviour
{
    [SerializeField] private Transform pivot; // ピボットを設定するTransform

    private void Start()
    {
        if (pivot == null)
        {
            Debug.LogWarning("Pivot transform is not assigned.");
            return;
        }

        AdjustMeshPivot();
    }

    private void AdjustMeshPivot()
    {
        // 元のメッシュを取得
        MeshFilter meshFilter = GetComponent<MeshFilter>();
        Mesh originalMesh = meshFilter.sharedMesh;

        if (originalMesh == null)
        {
            Debug.LogWarning("No mesh found on this object.");
            return;
        }

        // 新しいメッシュを作成し、元のメッシュの情報をコピー
        Mesh newMesh = Instantiate(originalMesh);

        // ピボットを基準に頂点位置を調整
        Vector3 pivotOffset = transform.InverseTransformPoint(pivot.position);
        Vector3[] vertices = newMesh.vertices;

        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i] -= pivotOffset;
        }
        
        // 調整後の頂点を新しいメッシュに適用
        newMesh.vertices = vertices;
        newMesh.RecalculateBounds(); // 境界ボックスの再計算

        // 新しいメッシュをオブジェクトに適用
        meshFilter.mesh = newMesh;

        // 元のオブジェクトをピボット位置に移動
        transform.position = pivot.position;
    }
}

 行っていることは全頂点をpivotOffset分変更させているという処理になります。

       // ピボットを基準に頂点位置を調整
        Vector3 pivotOffset = transform.InverseTransformPoint(pivot.position);
        Vector3[] vertices = newMesh.vertices;

        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i] -= pivotOffset;
        }
        

以上でPlane上に0.5m上げたところにあったオブジェクトでしたが、原点が調整され、0,0,0となりました。

また、底面が原点となったため、スケールを変更した際にマイナス軸に膨らまないようになりました。

回転を行う際は単純な座標計算ではなく回転行列を用いる必要があります。

こちらはまた次回行っていきます。

本日は以上です。