/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine; using static OVRPlugin; /// /// Represents the Triangle Mesh component of an . /// /// /// This component can be accessed from an that supports it by calling /// from the anchor. /// /// /// /// public readonly partial struct OVRTriangleMesh { /// /// Gets the number of vertices and triangles in the mesh. /// /// /// Use this method to get the required sizes of the vertex and triangle index buffers. The length of the `indices` /// array passed to and should be three times /// . /// /// This method is thread-safe. /// /// The number of vertices in the mesh. /// The number of triangles in the mesh. There are three times as many indices. /// True if the counts were retrieved; otherwise, false. public bool TryGetCounts(out int vertexCount, out int triangleCount) => GetSpaceTriangleMeshCounts(Handle, out vertexCount, out triangleCount); /// /// Gets the raw, untransformed triangle mesh. /// /// /// ## Thread safety /// This method is thread-safe. /// /// ## Memory ownership /// The caller owns the memory of the input arrays and is responsible for allocating them to the appropriate size /// before passing them to this method. Use to determine the required size of each array. /// Note that should be three times the number of triangles (`triangleCount`) indicated /// by . /// /// ## Coordinate space /// The mesh data provided by this method must be transformed into the appropriate coordinate space before being /// used with a `UnityEngine.Mesh`. Use or to get mesh /// data in the correct coordinate space. This method is typically for advanced use cases where you want to perform /// the conversion at a later time, or combine it with your own jobs. /// /// The are provided in the right-handed coordinate /// space defined by OpenXR, with X to the right, Y up, and Z backward. is an array of /// index triplets which define the triangles in counter-clockwise order. /// /// To convert to the coordinate space used by a Scene anchor in Unity's coordinate system, you must /// - Negate each vertex's X coordinate /// - Reverse the triangle winding by swapping each index triplet (a, b, c) => (a, c, b) /// /// The vertex positions of the mesh. /// The triangle indices of the mesh. /// True if the mesh data was retrieved; otherwise, false. public bool TryGetMeshRawUntransformed(NativeArray positions, NativeArray indices) => GetSpaceTriangleMesh(Handle, positions, indices); /// /// Gets the triangle mesh. /// /// /// The caller owns the memory of the input arrays and is responsible for allocating them to the appropriate size /// before passing them to this method. Use to determine the required size of each array. /// Note that should be three times the number of triangles (`triangleCount`) indicated /// by . /// /// This method is thread-safe. /// /// The vertex positions of the mesh. /// The triangle indices of the mesh. /// True if the mesh data was retrieved; otherwise, false. public bool TryGetMesh(NativeArray positions, NativeArray indices) { if (!TryGetMeshRawUntransformed(positions, indices)) return false; for (var i = 0; i < positions.Length; i++) { var p = positions[i]; // Necessary due to the coordinate space difference between OpenXR (right-handed) and Unity (left-handed) positions[i] = new Vector3(-p.x, p.y, p.z); } var triangles = indices.Reinterpret( expectedTypeSize: sizeof(int)); for (var i = 0; i < triangles.Length; i++) { var triangle = triangles[i]; triangles[i] = new Triangle { A = triangle.A, B = triangle.C, C = triangle.B }; } return true; } /// /// Schedules a job to get an anchor's triangle mesh. /// /// /// This schedules jobs with the Unity Job system to retrieve the mesh data and then perform the necessary /// conversion to Unity's coordinate space (see ). /// /// The caller owns the memory of the input arrays and is responsible for allocating them to the appropriate size /// before passing them to this method. Use to determine the required size of each array. /// Note that should be three times the number of triangles (`triangleCount`) indicated /// by . /// /// If the triangle mesh cannot be retrieved, all will be set to zero. Use this to check /// for success after the job completes. For example, if the first three indices are zero, then the mesh is not /// valid. /// /// The vertex positions of the triangle mesh. /// The triangle indices of the triangle mesh. /// (Optional) A job on which the new jobs will depend. /// Returns the handle associated with the new job. public JobHandle ScheduleGetMeshJob(NativeArray positions, NativeArray indices, JobHandle dependencies = default) { var getMeshJob = new GetMeshJob { Positions = positions, Indices = indices, Space = Handle }.Schedule(dependencies); var triangles = indices.Reinterpret(expectedTypeSize: sizeof(int)); return JobHandle.CombineDependencies( new NegateXJob { Positions = positions }.Schedule(positions.Length, 32, getMeshJob), new FlipTriangleWindingJob { Triangles = triangles }.Schedule(triangles.Length, 32, getMeshJob)); } private struct GetMeshJob : IJob { public ulong Space; public NativeArray Positions; public NativeArray Indices; public unsafe void Execute() { if (!GetSpaceTriangleMesh(Space, Positions, Indices)) { UnsafeUtility.MemSet(Indices.GetUnsafePtr(), 0, Indices.Length * sizeof(int)); } } } private struct Triangle { public int A, B, C; } private struct FlipTriangleWindingJob : IJobParallelFor { public NativeArray Triangles; public void Execute(int index) { var triangle = Triangles[index]; Triangles[index] = new Triangle { A = triangle.A, B = triangle.C, C = triangle.B }; } } // Necessary due to the coordinate space difference between OpenXR (right-handed) and Unity (left-handed) private struct NegateXJob : IJobParallelFor { public NativeArray Positions; public void Execute(int index) { var p = Positions[index]; Positions[index] = new Vector3(-p.x, p.y, p.z); } } }