VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction/Runtime/Scripts/Unity/UnityCanvas/CanvasCylinder.cs
IonutMocanu 48cccc22ad Main2
2025-09-08 11:13:29 +03:00

318 lines
12 KiB
C#

/*
* 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 System;
using Oculus.Interaction.Surfaces;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Oculus.Interaction.UnityCanvas
{
public class CanvasCylinder : CanvasMesh, ICurvedPlane, ICylinderClipper
{
[Serializable]
public struct MeshGenerationSettings
{
[Delayed]
public float VerticesPerDegree;
[Delayed]
public int MaxHorizontalResolution;
[Delayed]
public int MaxVerticalResolution;
}
public const int MIN_RESOLUTION = 2;
[SerializeField]
[Tooltip("The cylinder used to dictate the position and radius of the mesh.")]
private Cylinder _cylinder;
[SerializeField]
[Tooltip("Determines how the mesh is projected on the cylinder wall. " +
"Vertical results in a left-to-right curvature, Horizontal results in a top-to-bottom curvature.")]
private CylinderOrientation _orientation = CylinderOrientation.Vertical;
[SerializeField]
private MeshGenerationSettings _meshGeneration = new MeshGenerationSettings()
{
VerticesPerDegree = 1.4f,
MaxHorizontalResolution = 128,
MaxVerticalResolution = 32
};
public float Radius => _cylinder.Radius;
public Cylinder Cylinder => _cylinder;
public float ArcDegrees { get; private set; }
public float Rotation { get; private set; }
public float Bottom { get; private set; }
public float Top { get; private set; }
private float CylinderRelativeScale => _cylinder.transform.lossyScale.x / transform.lossyScale.x;
public bool GetCylinderSegment(out CylinderSegment segment)
{
segment = new CylinderSegment(Rotation, ArcDegrees, Bottom, Top);
return _started && isActiveAndEnabled;
}
protected override void Start()
{
this.BeginStart(ref _started, () => base.Start());
this.AssertField(_cylinder, nameof(_cylinder));
this.EndStart(ref _started);
}
#if UNITY_EDITOR
protected virtual void OnValidate()
{
_meshGeneration.MaxHorizontalResolution = Mathf.Max(MIN_RESOLUTION,
_meshGeneration.MaxHorizontalResolution);
_meshGeneration.MaxVerticalResolution = Mathf.Max(MIN_RESOLUTION,
_meshGeneration.MaxVerticalResolution);
_meshGeneration.VerticesPerDegree = Mathf.Max(0, _meshGeneration.VerticesPerDegree);
if (Application.isPlaying && _started)
{
EditorApplication.delayCall += () =>
{
UpdateImposter();
};
}
}
#endif
protected override void UpdateImposter()
{
base.UpdateImposter();
UpdateMeshPosition();
UpdateCurvedPlane();
}
protected override Vector3 MeshInverseTransform(Vector3 localPosition)
{
float angle = Mathf.Atan2(localPosition.x, localPosition.z + Radius);
float x = angle * Radius;
float y = localPosition.y;
return new Vector3(x, y);
}
protected override void GenerateMesh(out List<Vector3> verts,
out List<int> tris,
out List<Vector2> uvs)
{
verts = new List<Vector3>();
tris = new List<int>();
uvs = new List<Vector2>();
Vector2 worldSize = GetWorldSize();
float scaledRadius = Radius * CylinderRelativeScale;
float xPos = worldSize.x * 0.5f;
float xNeg = -xPos;
float yPos = worldSize.y * 0.5f;
float yNeg = -yPos;
Vector2Int GetClampedResolution(float arcMax, float axisMax)
{
int horizontalResolution = Mathf.Max(2,
Mathf.RoundToInt(_meshGeneration.VerticesPerDegree *
Mathf.Rad2Deg * arcMax / scaledRadius));
int verticalResolution =
Mathf.Max(2, Mathf.RoundToInt(horizontalResolution * axisMax / arcMax));
horizontalResolution = Mathf.Clamp(horizontalResolution, 2,
_meshGeneration.MaxHorizontalResolution);
verticalResolution = Mathf.Clamp(verticalResolution, 2,
_meshGeneration.MaxVerticalResolution);
return new Vector2Int(horizontalResolution, verticalResolution);
}
Vector3 GetCurvedPoint(float u, float v)
{
float x = Mathf.Lerp(xNeg, xPos, u);
float y = Mathf.Lerp(yNeg, yPos, v);
float angle;
Vector3 point;
switch (_orientation)
{
default:
case CylinderOrientation.Vertical:
angle = x / scaledRadius;
point.x = Mathf.Sin(angle) * scaledRadius;
point.y = y;
point.z = Mathf.Cos(angle) * scaledRadius - scaledRadius;
break;
case CylinderOrientation.Horizontal:
angle = y / scaledRadius;
point.x = x;
point.y = Mathf.Sin(angle) * scaledRadius;
point.z = Mathf.Cos(angle) * scaledRadius - scaledRadius;
break;
}
return point;
}
Vector2Int resolution;
switch (_orientation)
{
default:
case CylinderOrientation.Vertical:
resolution = GetClampedResolution(xPos, yPos);
break;
case CylinderOrientation.Horizontal:
resolution = GetClampedResolution(yPos, xPos);
break;
}
for (int y = 0; y < resolution.y; y++)
{
for (int x = 0; x < resolution.x; x++)
{
float u = x / (resolution.x - 1.0f);
float v = y / (resolution.y - 1.0f);
verts.Add(GetCurvedPoint(u, v));
uvs.Add(new Vector2(u, v));
}
}
for (int y = 0; y < resolution.y - 1; y++)
{
for (int x = 0; x < resolution.x - 1; x++)
{
int v00 = x + y * resolution.x;
int v10 = v00 + 1;
int v01 = v00 + resolution.x;
int v11 = v00 + 1 + resolution.x;
tris.Add(v00);
tris.Add(v11);
tris.Add(v10);
tris.Add(v00);
tris.Add(v01);
tris.Add(v11);
}
}
}
private void UpdateMeshPosition()
{
Vector3 posInCylinder = _cylinder.transform.InverseTransformPoint(transform.position);
Vector3 localYOffset = new Vector3(0, posInCylinder.y, 0);
Vector3 localCancelY = posInCylinder - localYOffset;
// If canvas position is on cylinder center axis, project forward.
// Otherwise, project canvas onto cylinder wall from center axis.
Vector3 projection = Mathf.Approximately(localCancelY.sqrMagnitude, 0f) ?
Vector3.forward : localCancelY.normalized;
Vector3 localUp;
switch (_orientation)
{
default:
case CylinderOrientation.Vertical:
localUp = Vector3.up;
break;
case CylinderOrientation.Horizontal:
localUp = Vector3.right;
break;
}
transform.position = _cylinder.transform.TransformPoint((projection * _cylinder.Radius) + localYOffset);
transform.rotation = _cylinder.transform.rotation * Quaternion.LookRotation(projection, localUp);
if (_meshCollider != null &&
_meshCollider.transform != transform &&
!transform.IsChildOf(_meshCollider.transform))
{
_meshCollider.transform.position = transform.position;
_meshCollider.transform.rotation = transform.rotation;
_meshCollider.transform.localScale *= transform.lossyScale.x / _meshCollider.transform.lossyScale.x;
}
}
private Vector2 GetWorldSize()
{
Vector2Int resolution = _canvasRenderTexture.GetBaseResolutionToUse();
float width = _canvasRenderTexture.PixelsToUnits(Mathf.RoundToInt(resolution.x));
float height = _canvasRenderTexture.PixelsToUnits(Mathf.RoundToInt(resolution.y));
return new Vector2(width, height) / transform.lossyScale;
}
private void UpdateCurvedPlane()
{
// Get world size in cylinder space
Vector2 cylinderSize = GetWorldSize() / CylinderRelativeScale;
float arcSize, axisSize;
switch (_orientation)
{
default:
case CylinderOrientation.Vertical:
arcSize = cylinderSize.x;
axisSize = cylinderSize.y;
break;
case CylinderOrientation.Horizontal:
arcSize = cylinderSize.y;
axisSize = cylinderSize.x;
break;
}
Vector3 posInCylinder = Cylinder.transform.InverseTransformPoint(transform.position);
Rotation = Mathf.Atan2(posInCylinder.x, posInCylinder.z) * Mathf.Rad2Deg;
ArcDegrees = (arcSize * 0.5f / Radius) * 2f * Mathf.Rad2Deg;
Top = posInCylinder.y + (axisSize * 0.5f);
Bottom = posInCylinder.y - (axisSize * 0.5f);
}
#region Inject
public void InjectAllCanvasCylinder(CanvasRenderTexture canvasRenderTexture,
MeshFilter meshFilter,
Cylinder cylinder,
CylinderOrientation orientation)
{
InjectAllCanvasMesh(canvasRenderTexture, meshFilter);
InjectCylinder(cylinder);
InjectOrientation(orientation);
}
public void InjectCylinder(Cylinder cylinder)
{
_cylinder = cylinder;
}
public void InjectOrientation(CylinderOrientation orientation)
{
_orientation = orientation;
}
#endregion
}
}