UnityのWebGLで点群を表示してみる

Unity 2018.3.2f1のWebGL出力で点群を表示できたのでやったことをメモしておく。
(はやくAmazon Sumerianで点群表示をサポートしてほしい)

# Unity Editorで点群を表示してみる

## 表示手順

[UnityでPoint Cloudを表示する方法 – NegativeMind – Medium](https://medium.com/@NegativeMind/unity%E3%81%A7point-cloud%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95-12a4e24e0718)
を参考にして以下のような手順を実施した。

* 以下のスクリプトを作成する。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class PointCloud : MonoBehaviour
{

    private Mesh mesh;
    int numPoints = 600000;

    // Use this for initialization
    void Start()
    {
        mesh = new Mesh();

        GetComponent<MeshFilter>().mesh = mesh;
        CreateMesh();
    }

    void CreateMesh()
    {
        Vector3[] points = new Vector3[numPoints];
        int[] indecies = new int[numPoints];
        Color[] colors = new Color[numPoints];
        for (int i = 0; i < points.Length; ++i)
        {
            points[i] = new Vector3(Random.Range(-10, 10), Random.Range(-10, 10), Random.Range(-10, 10));
            indecies[i] = i;
            colors[i] = new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), 1.0f);
        }

        mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
        mesh.vertices = points;
        mesh.colors = colors;
        mesh.SetIndices(indecies, MeshTopology.Points, 0);

    }
}
```

* 以下のシェーダーを作成する

```glsl
Shader "Custom/VertexColor"
{
    SubShader {
    Pass {
        LOD 200
         
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
 
        struct VertexInput {
            float4 v : POSITION;
            float4 color: COLOR;
        };
         
        struct VertexOutput {
            float4 pos : SV_POSITION;
            float4 col : COLOR;
        };
         
        VertexOutput vert(VertexInput v) {
         
            VertexOutput o;
            o.pos = UnityObjectToClipPos(v.v);
            o.col = v.color;
             
            return o;
        }
         
        float4 frag(VertexOutput o) : COLOR {
            return o.col;
        }
 
        ENDCG
        } 
    }
}
```

* マテリアルを作成して作成したシェーダーを指定する。
* [CreateEmpty]でGameObjectを作成する。
* 作成したGameObjectにMesh Rendererコンポーネント、Mesh Filterコンポーネント、作成したスクリプト、作成したマテリアルを割り当てる。
* 実行する。
![pointclouddisplaycapture.PNG](https://qiita-image-store.s3.amazonaws.com/0/16768/fc444217-dafc-5b57-109a-65d010275085.png)


## スクリプトについて

以下のように指定しているのでUInt32のMAXまで点群が設定可能。それを超える場合はゲームオブジェクト(メッシュ)の分割が必要。

```
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
```

# WebGLで点群を表示してみる

上記のままでWebGLビルドしても点群が表示されない。

多分以下の問題。
[MeshTopology.Point Geometry not displaying in WebGL Builds - Unity Forum](https://forum.unity.com/threads/meshtopology-point-geometry-not-displaying-in-webgl-builds.481640/)
以下のようにすることでWebGLで表示できた。

* リンク先にあった以下のシェーダーを作成する。

```GLSL
Shader "Custom/PointCloud_GL"
{
	Properties
	{
		_PointSize("PointSize", Float) = 5
		_HeightTex("Height Texture", 2D) = "white" {}
	}

	SubShader
	{
		Pass
		{
			LOD 200

			GLSLPROGRAM
			#pragma multi_compile __ HEIGHTMAP_ON

			#ifdef VERTEX

			out vec4 Color;
			uniform sampler2D _HeightTex;
			uniform float _PointSize;

			float ToneMap(float rawValue)
			{
				float contrast = 3.8;
				float exposure = 0.001;
				float a = exposure * pow(rawValue, contrast);
				return a / (1.0f + a);
			}

            void main()
            {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
				gl_PointSize = _PointSize * (1.0 / gl_Position.w);

				#ifdef HEIGHTMAP_ON
				float index = ToneMap(gl_MultiTexCoord0.x);
				Color = texture2D(_HeightTex, vec2(index, 0));
				#else
				Color = gl_Color;
				#endif
            }
           
            #endif
           
            #ifdef FRAGMENT
                       
            in vec4 Color;
           
            void main()
            {
				vec2 coord = gl_PointCoord - vec2(0.5);
				if (length(coord) > 0.5)
				{
					discard;
				}

				gl_FragColor = Color;
            }
           
            #endif

			ENDGLSL
		}
	}
}
```

* 上記シェーダーを[Editor] => [Project Settings]の[Always Included Shaders]に登録する。
* スクリプトのStart()に以下を追加する。

```c#
#if !UNITY_EDITOR && UNITY_WEBGL
        gameObject.GetComponent<MeshRenderer>().material.shader = Shader.Find("Custom/PointCloud_GL");
#endif
```

* ビルドする。

![pointcloudwebgldisplaycapture.PNG](https://qiita-image-store.s3.amazonaws.com/0/16768/0bcfbbfd-f6ce-5f78-15c1-14c9dfa4ad5d.png)