powerfun-unity/Assets/AR/ARRoute.cs
2023-01-17 18:07:49 +08:00

583 lines
27 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace Assets.AR
{
public class ARRoute
{
private const float ProjectionSmoothFrames = 30f;
private const float DefaultNearSideOffset = 0.0f;
private const float DefaultFarSideOffset = 4f;
public int[] LeftSideOffsetFrames;
public float[] LeftSideOffsets;
public int[] RightSideOffsetFrames;
public float[] RightSideOffsets;
public bool RearMode;
public ARRoute()
{
}
public ARRoute(ARRouteData data) => this.LoadData(data);
public int[] Visibility { get; set; }
public Vector3[] CameraPositions { get; set; }
public Vector3[] FilteredCameraPositions { get; set; }
public double[] FrameDistances { get; set; }
public Quaternion[] CameraRotations { get; set; }
public Quaternion[] CameraRotationsRear { get; set; }
public Quaternion[] TrajectoryOrientation { get; set; }
public float[] TrajectoryCurvatures { get; set; }
public float[] LightRotationFrames { get; set; }
public Quaternion[] LightRotations { get; set; }
public float[] ShadowIntensityFrames { get; set; }
public float[] ShadowIntensities { get; set; }
public SphericalHarmonicsL2[] SphericalHarmonics { get; set; }
public int[] SlamSegments { get; set; }
public CameraProjectionParameters[] ProjectionParameters { get; set; }
public bool LeftHanded { get; set; }
public int VideoFrameOffset { get; set; }
public float CameraHeight { get; set; }
public float RiderScale { get; set; } = 1f;
public float RouteMargin { get; private set; } = 2f;
public bool HasLeftSideOffsets => this.LeftSideOffsetFrames != null && this.LeftSideOffsets != null;
public bool HasRightSideOffsets => this.RightSideOffsetFrames != null && this.RightSideOffsets != null;
public int FrameCount => this.CameraPositions.Length;
public double Lenght => this.FrameDistances[this.FrameCount - 1];
private float DefaultLeftSideOffset => !this.LeftHanded ? 4f : 0.0f;
private float DefaultRightSideOffset => !this.LeftHanded ? 0.0f : 4f;
public int GetVisibilityAt(int frame)
{
if (this.Visibility == null || this.Visibility.Length == 0)
return 0;
if (frame <= 0)
return this.Visibility[0];
return frame >= this.Visibility.Length ? this.Visibility[this.Visibility.Length - 1] : this.Visibility[frame];
}
public float GetVisibility(float frame)
{
if (this.Visibility == null || this.Visibility.Length == 0)
return 0.0f;
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return (float)this.Visibility[0];
if (index >= this.Visibility.Length)
return (float)this.Visibility[this.Visibility.Length - 1];
float t = frame - (float)(index - 1);
return Mathf.Lerp((float)this.Visibility[index - 1], (float)this.Visibility[index], t);
}
public Vector3 GetCameraPositionAt(int frame)
{
if (frame <= 0)
return this.CameraPositions[0];
return frame >= this.FrameCount ? this.CameraPositions[this.CameraPositions.Length - 1] : this.CameraPositions[frame];
}
public Vector3 GetCameraPosition(float frame)
{
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.CameraPositions[0];
if (index >= this.FrameCount)
return this.CameraPositions[this.CameraPositions.Length - 1];
float t = frame - (float)(index - 1);
return Vector3.Lerp(this.CameraPositions[index - 1], this.CameraPositions[index], t);
}
public Vector3 GetFilteredCameraPositionAt(int frame)
{
if (frame <= 0)
return this.FilteredCameraPositions[0];
return frame >= this.FrameCount ? this.FilteredCameraPositions[this.FilteredCameraPositions.Length - 1] : this.FilteredCameraPositions[frame];
}
public Vector3 GetFilteredCameraPosition(float frame)
{
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.FilteredCameraPositions[0];
if (index >= this.FrameCount)
return this.FilteredCameraPositions[this.FilteredCameraPositions.Length - 1];
float t = frame - (float)(index - 1);
return Vector3.Lerp(this.FilteredCameraPositions[index - 1], this.FilteredCameraPositions[index], t);
}
public Quaternion GetCameraRotationAt(int frame)
{
if (frame <= 0)
return this.CameraRotations[0];
return frame >= this.FrameCount ? this.CameraRotations[this.CameraRotations.Length - 1] : this.CameraRotations[frame];
}
public Quaternion GetCameraRotation(float frame)
{
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.CameraRotations[0];
if (index >= this.FrameCount)
return this.CameraRotations[this.CameraRotations.Length - 1];
float t = frame - (float)(index - 1);
return Quaternion.Slerp(this.CameraRotations[index - 1], this.CameraRotations[index], t);
}
public Quaternion GetCameraRotationRear(float frame)
{
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.CameraRotationsRear[0];
if (index >= this.FrameCount)
return this.CameraRotationsRear[this.CameraRotationsRear.Length - 1];
float t = frame - (float)(index - 1);
return Quaternion.Slerp(this.CameraRotationsRear[index - 1], this.CameraRotationsRear[index], t);
}
public int GetSlamSegmentIndex(float frame)
{
for (int index = 1; index < this.SlamSegments.Length; ++index)
{
if ((double)this.SlamSegments[index] > (double)frame)
return index - 1;
}
return this.SlamSegments.Length - 1;
}
public void GetSlamSegmentRange(int index, out int start, out int end)
{
index = Mathf.Clamp(index, 0, this.SlamSegments.Length - 1);
start = this.SlamSegments[index];
if (index < this.SlamSegments.Length - 1)
end = this.SlamSegments[index + 1];
else
end = this.FrameCount;
}
public void GetVisibleSlamSegments(
int frame,
out int start,
out int end,
float defultVisibility = 0.0f)
{
float num = (float)this.GetVisibilityAt(frame);
if ((double)num == 0.0)
num = defultVisibility;
start = this.GetSlamSegmentIndex((float)frame);
end = this.GetSlamSegmentIndex((float)frame + num);
}
public double GetFrameAtDistance(double distance)
{
double[] frameDistances = this.FrameDistances;
int index = Array.BinarySearch<double>(frameDistances, distance);
if (index < 0)
index = ~index;
if (index == 0)
return 0.0;
if (index == frameDistances.Length)
return (double)(frameDistances.Length - 1);
double num = VTMath.InverseLerp(frameDistances[index - 1], frameDistances[index], distance);
return (double)index + num - 1.0;
}
public double GetTotalDistance()
{
return FrameDistances[FrameDistances.Length-1];
}
public double GetDistanceForFrame(double frame)
{
int index = (int)Math.Ceiling(frame);
if (index <= 0)
return this.FrameDistances[0];
if (index >= this.FrameCount)
return this.FrameDistances[this.FrameDistances.Length - 1];
double t = frame - (double)(index - 1);
return VTMath.Lerp(this.FrameDistances[index - 1], this.FrameDistances[index], t);
}
public CameraProjectionParameters GetCameraProjectionParameters(
float frame)
{
int index = Mathf.Clamp(this.GetSlamSegmentIndex(frame), 0, this.ProjectionParameters.Length - 1);
CameraProjectionParameters projectionParameter1 = this.ProjectionParameters[index];
int slamSegment1 = this.SlamSegments[index];
if (index > 0 && (double)frame < (double)slamSegment1 + 15.0)
{
float t = (float)(0.5 + ((double)frame - (double)slamSegment1) / 30.0);
return CameraProjectionParameters.Lerp(this.ProjectionParameters[index - 1], projectionParameter1, t);
}
if (index < this.SlamSegments.Length - 1)
{
int slamSegment2 = this.SlamSegments[index + 1];
if ((double)frame > (double)slamSegment2 - 15.0)
{
float t = (float)(0.5 - ((double)slamSegment2 - (double)frame) / 30.0);
CameraProjectionParameters projectionParameter2 = this.ProjectionParameters[index + 1];
return CameraProjectionParameters.Lerp(projectionParameter1, projectionParameter2, t);
}
}
return projectionParameter1;
}
//设置摄像机投影矩阵
public void SetCameraProjection(float frame, Camera camera, bool fitInside = false)
{
CameraProjectionParameters projectionParameters = this.GetCameraProjectionParameters(frame);
if ((double)projectionParameters.alpha == 0.0)
return;
float num1 = projectionParameters.cx / projectionParameters.cy;
float num2 = (float)Screen.width / (float)Screen.height;
float cx = projectionParameters.cx;
float cy = projectionParameters.cy;
if (fitInside)
{
if ((double)num2 > (double)num1)
cx = cy * num2;
if ((double)num2 < (double)num1)
cy = cx * 1f / num2;
}
else
{
if ((double)num2 < (double)num1)
cx = cy * num2;
if ((double)num2 > (double)num1)
cy = cx * 1f / num2;
}
camera.projectionMatrix = this.GetCameraProjectionMatrix(projectionParameters.alpha, projectionParameters.beta, cx, cy, camera.nearClipPlane, camera.farClipPlane);
}
private Matrix4x4 GetCameraProjectionMatrix(
float alpha,
float beta,
float cx,
float cy,
float nearClipPlane,
float farClipPlane)
{
Matrix4x4 projectionMatrix = new Matrix4x4();
float z = (float)(-((double)farClipPlane + (double)nearClipPlane) / ((double)farClipPlane - (double)nearClipPlane));
float w = (float)(-2.0 * (double)farClipPlane * (double)nearClipPlane / ((double)farClipPlane - (double)nearClipPlane));
projectionMatrix.SetRow(0, new Vector4(alpha / cx, 0.0f, 0.0f, 0.0f));
projectionMatrix.SetRow(1, new Vector4(0.0f, beta / cy, 0.0f, 0.0f));
projectionMatrix.SetRow(2, new Vector4(0.0f, 0.0f, z, w));
projectionMatrix.SetRow(3, new Vector4(0.0f, 0.0f, -1f, 0.0f));
return projectionMatrix;
}
//处理摄像机3d位置
public void CreateFilteredCameraPositions()
{
int length = this.CameraPositions.Length;
Vector3[] vector3Array = new Vector3[length];
for (int index = 0; index < length; ++index)
vector3Array[index] = this.CameraPositions[index];
for (int index1 = 0; index1 < 3; ++index1)
{
for (int index2 = 1; index2 < vector3Array.Length - 1; ++index2)
vector3Array[index2] = (vector3Array[index2 - 1] + vector3Array[index2] + vector3Array[index2 + 1]) / 3f;
}
this.FilteredCameraPositions = vector3Array;
}
//创建摄像机在3d空间的距离
private void CreateFrameDistances()
{
int length = this.CameraPositions.Length;
this.FrameDistances = new double[length];
this.FrameDistances[0] = 0.0;
double num = 0.0;
for (int index = 1; index < length; ++index)
{
num += (double)Vector3.Distance(this.CameraPositions[index - 1], this.CameraPositions[index]);
this.FrameDistances[index] = num;
}
}
//创建轨迹上的转向
public void CreateTrajectoryOrientations()
{
Quaternion[] quaternionArray = new Quaternion[this.FilteredCameraPositions.Length];
for (int index = 1; index < this.FilteredCameraPositions.Length - 1; ++index)
quaternionArray[index] = Quaternion.LookRotation(this.FilteredCameraPositions[index + 1] - this.FilteredCameraPositions[index - 1], Vector3.up);
quaternionArray[0] = quaternionArray[1];
quaternionArray[this.FilteredCameraPositions.Length - 1] = quaternionArray[this.FilteredCameraPositions.Length - 2];
this.TrajectoryOrientation = quaternionArray;
}
//获取轨迹上某帧的转向
public Quaternion GetTrajectoryOrientationAt(int frame)
{
int index = Mathf.Clamp(frame, 0, this.FrameCount);
if (index <= 0)
return this.TrajectoryOrientation[0];
return index >= this.FrameCount ? this.TrajectoryOrientation[this.TrajectoryOrientation.Length - 1] : this.TrajectoryOrientation[index];
}
//鬼区轨迹上模糊帧的转向
public Quaternion GetTrajectoryOrientation(float frame)
{
frame = Mathf.Clamp(frame, 0.0f, (float)this.FrameCount);
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.TrajectoryOrientation[0];
if (index >= this.FrameCount)
return this.TrajectoryOrientation[this.TrajectoryOrientation.Length - 1];
float t = frame - (float)(index - 1);
return Quaternion.Slerp(this.TrajectoryOrientation[index - 1], this.TrajectoryOrientation[index], t);
}
public float GetTrajectoryCurvature(float frame)
{
int index = (int)Math.Ceiling((double)frame);
if (index <= 0)
return this.TrajectoryCurvatures[0];
if (index >= this.FrameCount)
return this.TrajectoryCurvatures[this.TrajectoryCurvatures.Length - 1];
float t = frame - (float)(index - 1);
return Mathf.Lerp(this.TrajectoryCurvatures[index - 1], this.TrajectoryCurvatures[index], t);
}
public Quaternion GetLightDirection(float distance)
{
if (this.LightRotations == null || this.LightRotations.Length == 0)
return Quaternion.Euler(new Vector3(90f, 0.0f, 0.0f));
int index1 = 0;
for (int index2 = 0; index2 < this.LightRotationFrames.Length; ++index2)
{
if ((double)this.LightRotationFrames[index2] < (double)distance)
index1 = index2;
}
if (index1 + 1 == this.LightRotations.Length)
return this.LightRotations[this.LightRotations.Length - 1];
float t = Mathf.InverseLerp(this.LightRotationFrames[index1], this.LightRotationFrames[index1 + 1], distance);
return Quaternion.Slerp(this.LightRotations[index1], this.LightRotations[index1 + 1], t);
}
public float GetShadowIntensity(float distance)
{
if (this.ShadowIntensities == null || this.ShadowIntensities.Length == 0)
return 1f;
int index1 = 0;
for (int index2 = 0; index2 < this.ShadowIntensityFrames.Length; ++index2)
{
if ((double)this.ShadowIntensityFrames[index2] < (double)distance)
index1 = index2;
}
if (index1 + 1 == this.ShadowIntensities.Length)
return this.ShadowIntensities[this.ShadowIntensities.Length - 1];
float t = Mathf.InverseLerp(this.ShadowIntensityFrames[index1], this.ShadowIntensityFrames[index1 + 1], distance);
return Mathf.Lerp(this.ShadowIntensities[index1], this.ShadowIntensities[index1 + 1], t);
}
public float GetLeftSideOffset(float frame)
{
if (!this.HasLeftSideOffsets)
return this.DefaultLeftSideOffset;
int index = Array.BinarySearch<int>(this.LeftSideOffsetFrames, (int)Math.Ceiling((double)frame));
if (index < 0)
index = ~index;
if (index == 0)
return this.LeftSideOffsets[0];
if (index == this.LeftSideOffsetFrames.Length)
return this.LeftSideOffsets[this.LeftSideOffsetFrames.Length - 1];
float t = Mathf.InverseLerp((float)this.LeftSideOffsetFrames[index - 1], (float)this.LeftSideOffsetFrames[index], frame);
return Mathf.Lerp(this.LeftSideOffsets[index - 1], this.LeftSideOffsets[index], t);
}
public float GetRightSideOffset(float frame)
{
if (!this.HasRightSideOffsets)
return this.DefaultRightSideOffset;
int index = Array.BinarySearch<int>(this.RightSideOffsetFrames, (int)Math.Ceiling((double)frame));
if (index < 0)
index = ~index;
if (index == 0)
return this.RightSideOffsets[0];
if (index == this.RightSideOffsetFrames.Length)
return this.RightSideOffsets[this.RightSideOffsetFrames.Length - 1];
float t = Mathf.InverseLerp((float)this.RightSideOffsetFrames[index - 1], (float)this.RightSideOffsetFrames[index], frame);
return Mathf.Lerp(this.RightSideOffsets[index - 1], this.RightSideOffsets[index], t);
}
public void LoadData(ARRouteData data)
{
this.Visibility = data.Visibility;
this.VideoFrameOffset = data.VideoFrameOffset;
this.LeftHanded = data.LeftHanded;
this.SlamSegments = data.SlamSegments;
this.CameraHeight = data.CameraHeight;
this.RiderScale = (double)data.RiderScale != 0.0 ? data.RiderScale : 1f;
this.RiderScale *= 0.9f;
this.CameraPositions = ((IEnumerable<VectorData>)data.CameraPositions).Select<VectorData, Vector3>((Func<VectorData, Vector3>)(x => x.ToUnityVector())).ToArray<Vector3>();
this.ProjectionParameters = data.CameraProjectionParameters;
this.CameraRotations = ((IEnumerable<VectorData>)data.CameraRotations).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>();
VectorData[] cameraRotationsRear = data.CameraRotationsRear;
this.CameraRotationsRear = cameraRotationsRear != null ? ((IEnumerable<VectorData>)cameraRotationsRear).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>() : (Quaternion[])null;
this.LeftSideOffsetFrames = data.LeftSideOffsetFrames;
this.LeftSideOffsets = data.LeftSideOffsets;
this.RightSideOffsetFrames = data.RightSideOffsetFrames;
this.RightSideOffsets = data.RightSideOffsets;
if (data.LightRotationFrames == null || data.LightRotationFrames.Length == 0)
{
this.LightRotationFrames = new float[0];
this.LightRotations = new Quaternion[0];
}
else
{
this.LightRotations = ((IEnumerable<VectorData>)data.LightRotations).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>();
this.LightRotationFrames = data.LightRotationFrames;
}
if (data.ShadowIntensityFrames == null || data.ShadowIntensityFrames.Length == 0)
{
this.ShadowIntensityFrames = new float[0];
this.ShadowIntensities = new float[0];
}
else
{
this.ShadowIntensities = data.ShadowIntensities;
this.ShadowIntensityFrames = data.ShadowIntensityFrames;
}
this.SphericalHarmonics = this.LoadSphericalHarmonics(data.SphericalHarmonics);
this.CreateFilteredCameraPositions();
this.CreateFrameDistances();
this.CreateTrajectoryOrientations();
this.CreateTrajectoryCurvatures();
}
public ARRouteData ToARRouteData()
{
ARRouteData arRouteData = new ARRouteData();
arRouteData.Visibility = this.Visibility;
arRouteData.VideoFrameOffset = this.VideoFrameOffset;
arRouteData.LeftHanded = this.LeftHanded;
arRouteData.SlamSegments = this.SlamSegments;
arRouteData.CameraHeight = this.CameraHeight;
arRouteData.RiderScale = (double)this.RiderScale != 0.0 ? this.RiderScale : 1f;
arRouteData.CameraPositions = ((IEnumerable<Vector3>)this.CameraPositions).Select<Vector3, VectorData>((Func<Vector3, VectorData>)(x => new VectorData(x))).ToArray<VectorData>();
arRouteData.CameraProjectionParameters = this.ProjectionParameters;
arRouteData.CameraRotations = ((IEnumerable<Quaternion>)this.CameraRotations).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
arRouteData.LeftSideOffsetFrames = this.LeftSideOffsetFrames;
arRouteData.LeftSideOffsets = this.LeftSideOffsets;
arRouteData.RightSideOffsetFrames = this.RightSideOffsetFrames;
arRouteData.RightSideOffsets = this.RightSideOffsets;
if (this.LightRotationFrames == null || this.LightRotationFrames.Length == 0)
{
arRouteData.LightRotationFrames = new float[0];
arRouteData.LightRotations = ((IEnumerable<Quaternion>)new Quaternion[0]).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
}
else
{
arRouteData.LightRotations = ((IEnumerable<Quaternion>)this.LightRotations).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
arRouteData.LightRotationFrames = this.LightRotationFrames;
}
if (this.ShadowIntensityFrames == null || this.ShadowIntensityFrames.Length == 0)
{
arRouteData.ShadowIntensityFrames = new float[1];
arRouteData.ShadowIntensities = new float[1] { 1f };
}
else
{
arRouteData.ShadowIntensities = this.ShadowIntensities;
arRouteData.ShadowIntensityFrames = this.ShadowIntensityFrames;
}
arRouteData.SphericalHarmonics = this.StoreSphericalHarmonics(this.SphericalHarmonics);
return arRouteData;
}
private SphericalHarmonicsL2[] LoadSphericalHarmonics(float[] coefficients)
{
if (coefficients == null || coefficients.Length == 0)
return (SphericalHarmonicsL2[])null;
if (coefficients.Length % 27 != 0)
throw new ArgumentException("An array of SH coefficients must be divisible by 27.");
int num = 0;
SphericalHarmonicsL2[] sphericalHarmonicsL2Array = new SphericalHarmonicsL2[coefficients.Length / 27];
for (int index = 0; index < coefficients.Length / 27; ++index)
{
for (int rgb = 0; rgb < 3; ++rgb)
{
for (int coefficient = 0; coefficient < 9; ++coefficient)
sphericalHarmonicsL2Array[index][rgb, coefficient] = coefficients[num++];
}
}
return sphericalHarmonicsL2Array;
}
private float[] StoreSphericalHarmonics(SphericalHarmonicsL2[] sphericalHarmonics)
{
if (sphericalHarmonics == null || sphericalHarmonics.Length == 0)
return (float[])null;
int num = 0;
float[] numArray = new float[sphericalHarmonics.Length * 27];
for (int index = 0; index < sphericalHarmonics.Length; ++index)
{
for (int rgb = 0; rgb < 3; ++rgb)
{
for (int coefficient = 0; coefficient < 9; ++coefficient)
numArray[num++] = sphericalHarmonics[index][rgb, coefficient];
}
}
return numArray;
}
private void CreateTrajectoryCurvatures()
{
Vector3[] cameraPositions = this.CameraPositions;
double[] frameDistances = this.FrameDistances;
int length = cameraPositions.Length;
float[] numArray = new float[length];
for (int index = 0; index < length; ++index)
{
Vector3 aP1 = cameraPositions[index];
double num = frameDistances[index];
Vector3 filteredCameraPosition1 = this.GetFilteredCameraPosition((float)this.GetFrameAtDistance(num - 10.0));
Vector3 filteredCameraPosition2 = this.GetFilteredCameraPosition((float)this.GetFrameAtDistance(num + 10.0));
Vector3 center;
if (!Geometry.CircleCenter(filteredCameraPosition1, aP1, filteredCameraPosition2, out center))
{
numArray[index] = 0.0f;
}
else
{
float magnitude = (center - filteredCameraPosition1).magnitude;
Vector3 normalized = Vector3.Cross(aP1 - filteredCameraPosition1, Vector3.up).normalized;
if (((double)center.x - (double)filteredCameraPosition1.x) * (double)normalized.x + ((double)center.y - (double)filteredCameraPosition1.y) * (double)normalized.y + ((double)center.z - (double)filteredCameraPosition1.z) * (double)normalized.z < 0.0)
magnitude *= -1f;
numArray[index] = 1f / magnitude;
}
}
for (int index1 = 0; index1 < 2; ++index1)
{
for (int index2 = 1; index2 < numArray.Length - 1; ++index2)
numArray[index2] = (float)(((double)numArray[index2 - 1] + (double)numArray[index2] + (double)numArray[index2 + 1]) / 3.0);
}
this.TrajectoryCurvatures = numArray;
}
}
}