using UnityEngine;
using UnityEngine.UI;
using System;
using Rokid.UXR.Native;
namespace Rokid.UXR.Utility
{
public static partial class Utils
{
///
/// ClearChild
///
///
public static void ClearTransformChild(Transform transform)
{
for (int i = transform.childCount - 1; i >= 0; i--)
{
GameObject.Destroy(transform.GetChild(i).gameObject);
}
}
///
/// Retrieve angular measurement describing how large a sphere or circle appears from a given point of view.
/// Takes an angle (at given point of view) and a distance and returns the actual diameter of the object.
///
public static float ScaleFromAngularSizeAndDistance(float angle, float distance)
{
float scale = 1.5f * distance * Mathf.Tan(angle * Mathf.Deg2Rad * 0.5f);
return scale;
}
public static float GetYawAngleFromDirection(Vector3 direction)
{
float yaw = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;//所给方向与世界坐标系的z轴夹角(yaw angle,偏航角)
return yaw;
}
public static float GetPitchAngleFromDirection(Vector3 direction)
{
float pitch = Mathf.Atan2(direction.y, direction.z) * Mathf.Rad2Deg;
return pitch;
}
public static float GetRollAngleFromDirection(Vector3 direction)
{
float roll = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
return roll;
}
public static void LogFuncTimeStamp(Action func, string tag)
{
double beginTime = GetTimeStamp();
func?.Invoke();
double endTime = GetTimeStamp();
RKLog.Debug($"{tag}:" + (endTime - beginTime));
}
public static double GetTimeStamp()
{
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return ts.TotalMilliseconds;
}
public static long GetSystemStartupTimeStamp()
{
return (DateTime.Now.AddMilliseconds(-Environment.TickCount)).Ticks;
}
public static bool GetWorldPointInRectangle(RectTransform rect, Ray ray, out Vector3 worldPoint)
{
worldPoint = Vector2.zero;
Plane plane = new Plane(rect.rotation * Vector3.back, rect.position);
float enter = 0f;
float num = Vector3.Dot(Vector3.Normalize(rect.position - ray.origin), plane.normal);
if (num != 0f && !plane.Raycast(ray, out enter))
{
return false;
}
worldPoint = ray.GetPoint(enter);
return true;
}
public static bool GetWorldPointInRectangle(Graphic rect, Ray ray, out Vector3 worldPoint)
{
worldPoint = Vector2.zero;
Plane plane = new Plane(rect.transform.rotation * Vector3.back, rect.transform.position);
float enter = 0f;
float num = Vector3.Dot(Vector3.Normalize(rect.transform.position - ray.origin), plane.normal);
if (num != 0f && !plane.Raycast(ray, out enter))
{
return false;
}
worldPoint = ray.GetPoint(enter);
return true;
}
public static bool IsAndroidPlatfrom()
{
return Application.platform == RuntimePlatform.Android;
}
public static bool IsUnityEditor()
{
#if UNITY_EDITOR
return true;
#else
return false;
#endif
}
public static bool InCameraView(Vector3 point, Camera camera)
{
var v = camera.WorldToViewportPoint(point);
if (v.x > 0.8f || v.y > 0.8f || v.z < 0.1f)
{
return false;
}
return true;
}
private static bool useLeftEyeFov = true;
private static Vector4 halfFovTan = Vector4.zero;
public static Vector4 HalfFovTan
{
get
{
if (halfFovTan.x != 0)
return halfFovTan;
if (Utils.IsUnityEditor())
{
Camera cam = MainCameraCache.mainCamera;
float aspectRatio = cam.aspect;
float verticalFOV = cam.fieldOfView;
float horizontalFOV = 2f * Mathf.Atan(Mathf.Tan(verticalFOV * Mathf.Deg2Rad / 2f) * aspectRatio) * Mathf.Rad2Deg;
halfFovTan.x = halfFovTan.y = Mathf.Tan(horizontalFOV / 2 * Mathf.Deg2Rad);
halfFovTan.z = halfFovTan.w = Mathf.Tan(verticalFOV / 2 * Mathf.Deg2Rad);
}
else
{
float[] fov = new float[4];
NativeInterface.NativeAPI.GetUnityEyeFrustumHalf(!useLeftEyeFov, ref fov);
if (fov[0] > 0 && fov[1] > 0 && fov[2] > 0 && fov[3] > 0)
{
halfFovTan.x = Mathf.Tan(fov[0] * Mathf.Deg2Rad); // Left
halfFovTan.y = Mathf.Tan(fov[1] * Mathf.Deg2Rad); // Right
halfFovTan.z = Mathf.Tan(fov[2] * Mathf.Deg2Rad); // Top
halfFovTan.w = Mathf.Tan(fov[3] * Mathf.Deg2Rad); // Bottom
}
}
return halfFovTan;
}
}
public static Vector3[] GetCameraCorners(float dis, bool useLeftEyeFov = true)
{
Vector3[] corners = new Vector3[4];
Vector3 center = GetCameraCenter(dis);
Utils.useLeftEyeFov = useLeftEyeFov;
// Vector4 corner = Vector4.zero;
// corner.x = dis * HalfFovTan.x; // Left
// corner.y = -dis * HalfFovTan.y; // Right
// corner.z = dis * HalfFovTan.z; // Top
// corner.w = -dis * HalfFovTan.w; // Bottom
corners[0] = center + new Vector3(-dis * HalfFovTan.x, dis * HalfFovTan.z); // leftTop
corners[1] = center + new Vector3(dis * HalfFovTan.y, dis * HalfFovTan.z);// rightTop
corners[2] = center + new Vector3(-dis * HalfFovTan.x, -dis * HalfFovTan.w); //leftBottom
corners[3] = center + new Vector3(dis * HalfFovTan.y, -dis * HalfFovTan.w); //rightBottom
return corners;
}
public static Vector3 GetCameraCenter(float distance)
{
Vector4 halffovtan = Utils.HalfFovTan;
Vector2 pivot = new Vector2(halffovtan.y / (halffovtan.x + halffovtan.y), (halffovtan.z) / (halffovtan.z + halffovtan.w));
Vector3 center = MainCameraCache.mainCamera.ViewportToWorldPoint(new Vector3(pivot.x, pivot.y, distance));
if (Utils.IsAndroidPlatfrom())
{
//运行时相机 fov!=渲染 fov
center.y *= (NativeInterface.NativeAPI.GetVFov(true) / MainCameraCache.mainCamera.fieldOfView);
}
RKLog.KeyInfo($"====Utils==== GetCameraCenter halffovtan:{halffovtan},nativefov:{NativeInterface.NativeAPI.GetVFov(true)} mainCameraFov:{MainCameraCache.mainCamera.fieldOfView},pivot:{pivot},MainCameraProjectionMatrix:{MainCameraCache.mainCamera.projectionMatrix},distance:{distance},center:{center}");
return center;
}
// 获得分辨率,当选择 Free Aspect 直接返回相机的像素宽和高
public static Vector2 GetScreenPixelDimensions()
{
Vector2 dimensions = new Vector2(MainCameraCache.mainCamera.pixelWidth, MainCameraCache.mainCamera.pixelHeight);
#if UNITY_EDITOR
// 获取编辑器 GameView 的分辨率
float gameViewPixelWidth = 0, gameViewPixelHeight = 0;
float gameViewAspect = 0;
if (Editor__GetGameViewSize(out gameViewPixelWidth, out gameViewPixelHeight, out gameViewAspect))
{
if (gameViewPixelWidth != 0 && gameViewPixelHeight != 0)
{
dimensions.x = gameViewPixelWidth;
dimensions.y = gameViewPixelHeight;
}
}
#endif
return dimensions;
}
#if UNITY_EDITOR
static bool Editor__getGameViewSizeError = false;
public static bool Editor__gameViewReflectionError = false;
// 尝试获取 GameView 的分辨率
// 当正确获取到 GameView 的分辨率时,返回 true
public static bool Editor__GetGameViewSize(out float width, out float height, out float aspect)
{
try
{
Editor__gameViewReflectionError = false;
System.Type gameViewType = System.Type.GetType("UnityEditor.GameView,UnityEditor");
System.Reflection.MethodInfo GetMainGameView = gameViewType.GetMethod("GetMainGameView", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
object mainGameViewInst = GetMainGameView.Invoke(null, null);
if (mainGameViewInst == null)
{
width = height = aspect = 0;
return false;
}
System.Reflection.FieldInfo s_viewModeResolutions = gameViewType.GetField("s_viewModeResolutions", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
if (s_viewModeResolutions == null)
{
System.Reflection.PropertyInfo currentGameViewSize = gameViewType.GetProperty("currentGameViewSize", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
object gameViewSize = currentGameViewSize.GetValue(mainGameViewInst, null);
System.Type gameViewSizeType = gameViewSize.GetType();
int gvWidth = (int)gameViewSizeType.GetProperty("width").GetValue(gameViewSize, null);
int gvHeight = (int)gameViewSizeType.GetProperty("height").GetValue(gameViewSize, null);
int gvSizeType = (int)gameViewSizeType.GetProperty("sizeType").GetValue(gameViewSize, null);
if (gvWidth == 0 || gvHeight == 0)
{
width = height = aspect = 0;
return false;
}
else if (gvSizeType == 0)
{
width = height = 0;
aspect = (float)gvWidth / (float)gvHeight;
return true;
}
else
{
width = gvWidth; height = gvHeight;
aspect = (float)gvWidth / (float)gvHeight;
return true;
}
}
else
{
Vector2[] viewModeResolutions = (Vector2[])s_viewModeResolutions.GetValue(null);
float[] viewModeAspects = (float[])gameViewType.GetField("s_viewModeAspects", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).GetValue(null);
string[] viewModeStrings = (string[])gameViewType.GetField("s_viewModeAspectStrings", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).GetValue(null);
if (mainGameViewInst != null
&& viewModeStrings != null
&& viewModeResolutions != null && viewModeAspects != null)
{
int aspectRatio = (int)gameViewType.GetField("m_AspectRatio", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).GetValue(mainGameViewInst);
string thisViewModeString = viewModeStrings[aspectRatio];
if (thisViewModeString.Contains("Standalone"))
{
width = UnityEditor.PlayerSettings.defaultScreenWidth; height = UnityEditor.PlayerSettings.defaultScreenHeight;
aspect = width / height;
}
else if (thisViewModeString.Contains("Web"))
{
width = UnityEditor.PlayerSettings.defaultWebScreenWidth; height = UnityEditor.PlayerSettings.defaultWebScreenHeight;
aspect = width / height;
}
else
{
width = viewModeResolutions[aspectRatio].x; height = viewModeResolutions[aspectRatio].y;
aspect = viewModeAspects[aspectRatio];
// this is an error state
if (width == 0 && height == 0 && aspect == 0)
{
return false;
}
}
return true;
}
}
}
catch (System.Exception e)
{
if (Editor__getGameViewSizeError == false)
{
Debug.LogError("GameCamera.GetGameViewSize - has a Unity update broken this?\nThis is not a fatal error !\n" + e.ToString());
Editor__getGameViewSizeError = true;
}
Editor__gameViewReflectionError = true;
}
width = height = aspect = 0;
return false;
}
#endif
}
}