// Copyright 2016 Nibiru. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// 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 UnityEngine;
//Utility class that includes functions for calculating camera properties.
namespace Nxr.Internal
{
public class NxrCameraUtils
{
public static void FixProjection(Rect camRect, float nearClipPlane, float farClipPlane,
ref Matrix4x4 proj)
{
// Adjust for non-fullscreen camera. NxrViewer assumes fullscreen,
// so the aspect ratio might not match.
proj[0, 0] *= camRect.height / camRect.width / 2;
// NxrViewer had to pass "nominal" values of near/far to the native layer, which
// we fix here to match our mono camera's specific values.
proj[2, 2] = (nearClipPlane + farClipPlane) / (nearClipPlane - farClipPlane);
proj[2, 3] = 2 * nearClipPlane * farClipPlane / (nearClipPlane - farClipPlane);
}
public static Rect FixViewport(Rect rect, Rect viewport, bool isRightEye)
{
// We are rendering straight to the screen. Use the reported rect that is visible
// through the device's lenses.
if (isRightEye)
{
rect.x -= 0.5f;
}
rect.width *= 2 * viewport.width;
rect.x = viewport.x + 2 * rect.x * viewport.width;
rect.height *= viewport.height;
rect.y = viewport.y + rect.y * viewport.height;
return rect;
}
public static Rect FixEditorViewport(Rect rect, float profileAspect, float windowAspect)
{
float aspectComparison = profileAspect / windowAspect;
if (aspectComparison < 1)
{
rect.width *= aspectComparison;
rect.x *= aspectComparison;
rect.x += (1 - aspectComparison) / 2;
}
else
{
rect.height /= aspectComparison;
rect.y /= aspectComparison;
}
return rect;
}
public static void ZoomStereoCameras(float matchByZoom, float matchMonoFOV, float monoProj11,
ref Matrix4x4 proj)
{
float lerp = Mathf.Clamp01(matchByZoom) * Mathf.Clamp01(matchMonoFOV);
// Lerping the reciprocal of proj(1,1), so zoom is linear in frustum height not the depth.
float zoom = 1 / Mathf.Lerp(1 / proj[1, 1], 1 / monoProj11, lerp) / proj[1, 1];
proj[0, 0] *= zoom;
proj[1, 1] *= zoom;
}
//旋转矩阵转换成四元数
//RotationMatrix to Quaternion
public static void RotationMatrix_to_Quaternion(ref float[] quaternion, float[] r)
{
quaternion = new float[4] { 0, 0, 0, 0 };
//探测四元数中最大的项
float fourWSquaredMinusl = r[0] + r[4] + r[8];
float fourXSquaredMinusl = r[0] - r[4] - r[8];
float fourYSquaredMinusl = r[4] - r[0] - r[8];
float fourZSquaredMinusl = r[8] - r[0] - r[4];
int biggestIndex = 0;
float fourBiggestSqureMinus1 = fourWSquaredMinusl;
if (fourXSquaredMinusl > fourBiggestSqureMinus1)
{
fourBiggestSqureMinus1 = fourXSquaredMinusl;
biggestIndex = 1;
}
if (fourYSquaredMinusl > fourBiggestSqureMinus1)
{
fourBiggestSqureMinus1 = fourYSquaredMinusl;
biggestIndex = 2;
}
if (fourZSquaredMinusl > fourBiggestSqureMinus1)
{
fourBiggestSqureMinus1 = fourZSquaredMinusl;
biggestIndex = 3;
}
//计算平方根和除法
float biggestVal = Mathf.Sqrt(fourBiggestSqureMinus1 + 1.0f) * 0.5f;
float mult = 0.25f / biggestVal;
//计算四元数的值
switch (biggestIndex)
{
case 0:
quaternion[3] = biggestVal;
quaternion[0] = (r[5] - r[7]) * mult;
quaternion[1] = (r[6] - r[2]) * mult;
quaternion[2] = (r[1] - r[3]) * mult;
break;
case 1:
quaternion[0] = biggestVal;
quaternion[3] = (r[5] - r[7]) * mult;
quaternion[1] = (r[1] + r[3]) * mult;
quaternion[2] = (r[6] + r[2]) * mult;
break;
case 2:
quaternion[1] = biggestVal;
quaternion[3] = (r[6] - r[2]) * mult;
quaternion[0] = (r[1] + r[3]) * mult;
quaternion[2] = (r[5] + r[7]) * mult;
break;
case 3:
quaternion[2] = biggestVal;
quaternion[3] = (r[1] - r[3]) * mult;
quaternion[0] = (r[6] + r[2]) * mult;
quaternion[1] = (r[5] + r[7]) * mult;
break;
}
}
//旋转矩阵转换成欧拉角
///
///
///
///
/// 3X3
public static void RotationMatrixToEulerAngles(ref float[] eulerAngle, float[] rm)
{
float sy = Mathf.Sqrt(rm[0] * rm[0] + rm[3] * rm[3]);
bool singular = sy < 1e-6; // If
float x, y, z;
if (!singular)
{
x = Mathf.Atan2(rm[7], rm[8]);
y = Mathf.Atan2(-rm[6], sy);
z = Mathf.Atan2(rm[3], rm[0]);
}
else
{
x = Mathf.Atan2(-rm[5], rm[4]);
y = Mathf.Atan2(-rm[6], sy);
z = 0;
}
x = x * 180.0f / Mathf.PI;
y = y * 180.0f / Mathf.PI;
z = z * 180.0f / Mathf.PI;
eulerAngle = new float[3] { x, y, z };
}
}
}