5
2

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 1 year has passed since last update.

STYLYAdvent Calendar 2023

Day 19

【Unity】GPU Instancingで大量に描画したMeshをImmersalの位置合わせ処理に適用する

Last updated at Posted at 2023-12-18

サンプル

まずはサンプルです。円形の机にピッタリ芝生が生えるように配置しました。
芝生はGPU Instancingで大量に描画したMeshです。

前提

Immersalの位置合わせはARSpace.csをアタッチしたオブジェクト配下にAR用オブジェクトを配置することで実現できます。

内部では事前に作成したマップデータの特徴点を元に、ARSpaceが移動/回転することで位置合わせが行われています。

では、GPU Instancingで大量に描画したMeshについても、"ARSpace.csをアタッチしたオブジェクト配下"に並べておけば可能なのか、というとそうではありません。

GPU Instancingで大量にMeshを描画するにはGraphicsのAPIを利用します。
その際、MeshにはMatrix4x4で座標/回転/スケールの情報を与えることになります。

詳細は以下記事に実例とともにまとめています。

【参考リンク】:そろそろShaderをやるパート91 -URP編- GPU Instancingで大量に草を生やす

まとめると、単純に"ARSpace.csをアタッチしたオブジェクト配下"に並べた場合、以下GIFのように移動/回転させることができません。

GPUInstancingWithImmersal.gif

実装方法

実装方法としてはMeshのMatrix4x4にARScaceのTransformが反映されるようにしてあげればOKです。

以下コードです。

using System.Collections.Generic;
using Immersal.AR;
using UnityEngine;
using Random = UnityEngine.Random;

namespace TestGPUInstancing
{
    public class DrawMeshInstancing : MonoBehaviour
    {
        [SerializeField] private ARLocalizer _arLocalizer;
        [SerializeField] private Mesh _mesh;
        [SerializeField] private Material _material;
        [SerializeField] private float _radius = 5.0f;
        [SerializeField] private int _meshCount = 512;

        private Matrix4x4[] _matrices;
        private List<Vector3> _positions;

        private void Start()
        {
            _matrices = new Matrix4x4[_meshCount];
            _positions = GeneratePointsInCircle(_meshCount, _radius);
            _arLocalizer.OnPoseFound += OnPoseFound;
            UpdatePositions();
        }

        private void Update()
        {
            //デバッグ用。
            if (Application.isEditor && transform.hasChanged)
            {
                UpdatePositions();
                transform.hasChanged = false;
            }

            Graphics.DrawMeshInstanced(_mesh, 0, _material, _matrices, _meshCount);
        }

        private void OnDestroy()
        {
            _arLocalizer.OnPoseFound -= OnPoseFound;
        }

        private void OnPoseFound(LocalizerPose pose)
        {
            UpdatePositions();
        }

        private void UpdatePositions()
        {
            for (var i = 0; i < _meshCount; i++)
            {
                var meshPosition = transform.rotation * _positions[i] + transform.position;
                _matrices[i] = Matrix4x4.TRS(meshPosition, transform.rotation, transform.localScale);
            }
        }

        private List<Vector3> GeneratePointsInCircle(int numberOfPoints, float radius)
        {
            var points = new List<Vector3>();

            for (var i = 0; i < numberOfPoints; i++)
            {
                var randomPointOnCircle = Random.insideUnitCircle * radius;
                points.Add(new Vector3(randomPointOnCircle.x, 0f, randomPointOnCircle.y));
            }

            return points;
        }
    }
}

以下画像のような階層構造にしておけば、ARSpaceが移動すれば子のARObject
も移動するので、DrawMeshInstancing.csをアタッチしたオブジェクト自身のTransformを利用できます。
image.png

以下GIFのようにARSpaceの移動はもちろん、Unity Editor上での細かい位置合わせも可能となります。
ImmersalWithGPUInstancing.gif

宣伝

以下イベントで同様の手法を用いてMRグラス上で大量のオブジェクトを出現させるという試みにチャレンジさせていただきました。テレビでも取り上げられ、大盛況だったとのことです。

AR/VR関連でお困りごとあればご相談ください。

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?