using System; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(OVROverlay))] [ExecuteInEditMode] public class OVROverlayMeshGenerator : MonoBehaviour { private enum CubeFace { Right = 0, Left = 1, Top = 2, Bottom = 3, Front = 4, Back = 5, COUNT = 6 } private Mesh _Mesh; private List _Verts = new List(); private List _UV = new List(); private List _Tris = new List(); private OVROverlay _Overlay; private MeshFilter _MeshFilter; private MeshCollider _MeshCollider; private Transform _CameraRoot; private Transform _Transform; private OVROverlay.OverlayShape _LastShape; private Vector3 _LastPosition; private Quaternion _LastRotation; private Vector3 _LastScale; private Rect _LastRectLeft; private Rect _LastRectRight; private bool _Awake; private static readonly Vector3[] BottomLeft = new Vector3[6] { new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, 0.5f, -0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) }; private static readonly Vector3[] RightVector = new Vector3[6] { Vector3.forward, Vector3.back, Vector3.left, Vector3.left, Vector3.left, Vector3.right }; private static readonly Vector3[] UpVector = new Vector3[6] { Vector3.up, Vector3.up, Vector3.forward, Vector3.back, Vector3.up, Vector3.up }; protected void Awake() { _Overlay = GetComponent(); _MeshFilter = GetComponent(); _MeshCollider = GetComponent(); _Transform = base.transform; if ((bool)Camera.main && (bool)Camera.main.transform.parent) { _CameraRoot = Camera.main.transform.parent; } _Awake = true; } private Rect GetBoundingRect(Rect a, Rect b) { float num = Mathf.Min(a.x, b.x); float num2 = Mathf.Max(a.x + a.width, b.x + b.width); float num3 = Mathf.Min(a.y, b.y); float num4 = Mathf.Max(a.y + a.height, b.y + b.height); return new Rect(num, num3, num2 - num, num4 - num3); } private void Update() { if (!_Awake) { Awake(); } if ((bool)_Overlay) { OVROverlay.OverlayShape currentOverlayShape = _Overlay.currentOverlayShape; Vector3 vector = ((!_CameraRoot) ? _Transform.position : (_Transform.position - _CameraRoot.position)); Quaternion rotation = _Transform.rotation; Vector3 lossyScale = _Transform.lossyScale; Rect rect = ((!_Overlay.overrideTextureRectMatrix) ? new Rect(0f, 0f, 1f, 1f) : _Overlay.destRectLeft); Rect rect2 = ((!_Overlay.overrideTextureRectMatrix) ? new Rect(0f, 0f, 1f, 1f) : _Overlay.destRectRight); if (_Mesh == null || _LastShape != currentOverlayShape || _LastPosition != vector || _LastRotation != rotation || _LastScale != lossyScale || _LastRectLeft != rect || _LastRectRight != rect2) { UpdateMesh(currentOverlayShape, vector, rotation, lossyScale, GetBoundingRect(rect, rect2)); _LastShape = currentOverlayShape; _LastPosition = vector; _LastRotation = rotation; _LastScale = lossyScale; _LastRectLeft = rect; _LastRectRight = rect2; } } } private void UpdateMesh(OVROverlay.OverlayShape shape, Vector3 position, Quaternion rotation, Vector3 scale, Rect rect) { if ((bool)_MeshFilter) { if (_Mesh == null) { _Mesh = new Mesh { name = "Overlay" }; _Mesh.hideFlags = HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild; } _Mesh.Clear(); _Verts.Clear(); _UV.Clear(); _Tris.Clear(); GenerateMesh(_Verts, _UV, _Tris, shape, position, rotation, scale, rect); _Mesh.SetVertices(_Verts); _Mesh.SetUVs(0, _UV); _Mesh.SetTriangles(_Tris, 0); _Mesh.UploadMeshData(false); _MeshFilter.sharedMesh = _Mesh; if ((bool)_MeshCollider) { _MeshCollider.sharedMesh = _Mesh; } } } public static void GenerateMesh(List verts, List uvs, List tris, OVROverlay.OverlayShape shape, Vector3 position, Quaternion rotation, Vector3 scale, Rect rect) { switch (shape) { case OVROverlay.OverlayShape.Equirect: BuildSphere(verts, uvs, tris, position, rotation, scale, rect); break; case OVROverlay.OverlayShape.Cubemap: case OVROverlay.OverlayShape.OffcenterCubemap: BuildCube(verts, uvs, tris, position, rotation, scale); break; case OVROverlay.OverlayShape.Quad: BuildQuad(verts, uvs, tris, rect); break; case OVROverlay.OverlayShape.Cylinder: BuildHemicylinder(verts, uvs, tris, scale, rect); break; case (OVROverlay.OverlayShape)3: break; } } private static Vector2 GetSphereUV(float theta, float phi, float expand_coef) { float x = (theta / ((float)Math.PI * 2f) - 0.5f) / expand_coef + 0.5f; float y = phi / (float)Math.PI / expand_coef + 0.5f; return new Vector2(x, y); } private static Vector3 GetSphereVert(float theta, float phi) { return new Vector3((0f - Mathf.Sin(theta)) * Mathf.Cos(phi), Mathf.Sin(phi), (0f - Mathf.Cos(theta)) * Mathf.Cos(phi)); } public static void BuildSphere(List verts, List uv, List triangles, Vector3 position, Quaternion rotation, Vector3 scale, Rect rect, float worldScale = 800f, int latitudes = 128, int longitudes = 128, float expand_coef = 1f) { position = Quaternion.Inverse(rotation) * position; latitudes = Mathf.CeilToInt((float)latitudes * rect.height); longitudes = Mathf.CeilToInt((float)longitudes * rect.width); float num = (float)Math.PI * 2f * rect.x; float num2 = (float)Math.PI * (0.5f - rect.y - rect.height); float num3 = (float)Math.PI * 2f * rect.width / (float)longitudes; float num4 = (float)Math.PI * rect.height / (float)latitudes; for (int i = 0; i < latitudes + 1; i++) { for (int j = 0; j < longitudes + 1; j++) { float theta = num + (float)j * num3; float phi = num2 + (float)i * num4; Vector2 sphereUV = GetSphereUV(theta, phi, expand_coef); uv.Add(new Vector2((sphereUV.x - rect.x) / rect.width, (sphereUV.y - rect.y) / rect.height)); Vector3 sphereVert = GetSphereVert(theta, phi); sphereVert.x = (worldScale * sphereVert.x - position.x) / scale.x; sphereVert.y = (worldScale * sphereVert.y - position.y) / scale.y; sphereVert.z = (worldScale * sphereVert.z - position.z) / scale.z; verts.Add(sphereVert); } } for (int k = 0; k < latitudes; k++) { for (int l = 0; l < longitudes; l++) { triangles.Add(k * (longitudes + 1) + l); triangles.Add((k + 1) * (longitudes + 1) + l); triangles.Add((k + 1) * (longitudes + 1) + l + 1); triangles.Add((k + 1) * (longitudes + 1) + l + 1); triangles.Add(k * (longitudes + 1) + l + 1); triangles.Add(k * (longitudes + 1) + l); } } } private static Vector2 GetCubeUV(CubeFace face, Vector2 sideUV, float expand_coef) { sideUV = (sideUV - 0.5f * Vector2.one) / expand_coef + 0.5f * Vector2.one; switch (face) { case CubeFace.Bottom: return new Vector2(sideUV.x / 3f, sideUV.y / 2f); case CubeFace.Front: return new Vector2((1f + sideUV.x) / 3f, sideUV.y / 2f); case CubeFace.Back: return new Vector2((2f + sideUV.x) / 3f, sideUV.y / 2f); case CubeFace.Right: return new Vector2(sideUV.x / 3f, (1f + sideUV.y) / 2f); case CubeFace.Left: return new Vector2((1f + sideUV.x) / 3f, (1f + sideUV.y) / 2f); case CubeFace.Top: return new Vector2((2f + sideUV.x) / 3f, (1f + sideUV.y) / 2f); default: return Vector2.zero; } } private static Vector3 GetCubeVert(CubeFace face, Vector2 sideUV, float expand_coef) { return BottomLeft[(int)face] + sideUV.x * RightVector[(int)face] + sideUV.y * UpVector[(int)face]; } public static void BuildCube(List verts, List uv, List triangles, Vector3 position, Quaternion rotation, Vector3 scale, float worldScale = 800f, int subQuads = 1, float expand_coef = 1.01f) { position = Quaternion.Inverse(rotation) * position; int num = (subQuads + 1) * (subQuads + 1); for (int i = 0; i < 6; i++) { for (int j = 0; j < subQuads + 1; j++) { for (int k = 0; k < subQuads + 1; k++) { float x = (float)j / (float)subQuads; float y = (float)k / (float)subQuads; uv.Add(GetCubeUV((CubeFace)i, new Vector2(x, y), expand_coef)); Vector3 cubeVert = GetCubeVert((CubeFace)i, new Vector2(x, y), expand_coef); cubeVert.x = (worldScale * cubeVert.x - position.x) / scale.x; cubeVert.y = (worldScale * cubeVert.y - position.y) / scale.y; cubeVert.z = (worldScale * cubeVert.z - position.z) / scale.z; verts.Add(cubeVert); } } for (int l = 0; l < subQuads; l++) { for (int m = 0; m < subQuads; m++) { triangles.Add(num * i + (l + 1) * (subQuads + 1) + m); triangles.Add(num * i + l * (subQuads + 1) + m); triangles.Add(num * i + (l + 1) * (subQuads + 1) + m + 1); triangles.Add(num * i + (l + 1) * (subQuads + 1) + m + 1); triangles.Add(num * i + l * (subQuads + 1) + m); triangles.Add(num * i + l * (subQuads + 1) + m + 1); } } } } public static void BuildQuad(List verts, List uv, List triangles, Rect rect) { verts.Add(new Vector3(rect.x - 0.5f, 1f - rect.y - rect.height - 0.5f, 0f)); verts.Add(new Vector3(rect.x - 0.5f, 1f - rect.y - 0.5f, 0f)); verts.Add(new Vector3(rect.x + rect.width - 0.5f, 1f - rect.y - 0.5f, 0f)); verts.Add(new Vector3(rect.x + rect.width - 0.5f, 1f - rect.y - rect.height - 0.5f, 0f)); uv.Add(new Vector2(0f, 0f)); uv.Add(new Vector2(0f, 1f)); uv.Add(new Vector2(1f, 1f)); uv.Add(new Vector2(1f, 0f)); triangles.Add(0); triangles.Add(1); triangles.Add(2); triangles.Add(2); triangles.Add(3); triangles.Add(0); } public static void BuildHemicylinder(List verts, List uv, List triangles, Vector3 scale, Rect rect, int longitudes = 128) { float num = Mathf.Abs(scale.y) * rect.height; float z = scale.z; float num2 = scale.x * rect.width; float num3 = num2 / z; float num4 = scale.x * (-0.5f + rect.x) / z; int num5 = Mathf.CeilToInt((float)longitudes * num3 / ((float)Math.PI * 2f)); float num6 = num2 / (float)num5; float num7 = num / num6; int num8 = Mathf.CeilToInt(num7 / 2f); for (int i = 0; i < num8 + 1; i++) { for (int j = 0; j < num5 + 1; j++) { uv.Add(new Vector2((float)j / (float)num5, 1f - (float)i / (float)num8)); Vector3 zero = Vector3.zero; zero.x = Mathf.Sin(num4 + (float)j * num3 / (float)num5) * z / scale.x; zero.y = 0.5f - rect.y - rect.height + rect.height * (1f - (float)i / (float)num8); zero.z = Mathf.Cos(num4 + (float)j * num3 / (float)num5) * z / scale.z; verts.Add(zero); } } for (int k = 0; k < num8; k++) { for (int l = 0; l < num5; l++) { triangles.Add(k * (num5 + 1) + l); triangles.Add((k + 1) * (num5 + 1) + l + 1); triangles.Add((k + 1) * (num5 + 1) + l); triangles.Add((k + 1) * (num5 + 1) + l + 1); triangles.Add(k * (num5 + 1) + l); triangles.Add(k * (num5 + 1) + l + 1); } } } }