ar帧数匹配精准度问题

This commit is contained in:
lishuo 2022-11-25 19:18:21 +08:00
parent e3059fc1c2
commit 9552fed2e0
57 changed files with 852691 additions and 1 deletions

8
Assets/AR.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 328b5d62a858984408481bbfd6024557
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

72
Assets/AR/ARLaneObject.cs Normal file
View File

@ -0,0 +1,72 @@
using UnityEngine;
using DG.Tweening;
namespace Assets.AR
{
public class ARLaneObject : ARObject
{
public Vector3 Lean { get; set; }//偏移量
public int StartPosition;
public bool IsAtFinish { get; set; }//是否到达终点
public float RouteDistance { get; set; }//线路上的距离
public float Lane { get; set; }//车道上的位置
public float BaseOffset { get; set; }//基准偏移量
public float DeltaLane { get; set; }//
public float LaneWidth { get; set; }//车道宽度
public float Speed { get; set; }//速度
public float Curvature { get; set; }//转向
public float LaneChangingDirection { get; set; }//方向
public float LaneCamera { get; set; }//车道上摄像机的位置
public float DistanceSort { get; set; }//距离排序
public float FrameIndexDistanceCorrection { get; set; }//位置纠正
public double TestPower = 500;
//重置碰撞检测参数
public void ResetCollisionDetectionParameters()
{
this.StartPosition = 0;//开始位置
this.Lane = 0.0f;//轨迹上的距离
this.DeltaLane = 0.0f;//差距
this.LaneWidth = 0.0f;//轨迹宽度
this.LaneCamera = 0.0f;//轨迹上摄像头的位置
this.DistanceSort = 0.0f;//距离上的远近
this.Curvature = 0.0f;//角度
this.LaneChangingDirection = 0.0f;//偏转方向
}
//更新人物的位置和转向
public override void UpdateTransform()
{
PositionOffset = Vector3.up * route.CameraHeight * (-1);
Quaternion cameraRotation = this.GetCameraRotation(this.frame - this.FrameIndexDistanceCorrection);
Vector3 filteredCameraPosition = this.GetFilteredCameraPosition(this.frame + this.FrameIndexDistanceCorrection);
Debug.Log($"{filteredCameraPosition}={this.CameraPositionOffset}:{this.Route.GetFilteredCameraPosition(this.frame )}");
Vector3 vector3 = Vector3.left * (this.route.LeftHanded ? -1f : 1f) * (this.LaneWidth * (this.Lane + this.LaneCamera) - this.BaseOffset);
this.transform.position = filteredCameraPosition + cameraRotation * (vector3 + this.PositionOffset);
this.transform.rotation = cameraRotation * Quaternion.Euler(this.RotationOffset) * Quaternion.Euler(this.Lean);
this.transform.localScale = this.Scale;
var animator = GetComponent<Animator>();
animator.SetFloat("speed", 30);
animator.SetFloat("power", (float)TestPower);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c83121d82f416c345a6250c354717a41
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,258 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Assets.AR
{
public abstract class ARLaneObjectsController : ARObjectsController
{
protected const float LaneWidth = 0.7f;
protected const float StartRegionDistance = 200f;
private const float StartRowsGap = 2.2f;
private const float StartRowsRandomDistance = 0.4f;
private const float StartRowsRandomWidth = 0.15f;
private const float MinCollisionDistance = 1.33f;
protected readonly Dictionary<int, ARLaneObject> riderObjects = new Dictionary<int, ARLaneObject>();
private readonly Dictionary<int, Vector2> randomizedStartOffsets = new Dictionary<int, Vector2>();
private readonly List<ARLaneObject> collisionList = new List<ARLaneObject>();
public bool AllowStartOrder { get; set; } = true;
protected float StartRegionRouteWidth { get; private set; }
protected int RiderCountInStartRow { get; private set; }
public float OvertakingThreshold { get; set; } = 5f;
public bool NearViewMode { get; set; }
public int FollowedRiderId { get; set; }
public IReadOnlyDictionary<int, ARLaneObject> ArRiders => (IReadOnlyDictionary<int, ARLaneObject>)this.riderObjects;
protected virtual void Start()
{
float frame = 100f;
this.StartRegionRouteWidth = this.GetRouteLeftOffset(frame) + this.GetRouteRightOffset(frame);
this.RiderCountInStartRow = Mathf.Max(1, Mathf.CeilToInt(this.StartRegionRouteWidth / 0.7f));
}
protected override void UpdateObjects(
float videoFrame,
float visibilityRear,
float visibilityFront)
{
base.UpdateObjects(videoFrame, visibilityRear, visibilityFront);//控制3d物体显示隐藏
if (this.Route == null || this.videoSync == null)
return;
this.DetectRidersCollisions(this.CameraDistance);//计算3d物体的位置和转向
}
//检测碰撞
private void DetectRidersCollisions(float cameraDistance)
{
float num1 = cameraDistance - ARObject.MaxDistanceVisibilityModels;
float num2 = cameraDistance + ARObject.MaxDistanceVisibilityModels;
this.collisionList.Clear();
foreach (ARLaneObject arLaneObject in this.riderObjects.Values)
{
if (arLaneObject.gameObject.activeSelf && !arLaneObject.IsAtFinish)
{
if ((double)arLaneObject.Distance >= (double)num1 && (double)arLaneObject.Distance <= (double)num2)
{
this.collisionList.Add(arLaneObject);
arLaneObject.DistanceSort = arLaneObject.Distance;
}
}
}
foreach (ARLaneObject collision in this.collisionList)
{
if ((double)collision.RouteDistance < 200.0)
{
collision.Distance = this.GetModelRouteDistance(collision.StartPosition, collision.RouteDistance);
collision.DistanceSort = collision.Distance;
}
}
this.collisionList.Sort((Comparison<ARLaneObject>)((r1, r2) =>
{
int num3 = r1.Lane.CompareTo(r2.Lane);
if (num3 == 0)
num3 = r2.DistanceSort.CompareTo(r1.DistanceSort);
return num3;
}));
float deltaTime = Time.deltaTime;
for (int index = 0; index < this.collisionList.Count; ++index)
{
ARLaneObject collision = this.collisionList[index];
float lane = collision.Lane;
float num4 = this.GetLane(collision.RouteDistance, collision.DistanceSort, index);
if ((double)collision.LaneWidth != 0.0)
{
float num5 = 0.02f * deltaTime * Mathf.Log(collision.Speed + 5f, 1.1f);
num4 = Mathf.Clamp(num4, lane - num5, lane + num5 * 1.5f);
collision.DeltaLane = (num4 - lane) / deltaTime;
}
collision.Lane = num4;
}
this.CalculateOvertakingParameters();
foreach (ARLaneObject collision in this.collisionList)
{
collision.LaneWidth = 0.7f;
float num6 = this.Route.LeftHanded ? this.GetRouteLeftOffset(collision.Frame) : this.GetRouteRightOffset(collision.Frame);
float num7 = Mathf.Lerp(this.GetStartOffset(collision.StartPosition).x, 0.0f, collision.Distance / 200f);
collision.BaseOffset = num6 + num7;
}
this.CalculateCameraAvoidance(cameraDistance);
}
//摄像机障碍物避免
private void CalculateCameraAvoidance(float cameraDistance)
{
float deltaTime = Time.deltaTime;
for (int index = 0; index < this.collisionList.Count; ++index)
{
ARLaneObject collision = this.collisionList[index];
bool flag1 = collision.StartPosition == this.FollowedRiderId;
float x = Math.Abs(collision.Distance - cameraDistance);
float x2 = 4f;
if (this.NearViewMode && !flag1)
x2 = 5.5f;
if ((double)x > (double)x2)
{
if ((double)collision.LaneCamera > 0.0)
collision.LaneCamera = Mathf.Max(0.0f, collision.LaneCamera - deltaTime);
else if ((double)collision.LaneCamera < 0.0)
collision.LaneCamera = Mathf.Min(0.0f, collision.LaneCamera + deltaTime);
}
else
{
float num1 = VTMath.Lerp(0.0f, 1f, x2, 0.0f, x);
float num2 = collision.Lane * collision.LaneWidth - collision.BaseOffset;
float num3 = 0.75f;
if (this.NearViewMode && !flag1)
{
num2 += num3 / 2f;
num3 *= 1.5f;
}
bool flag2 = (double)collision.LaneCamera < 0.0 || (double)collision.LaneCamera <= 0.0 && (double)num2 < 0.0;
float a1 = (float)(-(double)num2 - (double)num1 * (double)num3) / collision.LaneWidth;
float a2 = (num1 * num3 - num2) / collision.LaneWidth;
if (this.NearViewMode & flag1)
{
float num4 = Mathf.Max(a1 - collision.LaneCamera, -deltaTime);
collision.LaneCamera = Mathf.Min(collision.LaneCamera + num4, -1.401298E-45f);
}
else
collision.LaneCamera = !flag2 ? Mathf.Max(a2, float.Epsilon) : Mathf.Min(a1, -1.401298E-45f);
}
}
}
private void CalculateOvertakingParameters()
{
float deltaTime = Time.deltaTime;
foreach (ARLaneObject laneObject in this.riderObjects.Values)
{
float num1 = laneObject.Speed * deltaTime;
if ((double)num1 == 0.0)
{
laneObject.Curvature = 0.0f;
laneObject.LaneChangingDirection = 0.0f;
}
else
{
float num2 = (this.Route.LeftHanded ? -1f : 1f) * laneObject.DeltaLane * laneObject.LaneWidth * deltaTime;
if ((double)laneObject.LaneCamera != 0.0)
num2 = 0.0f;
float curvature = 0.0f;
if ((double)num1 > 0.0)
{
float num3 = Mathf.Atan(num2 / num1);
curvature = (float)(0.039999999105930328 * (double)VTMath.Lerp(0.0f, 3f, 20f, 1f, laneObject.Speed)) * num3;
}
this.UpdateRiderCurvature(laneObject, curvature, deltaTime);
float angle = -57.29578f * Mathf.Atan(num2 / num1);
this.UpdateLaneChangingDirection(laneObject, angle, deltaTime);
}
}
}
protected void UpdateRiderCurvature(ARLaneObject laneObject, float curvature, float deltaTime)
{
float num = 6f;
laneObject.Curvature = Mathf.Lerp(laneObject.Curvature, curvature, num * deltaTime);
}
protected void UpdateLaneChangingDirection(
ARLaneObject laneObject,
float angle,
float deltaTime)
{
float num = 10f * deltaTime;
laneObject.LaneChangingDirection = Mathf.Clamp(angle, laneObject.LaneChangingDirection - num, laneObject.LaneChangingDirection + num);
}
protected float GetLane(float routeDistance, float modelDistance, int count = -1)
{
if (count == -1)
count = this.collisionList.Count;
float overtakingThreshold = this.GetOvertakingThreshold(routeDistance);
float b = 0.0f;
for (int index = count - 1; index >= 0; --index)
{
ARLaneObject collision = this.collisionList[index];
if ((double)collision.Lane + 1.0 >= (double)b)
{
float collisionParameter = ARLaneObjectsController.GetCollisionParameter(modelDistance, collision.DistanceSort, overtakingThreshold);
if ((double)collisionParameter > 0.0)
b = Mathf.Max(collision.Lane + collisionParameter, b);
}
else
break;
}
return b;
}
protected float GetOvertakingThreshold(float routeDistance)
{
float b = this.OvertakingThreshold;
if (this.AllowStartOrder && (double)routeDistance < 200.0)
b = Mathf.Lerp(1.33f, b, routeDistance / 200f);
return b;
}
private Vector2 GetStartOffset(int atIndex)
{
Vector2 startOffset;
if (this.randomizedStartOffsets.TryGetValue(atIndex, out startOffset))
return startOffset;
startOffset = new Vector2(UnityEngine.Random.Range(-0.15f, 0.15f), UnityEngine.Random.Range(-0.4f, 0.4f));
this.randomizedStartOffsets.Add(atIndex, startOffset);
return startOffset;
}
public float GetModelRouteDistance(int startPosition, float routeDistance)
{
if (!this.AllowStartOrder || (double)routeDistance >= 200.0)
return routeDistance;
float num = Mathf.Lerp((float)((double)(RiderCountInStartRow == 0 ? 0 :(startPosition - 1) / this.RiderCountInStartRow) * 2.2000000476837158 + 6.0) + this.GetStartOffset(startPosition).y, 0.0f, routeDistance / 200f);
return routeDistance + num;
}
//计算碰撞距离
protected static float GetCollisionParameter(
float distSource,
float distOther,
float maxDistance)
{
float x = distSource - distOther;
if ((double)x < 0.0)
x = -x;
if ((double)x < 1.0)
return 1f;
return (double)x > (double)maxDistance ? 0.0f : VTMath.SmoothStep(1f, 1f, maxDistance, 0.0f, x);
}
private float GetRouteLeftOffset(float frame) => this.Route == null ? 0.0f : this.Route.GetLeftSideOffset(frame);
private float GetRouteRightOffset(float frame) => this.Route == null ? 0.0f : this.Route.GetRightSideOffset(frame);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: beab89ef5c7a65d4693d9b8b472bb0d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

120
Assets/AR/ARMeshFactory.cs Normal file
View File

@ -0,0 +1,120 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace Assets.AR
{
public static class ARMeshFactory
{
private static bool IsValidVertex(Vector3 v) => !float.IsNaN(v.x) && !float.IsInfinity(v.x) && !float.IsNaN(v.y) && !float.IsInfinity(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.z);
//创建轨迹
public static GameObject CreateTrajectory(
ARRoute route,
int segment,
float lOffset,
float rOffset,
float margin = float.NaN)
{
int start;
int end;
route.GetSlamSegmentRange(segment, out start, out end);
int num1 = end - start + 1;
int[] indices = new int[(num1 - 1) * 6];
Vector3[] vector3Array1 = new Vector3[num1 * 2];
Vector3 left;
Vector3 right;
ARMeshFactory.CreateVertices(start, route, lOffset, rOffset, out left, out right, margin);
vector3Array1[0] = left;
vector3Array1[1] = right;
int num2 = 2;
int num3 = 0;
for (int frame = start + 1; frame <= end; ++frame)
{
ARMeshFactory.CreateVertices(frame, route, lOffset, rOffset, out left, out right, margin);
if (ARMeshFactory.IsValidVertex(left) && ARMeshFactory.IsValidVertex(right))
{
Vector3[] vector3Array2 = vector3Array1;
int index1 = num2;
int num4 = index1 + 1;
Vector3 vector3_1 = left;
vector3Array2[index1] = vector3_1;
Vector3[] vector3Array3 = vector3Array1;
int index2 = num4;
num2 = index2 + 1;
Vector3 vector3_2 = right;
vector3Array3[index2] = vector3_2;
int[] numArray1 = indices;
int index3 = num3;
int num5 = index3 + 1;
int num6 = num2 - 3;
numArray1[index3] = num6;
int[] numArray2 = indices;
int index4 = num5;
int num7 = index4 + 1;
int num8 = num2 - 4;
numArray2[index4] = num8;
int[] numArray3 = indices;
int index5 = num7;
int num9 = index5 + 1;
int num10 = num2 - 1;
numArray3[index5] = num10;
int[] numArray4 = indices;
int index6 = num9;
int num11 = index6 + 1;
int num12 = num2 - 4;
numArray4[index6] = num12;
int[] numArray5 = indices;
int index7 = num11;
int num13 = index7 + 1;
int num14 = num2 - 2;
numArray5[index7] = num14;
int[] numArray6 = indices;
int index8 = num13;
num3 = index8 + 1;
int num15 = num2 - 1;
numArray6[index8] = num15;
}
}
Mesh mesh = new Mesh();
mesh.vertices = vector3Array1;
mesh.indexFormat = IndexFormat.UInt32;
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
GameObject trajectory = new GameObject(string.Format("Segment {0}", (object)segment), new System.Type[3]
{
typeof (MeshFilter),
typeof (MeshRenderer),
typeof (MeshCollider)
});
trajectory.GetComponent<MeshFilter>().sharedMesh = mesh;
trajectory.GetComponent<MeshCollider>().sharedMesh = trajectory.GetComponent<MeshFilter>().sharedMesh;
return trajectory;
}
private static void CreateVertices(
int frame,
ARRoute route,
float lOffset,
float rOffset,
out Vector3 left,
out Vector3 right,
float margin = float.NaN)
{
Quaternion trajectoryOrientationAt = route.GetTrajectoryOrientationAt(frame);
Vector3 vector3 = route.GetCameraPositionAt(frame) - trajectoryOrientationAt * Vector3.up * route.CameraHeight;
if ((double)lOffset == 0.0)
lOffset = route.GetLeftSideOffset((float)frame);
if (float.IsNaN(margin))
lOffset += route.RouteMargin;
else
lOffset += margin;
left = vector3 + trajectoryOrientationAt * Vector3.left * lOffset;
if ((double)rOffset == 0.0)
rOffset = route.GetRightSideOffset((float)frame);
if (float.IsNaN(margin))
rOffset += route.RouteMargin;
else
rOffset += margin;
right = vector3 - trajectoryOrientationAt * Vector3.left * rOffset;
left.y = right.y = vector3.y;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ed86df267dfdd249bbec364a3c88ac9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

178
Assets/AR/ARObject.cs Normal file
View File

@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.AR
{
public class ARObject : MonoBehaviour
{
public string Hash;
public const int Layer = 9;
public const int TestRidersLayer = 10;
public static float MaxDistanceVisibilityModels = 80f;
public const float VisibilityHidingTime = 0.2f;
public const float VisibilityHidingeRange = 0.5f;
protected VideoPointsSync videoSync { get; set; }
protected ARRoute route { get; set; }
public float frame;
private float lastVisibilityLevel;
public float distance;
private int nextTimeDefIndex;
protected bool useMultilapTransform;
public Vector3 PositionOffset = Vector3.zero;
public Vector3 RotationOffset = Vector3.zero;
public Vector3 Scale = Vector3.one;
private float FrameRate = 29.97f;
public string CustomUrl { get; set; }
public string ArName { get; set; }
public Vector3 CameraPositionOffset { get; set; }
public float Frame => !this.useMultilapTransform ? this.frame : this.frame + this.videoSync.LastVideoFrame;
public float VisibilityLevel { get; protected set; }
public float ManualVisibility { get; set; }
public ARRoute Route
{
get => this.route;
set
{
if (this.route == value)
return;
this.route = value;
this.SetFrame();
}
}
public VideoPointsSync VideoSync
{
get => this.videoSync;
set
{
if (this.videoSync == value)
return;
this.videoSync = value;
this.SetFrame();
}
}
public float Distance
{
get => this.distance;
set
{
if ((double)this.distance == (double)value)
return;
this.distance = value;
this.SetFrame();
}
}
public virtual void UpdateTransform()
{
if (this.Route == null)
return;
Quaternion cameraRotation = this.GetCameraRotation(this.frame);
Vector3 filteredCameraPosition = this.GetFilteredCameraPosition(this.frame);
this.transform.rotation = cameraRotation * Quaternion.Euler(this.RotationOffset);
this.transform.position = filteredCameraPosition + cameraRotation * this.PositionOffset;
this.transform.localScale = this.Scale;
}
public void UpdateOffsets()
{
if (this.Route == null || this.VideoSync == null)
return;
Quaternion quaternion = Quaternion.Inverse(this.GetCameraRotation(this.frame));
Vector3 filteredCameraPosition = this.GetFilteredCameraPosition(this.frame);
this.RotationOffset = (quaternion * this.transform.rotation).eulerAngles;
this.PositionOffset = quaternion * (this.transform.position - filteredCameraPosition);
this.Scale = this.transform.localScale;
}
public void UpdateVisibility(
float videoFrame,
float visibilityRear,
float visibilityFront,
bool multiLap)
{
if ((double)this.ManualVisibility > 0.0)
{
visibilityFront = this.ManualVisibility;
visibilityRear = this.ManualVisibility;
}
float deltaVisibility = Time.deltaTime * 5f;
float a = this.GetVisibilityParameter(this.frame, videoFrame, visibilityRear, visibilityFront, deltaVisibility);
if (multiLap && (double)a <= 0.0)
{
float visibilityParameter = this.GetVisibilityParameter(this.frame + this.videoSync.LastVideoFrame, videoFrame, visibilityRear, visibilityFront, deltaVisibility);
a = Mathf.Max(a, visibilityParameter);
if ((double)a > 0.0)
this.useMultilapTransform = true;
}
else
this.useMultilapTransform = false;
this.VisibilityLevel = a;
this.lastVisibilityLevel = this.VisibilityLevel;
}
protected virtual void Update()
{
if (this.Route == null || this.VideoSync == null)
return;
this.UpdateTransform();
}
protected virtual void Awake()
{
}
protected Quaternion GetCameraRotation(float frame) => this.Route.GetTrajectoryOrientation(this.useMultilapTransform ? frame + this.videoSync.LastVideoFrame : frame);
protected Vector3 GetFilteredCameraPosition(float frame) => this.Route.GetFilteredCameraPosition(this.useMultilapTransform ? frame + this.videoSync.LastVideoFrame : frame) - this.CameraPositionOffset;
private void SetFrame()
{
if (this.Route == null || this.VideoSync == null)
return;
this.frame = this.VideoSync.GetVideoFrameAtDistance(this.Distance);
}
private float GetVisibilityParameter(
float objectFrame,
float videoFrame,
float visibilityRear,
float visibilityFront,
float deltaVisibility)
{
if ((double)objectFrame < (double)videoFrame - (double)visibilityRear)
return 0.0f;
if ((double)visibilityFront <= 0.0)
return 1f;
if ((double)this.ManualVisibility == -1.0)
return Mathf.Clamp(0.0f, this.lastVisibilityLevel - deltaVisibility, this.lastVisibilityLevel + deltaVisibility);
float num1;
if ((double)objectFrame > (double)videoFrame)
{
float num2 = (float)((double)videoFrame + (double)visibilityFront - 0.5 * (double)this.FrameRate);
float num3 = videoFrame + visibilityFront;
num1 = 1f - Mathf.Clamp01((float)(((double)objectFrame - (double)num2) / ((double)num3 - (double)num2)));
}
else
{
float num4 = videoFrame - visibilityRear;
float num5 = (float)((double)videoFrame - (double)visibilityRear + 0.5 * (double)this.FrameRate);
num1 = Mathf.Clamp01((float)(((double)objectFrame - (double)num4) / ((double)num5 - (double)num4)));
}
return Mathf.Clamp(num1, this.lastVisibilityLevel - deltaVisibility, this.lastVisibilityLevel + deltaVisibility);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dbf584e2324021741a949900752a8650
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

34
Assets/AR/ARObjectType.cs Normal file
View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.AR
{
public enum ARObjectType
{
Sign,
Box,
Sphere,
SplitGate,
FinishGate,
Bariccade,
Custom,
}
public enum RiderCameraDistance
{
FirstPerson,
Near,
Middle,
Far,
}
public enum VideoControlMode
{
Front,
AutoPanorama,
Rear,
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a289f05c09632e48b90c9f12837743a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,206 @@
using RenderHeads.Media.AVProVideo;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace Assets.AR
{
public abstract class ARObjectsController : MonoBehaviour
{
public float MaximumVisibilityDistance = 200f;
private readonly Vector3 CameraOriginOffset = Vector3.up * -100f;
protected static readonly Vector3 DefaultObjectPosition = new Vector3(0.0f, 1000f, 0.0f);
protected List<ARObject> arObjects = new List<ARObject>();
protected Material matShadow { get; set; }
protected Material matModelMask;
protected AVProVideoPlayer videoPlayer { get; set; }
protected VideoPointsSync videoSync{ get; set; }
protected Vector3 cameraPositionOffset { get; set; }
private GameObject panoramaObject;
private Material panoramaMaterial;
private Material skyboxMaterialBackup;
protected GameObject trajectoryObject;
private float ambientIntensity;
private GameObject camGo;
protected Dictionary<int, ARObjectsController.Segment> trajectorySegments = new Dictionary<int, ARObjectsController.Segment>();
protected int lapCount = 1;
protected double lapLength;
public bool AR360Version { get; private set; }
public Camera UnityCamera { get; protected set; }
public float FrameIndexDistanceCorrection { get; set; }
public ARRoute Route { get; private set; }
protected float CameraDistance { get; private set; }
public float TargetCameraDistance { get; private set; }
public Camera PanoramaCamera { get; private set; }
public bool PassedPanorama { get; set; }
public bool IsMultilap => this.lapCount > 1;
protected virtual void Awake()
{
this.ambientIntensity = RenderSettings.ambientIntensity;
this.matShadow = Resources.Load<Material>("UI/Material/TransparentPlane");
//this.matModelMask = Resources.Load<Material>("Materials/ModelDepth");
}
protected virtual void SetupCamera()
{
this.camGo = new GameObject("ARCamera");
this.camGo.transform.parent = this.transform;
this.UnityCamera = this.camGo.AddComponent<Camera>();
this.UnityCamera.cullingMask = 512;
this.UnityCamera.clearFlags = CameraClearFlags.Nothing;
this.UnityCamera.depth = 1f;
}
public virtual void SetArRoute(ARRoute route, VideoPointsSync videoSync,AVProVideoPlayer mediaPlayer)
{
videoPlayer = mediaPlayer;
this.Route = route;
this.videoSync = videoSync;
if (this.Route.CameraRotationsRear != null && this.Route.CameraRotationsRear.Length == this.Route.CameraRotations.Length)
{
this.AR360Version = true;
ARObject.MaxDistanceVisibilityModels = 200f;
this.MaximumVisibilityDistance = 500f;
}
else
{
this.AR360Version = false;
ARObject.MaxDistanceVisibilityModels = 80f;
this.MaximumVisibilityDistance = 200f;
}
if (route == null)
return;
foreach (ARObject arObject in this.arObjects)
{
arObject.VideoSync = videoSync;
arObject.Route = route;
}
this.trajectoryObject = new GameObject("TrajectoryMesh");
this.trajectoryObject.transform.parent = this.transform;
this.trajectoryObject.layer = 9;
}
protected virtual void UpdateObjects(
float videoFrame,
float visibilityRear,
float visibilityFront)
{
foreach (ARObject arObject in this.arObjects)
{
arObject.CameraPositionOffset = this.cameraPositionOffset;
if (arObject is ARLaneObject arLaneObject)
arLaneObject.FrameIndexDistanceCorrection = this.FrameIndexDistanceCorrection;
{
arObject.UpdateVisibility(videoFrame, visibilityRear, visibilityFront, this.IsMultilap);
bool flag = this.IsArObjectActive(arObject);
//arObject.gameObject.SetActive(flag); TODO
}
}
}
protected virtual bool IsArObjectActive(ARObject arObject) => (double)arObject.VisibilityLevel > 0.0;
protected virtual Material GetTrajectoryMaterial() => this.matShadow;
protected virtual void Update()
{
if (this.Route == null)
return;
this.arObjects.Clear();
this.arObjects.AddRange(FindObjectsOfType<ARObject>());
float num1 = this.videoPlayer.CurrentFrame - (float)this.Route.VideoFrameOffset;
{
this.cameraPositionOffset = this.Route.GetCameraPosition(num1) - this.CameraOriginOffset;
Camera.main.transform.position = this.CameraOriginOffset;
Camera.main.transform.rotation = this.Route.GetCameraRotation(num1);
this.Route.SetCameraProjection(num1, Camera.main);
}
this.CameraDistance = this.videoSync.GetDistanceForVideoFrame(num1 + this.FrameIndexDistanceCorrection);
float num2 = Mathf.Min(float.MaxValue, this.Route.GetVisibility(num1));
float num3 = num2;
float visibilityRear = 200f;
if ((double)num3 == 0.0)
num3 = 600f;
if ((double)visibilityRear == 0.0)
visibilityRear = 600f;
this.UpdateTrajectory(num1, num3);//更新轨迹
this.UpdateObjects(num1, visibilityRear, num3);//更新骑手等位置
}
//更新当前可见轨迹
private void UpdateTrajectory(float frame, float defaultVisibility)
{
int start;
int end;
this.Route.GetVisibleSlamSegments((int)frame, out start, out end, defaultVisibility);
List<int> intList = new List<int>();
foreach (int key in this.trajectorySegments.Keys)
{
if (key < start || key > end)
intList.Add(key);
}
foreach (int key in intList)
{
UnityEngine.Object.Destroy((UnityEngine.Object)this.trajectorySegments[key].GameObject);
this.trajectorySegments.Remove(key);
}
for (int index = start; index <= end; ++index)
{
if (!this.trajectorySegments.ContainsKey(index))
{
GameObject trajectory = this.CreateTrajectory(index, 0.0f, 0.0f);
ARObjectsController.Segment segment = new ARObjectsController.Segment(trajectory, trajectory.transform.position);
this.trajectorySegments.Add(index, segment);
}
}
foreach (int key in this.trajectorySegments.Keys)
{
ARObjectsController.Segment trajectorySegment = this.trajectorySegments[key];
trajectorySegment.GameObject.transform.position = trajectorySegment.Position - this.cameraPositionOffset;
}
}
//创建轨迹
protected virtual GameObject CreateTrajectory(
int segment,
float lOffset,
float rOffset,
float margin = float.NaN)
{
GameObject trajectory = ARMeshFactory.CreateTrajectory(this.Route, segment, lOffset, rOffset, margin);
trajectory.transform.parent = this.trajectoryObject.transform;
trajectory.layer = 9;
trajectory.GetComponent<MeshRenderer>().shadowCastingMode = ShadowCastingMode.Off;
trajectory.GetComponent<MeshRenderer>().material = this.GetTrajectoryMaterial();
return trajectory;
}
protected Vector3 GetCameraPosition(float frame) => this.Route.GetCameraPosition(frame) - this.cameraPositionOffset;
public class Segment
{
public GameObject GameObject;
public Vector3 Position;
public Segment(GameObject gameObject, Vector3 position)
{
this.GameObject = gameObject;
this.Position = position;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d565e7e3c0027f41836c0210a05072c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

578
Assets/AR/ARRoute.cs Normal file
View File

@ -0,0 +1,578 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Rendering;
namespace Assets
{
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 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.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;
}
}
}

11
Assets/AR/ARRoute.cs.meta Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a1e61467f8f84048b899dc7815c65ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

248
Assets/AR/ARRouteData.cs Normal file
View File

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using UnityEngine;
namespace Assets
{
[Serializable]
public class RouteDetailData
{
public RouteInfoData RouteInfo;
public List<RouteGeometryPointData> Geometry;
public List<RouteVideoPointData> VideoPoints;
public List<RouteDetailSplitData> Splits;
public long Record;
public long UserRecord;
}
public class RouteDetailSplitData
{
private bool lapFinish;
private int lapFinishIndex;
public double Distance;
public string Name;
public bool IsLapFinish => this.lapFinish;
public int LapFinishIndex => !this.IsLapFinish ? -1 : this.lapFinishIndex;
public void SetLapFinish(bool lapFinish, int lapFinishIndex)
{
this.lapFinish = lapFinish;
this.lapFinishIndex = lapFinishIndex;
}
public override bool Equals(object obj)
{
if (obj == null || !this.GetType().Equals(obj.GetType()))
return false;
RouteDetailSplitData routeDetailSplitData = obj as RouteDetailSplitData;
return this.Distance == routeDetailSplitData.Distance && string.Equals(this.Name, routeDetailSplitData.Name);
}
public override int GetHashCode()
{
int hashCode = 23 * 31 + this.Distance.GetHashCode();
if (this.Name != null)
hashCode = hashCode * 31 + this.Name.GetHashCode();
return hashCode;
}
}
public class RouteVideoPointData
{
public double Distance;
public double VideoTime;
}
[Serializable]
public class RouteInfoData
{
private double lapLength;
private double lapUpclimb;
public string Name;
public string CountryCode;
public string VideoScreen;
public string Profile;
public int Version;
public int Rating;
public int RatingCount;
public double Length;
public int Upclimb;
public double MaxSlope;
public double AvgSlope;
public bool IsFavourite;
public string ARFileUrl;
public List<RouteVideoData> Videos;
public bool SuitableForRunning;
public bool SuitableForCycling;
public bool IsMultiLap;
public int LiveSegmentsCount;
public bool HasVideo => this.Videos != null && this.Videos.Count > 0;
public bool IsAr => !string.IsNullOrEmpty(this.ARFileUrl);
public double LapLength => this.lapLength != 0.0 ? this.lapLength : this.Length;
public double LapUpclimb => this.lapUpclimb != 0.0 ? this.lapUpclimb : (double)this.Upclimb;
public void SetLapLength(double lapLength) => this.lapLength = lapLength;
public void SetLapUpclimb(double lapUpclimb) => this.lapUpclimb = lapUpclimb;
}
public class RouteVideoData
{
public const int MobileQuality = 540;
public const int DesktopQuality = 720;
public const int HdQuality = 1080;
public const int QhdQuality = 1440;
public bool IsOFlow;
public int Quality;
public string Url;
public long Size;
public static int[] AllQualitites() => new int[4]
{
540,
720,
1080,
1440
};
public static int[] StreamingQualities() => new int[3]
{
540,
720,
1080
};
}
public class RouteGeometryPointData
{
public double Latitude;
public double Longitude;
public double Distance;
public double Altitude;
}
[Serializable]
public class ARData
{
public ARRouteData Route;
public ARObjectData[] Objects;
public ARPanoramaData[] Panoramas;
public ARPanoramaData[] Panoramas20;
}
[Serializable]
public class ARObjectData
{
[OptionalField]
public string Hash;
public int ObjectTypeId;
public float Distance;
public VectorData PositionOffset;
public VectorData RotationOffset;
public VectorData Scale;
public float ManualVisibility;
public ARObjectTimeTransformData[] TimeData;
public string CustomUrl;
public string ArName;
}
[Serializable]
public class ARPanoramaData
{
public string name;
public string url;
public float frame;
public int visibilityRear;
public int visibilityFront;
public float[] matrix;
}
[Serializable]
public class ARObjectTimeTransformData
{
public int Frame;
public float Distance;
public VectorData PositionOffset;
public VectorData RotationOffset;
public VectorData Scale;
}
[Serializable]
public class ARRouteData
{
public int[] Visibility;
public VectorData[] CameraPositions;
public VectorData[] CameraRotations;
public VectorData[] CameraRotationsRear;
public float[] LightRotationFrames;
public VectorData[] LightRotations;
public float[] ShadowIntensityFrames;
public float[] ShadowIntensities;
public float[] SphericalHarmonics;
public int[] SlamSegments;
public CameraProjectionParameters[] CameraProjectionParameters;
public bool LeftHanded;
public int VideoFrameOffset;
public int VideoFrameOffsetMac = -1;
public float CameraHeight;
public float RiderScale = 1f;
public int[] LeftSideOffsetFrames;
public float[] LeftSideOffsets;
public int[] RightSideOffsetFrames;
public float[] RightSideOffsets;
}
public class VectorData
{
public float x;
public float y;
public float z;
public Vector3 ToUnityVector() => new Vector3(this.x, this.y, this.z);
public VectorData()
{
}
public VectorData(Vector3 unityVector)
{
this.x = unityVector.x;
this.y = unityVector.y;
this.z = unityVector.z;
}
}
[Serializable]
public class CameraProjectionParameters
{
public float alpha;
public float beta;
public float cx;
public float cy;
public CameraProjectionParameters Clone() => new CameraProjectionParameters()
{
alpha = this.alpha,
beta = this.beta,
cx = this.cx,
cy = this.cy
};
public static CameraProjectionParameters Lerp(
CameraProjectionParameters a,
CameraProjectionParameters b,
float t)
{
return new CameraProjectionParameters()
{
alpha = Mathf.Lerp(a.alpha, b.alpha, t),
beta = Mathf.Lerp(a.beta, b.beta, t),
cx = Mathf.Lerp(a.cx, b.cx, t),
cy = Mathf.Lerp(a.cy, b.cy, t)
};
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4aaeffc1df7bde4880cda54a3cfaf61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,283 @@
using RenderHeads.Media.AVProVideo;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace Assets.AR
{
public class AVProVideoPlayer : MonoBehaviour
{
private const float DefaultFps = 29.97f;
public MediaPlayer videoPlayer;
private Vector2Int videoResolution = Vector2Int.zero;
private Vector2Int textureResolution = Vector2Int.zero;
private int displacement;
private bool interpolate;
private bool useFlow;
private bool pausedByTrainingPause = false;
private bool pausedByPlaybackSpeed;
private RenderTexture currentTexture;
private RenderTexture previousTexture;
private bool switchBuffer = true;
private bool canSwitchBuffer = true;
private int previousTextureFrameCount;
private float previousVideoTimeMs;
private float shift;
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
private float localCurrentFrame;
private bool intendedRear;
private void Awake()
{
//this.videoPlayer = this.gameObject.AddComponent<MediaPlayer>();
//this.videoPlayer.PlatformOptionsAndroid.videoApi = RenderHeads.Media.AVProVideo.Android.VideoApi.MediaPlayer;
//this.videoPlayer.PlatformOptionsAndroid.preferSoftwareDecoder = true;
//GameObject primitive = GameObject.CreatePrimitive(PrimitiveType.Quad);
//primitive.name = "VideoMesh";
//primitive.layer = 9;
//UnityEngine.Object.Destroy((UnityEngine.Object)primitive.GetComponent<MeshCollider>());
//this.VideoRenderer = (Renderer)primitive.GetComponent<MeshRenderer>();
//primitive.transform.parent = this.transform;
//this.VideoRenderer.material = new Material(Shader.Find("Rouvy/FrameInterpolation"));
}
private void OnDisable() => this.ReleaseRenderTextures();
private void OnDestroy() => UnityEngine.Object.Destroy((UnityEngine.Object)this.VideoRenderer?.material);
public bool Initialized => true;
public float CurrentFrame => (double)this.localCurrentFrame >= (double)this.StreamFrameCount ? this.localCurrentFrame - (float)this.StreamFrameCount : this.localCurrentFrame;
public bool IntendedRear
{
get => this.intendedRear;
set
{
if (this.intendedRear == value)
return;
this.intendedRear = value;
this.Seek((long)(int)this.CurrentFrame, true);
}
}
public bool IsRear => (double)this.localCurrentFrame >= (double)this.StreamFrameCount;
public int StreamFrameCount { get; set; }
public void UpdateCurrentFrame()
{
this.localCurrentFrame = (float)(this.videoPlayer.Control.GetCurrentTime() * 29.97f);
}
public float FrameRate { get; private set; } = 29.97f;
public bool HasOpticalFlow { get; private set; }
public float PlaybackSpeed => this.videoPlayer.Control.GetPlaybackRate();
public Renderer VideoRenderer { get; private set; }
public bool IsPaused => this.pausedByTrainingPause;
public bool IsSeeking => this.videoPlayer.Control.IsSeeking();
private bool Interpolate
{
get => this.interpolate;
set
{
if (this.interpolate == value)
return;
this.interpolate = value;
this.SetShaderKeywords();
}
}
private bool UseFlow
{
get => this.useFlow;
set
{
if (this.useFlow == value)
return;
this.useFlow = value;
this.SetShaderKeywords();
}
}
public void OpenVideo(string videoUrl, int streamFramesCount)
{
this.StreamFrameCount = streamFramesCount;
this.StopVideo();
//this.videoPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.AbsolutePathOrURL, videoUrl);
}
public void Pause()
{
this.videoPlayer.Pause();
this.pausedByTrainingPause = true;
}
public void Resume()
{
if (!this.pausedByPlaybackSpeed)
this.videoPlayer.Play();
this.pausedByTrainingPause = false;
}
public void StopVideo()
{
this.videoPlayer.Stop();
this.videoPlayer.CloseMedia();
this.ReleaseRenderTextures();
}
public bool SetPlaybackSpeed(float playbackSpeed)
{
if (this.IsSeeking || this.IsPaused || DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds < 1.0)
return false;
if ((double)playbackSpeed == 0.0 && !this.pausedByPlaybackSpeed)
{
this.pausedByPlaybackSpeed = true;
this.videoPlayer.Pause();
}
else if ((double)playbackSpeed > 0.0 && this.pausedByPlaybackSpeed)
{
this.pausedByPlaybackSpeed = false;
if (!this.pausedByTrainingPause)
this.videoPlayer.Play();
}
this.videoPlayer.PlaybackRate = playbackSpeed;
this.lastPlaybackSpeedChange = DateTime.UtcNow;
return true;
}
public bool Seek(long frame, bool force = false)
{
if (this.IntendedRear)
frame += (long)this.StreamFrameCount;
if (!this.Initialized || this.IsSeeking && !force)
return false;
this.videoPlayer.Control.SeekToFrame((int)frame);
return true;
}
private void Initialize()
{
if (this.Initialized)
return;
this.VideoPrepareAction();
}
private void LateUpdate()
{
if (!this.Initialized)
{
this.Initialize();
}
else
{
this.previousVideoTimeMs = (float)this.videoPlayer.Control.GetCurrentTime();
if (!this.pausedByTrainingPause && this.videoPlayer.Control.IsPaused() && !this.pausedByPlaybackSpeed)
this.videoPlayer.Play();
if (!this.pausedByTrainingPause && !this.pausedByPlaybackSpeed || this.videoPlayer.Control.IsPaused())
return;
this.videoPlayer.Pause();
}
}
private void CheckAndPauseByPlaybackSpeed()
{
if ((double)this.videoPlayer.Control.GetPlaybackRate() != 0.0 || this.pausedByPlaybackSpeed)
return;
this.pausedByPlaybackSpeed = true;
this.videoPlayer.Pause();
}
private void VideoPrepareAction()
{
this.FrameRate = 29.97f;
this.videoPlayer.Control.SetTextureProperties(anisoLevel: 0);
if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1688) < 10)
{
this.videoResolution = new Vector2Int(1280, 720);
this.displacement = 40;
this.HasOpticalFlow = true;
}
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 2528) < 10)
{
this.videoResolution = new Vector2Int(1920, 1080);
this.displacement = 64;
this.HasOpticalFlow = true;
}
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 3372) < 10)
{
this.videoResolution = new Vector2Int(2560, 1440);
this.displacement = 128;
this.HasOpticalFlow = true;
}
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1264) < 10)
{
this.videoResolution = new Vector2Int(960, 540);
this.HasOpticalFlow = true;
this.displacement = 32;
}
else
{
this.videoResolution = new Vector2Int(this.videoPlayer.Info.GetVideoWidth(), this.videoPlayer.Info.GetVideoHeight());
this.HasOpticalFlow = false;
}
this.Interpolate = this.UseFlow = this.HasOpticalFlow;
this.videoPlayer.Play();
if (!this.pausedByTrainingPause)
return;
this.videoPlayer.Pause();
}
private void ReleaseRenderTextures()
{
if ((UnityEngine.Object)this.currentTexture != (UnityEngine.Object)null)
{
this.currentTexture.Release();
this.currentTexture = (RenderTexture)null;
}
if (!((UnityEngine.Object)this.previousTexture != (UnityEngine.Object)null))
return;
this.previousTexture.Release();
this.previousTexture = (RenderTexture)null;
}
private void SetShaderKeywords()
{
if (this.Interpolate)
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
else
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
if (this.UseFlow && this.videoResolution != this.textureResolution)
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
else
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
private struct ShaderID
{
public static int previousFrame = Shader.PropertyToID("_PreviousFrame");
public static int currentFrame = Shader.PropertyToID("_CurrentFrame");
public static int displacement = Shader.PropertyToID("_MaxDisplacement");
public static int shift = Shader.PropertyToID("_Shift");
public static int flip = Shader.PropertyToID("_Flip");
public static int videoResolution = Shader.PropertyToID("_VideoResolution");
public static int textureResolution = Shader.PropertyToID("_TextureResolution");
public static int screenResolution = Shader.PropertyToID("_ScreenResolution");
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
private struct ShaderKeyword
{
public static string interpolate = "INTERPOLATE";
public static string useFlow = "USE_FLOW";
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5609ccb62c92e784e873a76e89abc3aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

80
Assets/AR/BaseRenderer.cs Normal file
View File

@ -0,0 +1,80 @@
using System.Runtime.InteropServices;
using UnityEngine;
namespace Assets.AR
{
public abstract class BaseRenderer : ARLaneObject
{
protected Animator animator;
protected Shader shaderNormal;
protected Shader shaderAplha;
protected MaterialPropertyBlock materialPropertyBlock;
private bool paused = true;
public bool Male { get; protected set; }
public Texture2D JerseyTexture { get; set; }
public Color ColorSkin { get; set; }
public Color ColorUser { get; set; }
public bool Paused
{
get => this.paused;
set
{
if (value == this.paused)
return;
this.paused = value;
this.OnPause(this.paused);
}
}
protected override void Awake()
{
base.Awake();
this.animator = this.GetComponent<Animator>();
//this.shaderAplha = Shader.Find("Rouvy/RiderShaderOneAlpha");
//this.shaderNormal = Shader.Find("Rouvy/RiderShaderOne");
this.materialPropertyBlock = new MaterialPropertyBlock();
}
public void Initialize(bool male) => this.Male = male;
protected virtual void Start()
{
this.SetupModels();
this.SetLayerRecursively(this.gameObject, 9);
this.animator.avatar = (Avatar)null;
}
protected override void Update()
{
base.Update();
}
protected abstract void SetupModels();
protected virtual void OnPause(bool paused)
{
}
protected void SetLayerRecursively(GameObject obj, int layer)
{
obj.layer = layer;
foreach (Component component in obj.transform)
this.SetLayerRecursively(component.gameObject, layer);
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct ShaderID
{
public static int mainTex = Shader.PropertyToID("_MainTex");
public static int opacity = Shader.PropertyToID("_Opacity");
public static int colorCustom = Shader.PropertyToID("_ColorCustom");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f542667dd24fe84e87fcb325e8535cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

34
Assets/AR/Geometry.cs Normal file
View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace Assets
{
public static class Geometry
{
public static bool CircleCenter(Vector3 aP0, Vector3 aP1, Vector3 aP2, out Vector3 center)
{
Vector3 lhs = aP1 - aP0;
Vector3 vector3 = aP2 - aP0;
Vector3 rhs = Vector3.Cross(lhs, vector3);
if ((double)rhs.sqrMagnitude < 9.9999998245167E-15)
{
center = Vector3.zero;
return false;
}
rhs.Normalize();
if ((double)rhs.sqrMagnitude < 9.9999998245167E-15)
{
center = Vector3.zero;
return false;
}
Vector3 normalized1 = Vector3.Cross(lhs, rhs).normalized;
Vector3 normalized2 = Vector3.Cross(vector3, rhs).normalized;
Vector3 from = (lhs - vector3) * 0.5f;
float num1 = Vector3.Angle(normalized1, normalized2);
float num2 = Vector3.Angle(from, normalized1);
float num3 = from.magnitude * Mathf.Sin(num2 * ((float)Math.PI / 180f)) / Mathf.Sin(num1 * ((float)Math.PI / 180f));
center = (double)Vector3.Dot(lhs, aP2 - aP1) <= 0.0 ? aP0 + vector3 * 0.5f + normalized2 * num3 : aP0 + vector3 * 0.5f - normalized2 * num3;
return !float.IsInfinity(center.x) && !float.IsNaN(center.x) && !float.IsInfinity(center.y) && !float.IsNaN(center.y) && !float.IsInfinity(center.z) && !float.IsNaN(center.z);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 192a6b01fc9e2ec44b90f5d19c277ca4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

214
Assets/AR/RiderRenderer.cs Normal file
View File

@ -0,0 +1,214 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace Assets.AR
{
public class RiderRenderer : BaseRenderer
{
private const int PowerWindowSize = 10;
private const float Circumference = 2.13097382f;
private const double SpeedLimitForWheelRotation = 10.0;
private const double MaxAngularSpeed = 1689.3684817282528;
private const double MaxAnglePerFrame = 6.5;
private const float AfterFinishRideInSec = 5f;
public const float MaxLeanAngle = 35f;
public const float MaxLeanAngleChange = 60f;
public const float MaxTurnAngle = 6f;
public const float MaxTurnAngleChange = 10f;
public const float LeanAngleSoftStageLength = 15f;
private float lastSpeed = 1f;
private bool lastPauseState;
private int lastDifficultyLevel;
private float lastVisibilitylevel = -1f;
private float afterFinishTime;
private float afterFinishFrame;
private float finishPassSpeed;
private float afterFinishOffsetZ;
private float lastDiffLevelChange = float.MinValue;
private float[] powerWindow = new float[10];
private float lastPowerWinWrite;
private int lastPowerWinIndex;
private float PowerWinSum;
private float lastPowerPeak = float.MinValue;
private int powerPeakSum;
private Transform wheelFront;
private Transform wheelRear;
private float lookTime;
private bool lockIdleAnimations;
public float Cadence { get; set; }
public int DifficultyLevel { get; set; }
public float Power { get; set; }
public float Weight { get; set; }
public float Slope { get; set; }
public Texture2D HelmTexture { get; set; }
public Texture2D BikeTexture { get; set; }
public bool WinAnimation { get; set; }
public bool TimeTrialBike { get; private set; }
public GameObject BasicShadowRenderer { get; set; }
public bool LockIdleAnimations
{
get => this.lockIdleAnimations;
set
{
if (value == this.lockIdleAnimations)
return;
this.lockIdleAnimations = value;
}
}
protected override void Awake()
{
base.Awake();
}
public void Initialize(bool male, bool timeTrialBike)
{
this.Initialize(male);
this.TimeTrialBike = timeTrialBike;
}
private void OnEnable()
{
if ((UnityEngine.Object)this.animator != (UnityEngine.Object)null)
{
}
if (!this.LockIdleAnimations)
return;
}
protected override void Start()
{
base.Start();
this.PlanNextLook();
}
protected override void Update()
{
if (this.route == null)
return;
this.UpdateDiffciulityLevel();
base.Update();
float num = this.Speed;
bool flag = this.Paused;
if (this.IsAtFinish)
{
if ((double)this.afterFinishTime < 5.0)
{
this.ManualVisibility = 1000f;
float videoSpeedAtDistance = this.videoSync.GetVideoSpeedAtDistance(this.Distance - 5f);
if ((double)this.afterFinishFrame == 0.0 && (double)this.afterFinishOffsetZ == 0.0)
{
this.finishPassSpeed = (double)this.lastSpeed > 0.0 ? this.lastSpeed : 10f;
}
flag = false;
this.afterFinishTime += Time.deltaTime;
this.afterFinishTime = Math.Min(5f, this.afterFinishTime);
num = Mathf.Lerp(this.finishPassSpeed, 0.0f, this.afterFinishTime / 5f);
//this.afterFinishFrame += num / videoSpeedAtDistance * Time.deltaTime * this.VideoPlayer.FrameRate;
this.frame = Math.Min((float)(this.route.CameraPositions.Length - 1), this.videoSync.GetVideoFrameAtDistance(this.Distance) + this.afterFinishFrame);
if ((double)this.frame == (double)(this.route.CameraPositions.Length - 1))
this.afterFinishOffsetZ += num * Time.deltaTime;
}
else
{
this.afterFinishTime += Time.deltaTime;
num = 0.0f;
if ((double)this.afterFinishTime > 15.0)
this.ManualVisibility = -1f;
else
this.ManualVisibility = 1000f;
}
this.PositionOffset.z = this.afterFinishOffsetZ;
this.transform.localScale = Vector3.one * this.route.RiderScale;
this.UpdateTransform();
}
else
{
this.transform.localScale = Vector3.one * this.route.RiderScale;
if (flag)
num = 0.0f;
this.ManualVisibility = 0.0f;
this.afterFinishTime = 0.0f;
this.afterFinishFrame = 0.0f;
this.afterFinishOffsetZ = 0.0f;
this.PositionOffset.z = 0.0f;
}
if (flag != this.lastPauseState)
{
this.lastPauseState = flag;
}
if ((double)this.lastSpeed != (double)num)
{
this.lastSpeed = num;
}
if ((double)this.lastSpeed > 0.0 && this.lastDifficultyLevel != this.DifficultyLevel && !this.lastPauseState && (double)Math.Abs(Time.time - this.lastDiffLevelChange) > 2.0)
{
this.lastDifficultyLevel = this.DifficultyLevel;
this.lastDiffLevelChange = Time.time;
}
if ((double)this.lastVisibilitylevel == (double)this.VisibilityLevel)
return;
this.lastVisibilitylevel = this.VisibilityLevel;
}
private void FixedUpdate()
{
//if (this.Paused || (double)this.Speed <= 0.0)
// return;
//float angle = (float)VTMath.Clamp(VTMath.Lerp(0.0, 0.0, 1689.3684817282528, 6.5, 360.0 * ((double)this.Speed < 10.0 ? (double)this.Speed : 2.3463451135114624)), 0.0, 6.5);
//this.wheelFront.transform.Rotate(Vector3.right, angle);
//this.wheelRear.transform.Rotate(Vector3.right, angle);
}
protected override void SetupModels()
{
}
private void PlanNextLook()
{
}
private void UpdateDiffciulityLevel()
{
float num = this.PowerWinSum / 10f;
if ((double)Math.Abs(Time.time - this.lastPowerWinWrite) >= 1.0)
{
++this.lastPowerWinIndex;
this.lastPowerWinIndex %= 10;
this.PowerWinSum -= this.powerWindow[this.lastPowerWinIndex];
this.powerWindow[this.lastPowerWinIndex] = this.Power;
this.PowerWinSum += this.Power;
this.lastPowerWinWrite = Time.time;
num = this.PowerWinSum / 10f;
if ((double)this.Power > (double)num * 1.2000000476837158 && (double)this.Power / (double)this.Weight > 2.0)
++this.powerPeakSum;
else
this.powerPeakSum = 0;
}
if ((double)this.Power / (double)this.Weight > 8.0 || this.powerPeakSum > 2 || (double)this.Power > (double)num * 3.0 && (double)this.Power / (double)this.Weight > 2.0)
this.lastPowerPeak = Time.time;
if ((double)Math.Abs(Time.time - this.lastPowerPeak) < 2.0)
this.DifficultyLevel = 2;
else if ((double)this.Power / (double)this.Weight > 2.0)
this.DifficultyLevel = 1;
else
this.DifficultyLevel = 0;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a779f3247875ef947ab87e8093f5bb39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

367
Assets/AR/TestPlayer.cs Normal file
View File

@ -0,0 +1,367 @@
using Assets.AR;
using DG.Tweening;
using RenderHeads.Media.AVProVideo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Assets.Scripts.Scenes.VideoRide
{
public class TestPlayer : ARLaneObjectsController
{
protected Transform LightTrans { get; set; }
public MediaPlayer mediaPlayer;
public Transform Player;
private ARData aRData;
private RouteDetailData detail;
private VideoPointsSync videoPointsSync;
private int index = 1;
private readonly List<ARLaneObject> collisionList = new List<ARLaneObject>();
///private Dictionary<int, IRouteRider> riders = new Dictionary<int, IRouteRider>();
VideoPlayerControl VideoPlayerControl;
ARLaneObject[] rides;
public ARLaneObject mainObject;
private Light arLight;
private Light arBackLight;
protected override void Start()
{
base.Start();
var txt = Resources.Load<TextAsset>("UI/88019").text;
var route = Resources.Load<TextAsset>("UI/route-88019").text;
aRData = Newtonsoft.Json.JsonConvert.DeserializeObject<ARData>(txt);
detail = Newtonsoft.Json.JsonConvert.DeserializeObject<RouteDetailData>(route);
videoPointsSync = new VideoPointsSync(detail.VideoPoints.Select(c => new VideoPoint()
{
Distance = (float)c.Distance,
Time = (float)c.VideoTime
}));
videoSync = videoPointsSync;
this.VideoPlayerControl = new VideoPlayerControl();
this.VideoPlayerControl.VideoSyncSource = videoSync;
this.videoPlayer = new AVProVideoPlayer();
this.videoPlayer.videoPlayer = mediaPlayer;
SetArRoute(new ARRoute(aRData.Route), videoSync, videoPlayer);
this.VideoPlayerControl.VideoFrameOffset = this.Route.VideoFrameOffset;
this.VideoPlayerControl.Route = Route;
this.VideoPlayerControl.SetVideoPlayer(videoPlayer);
rides = FindObjectsOfType<ARLaneObject>();
CreateBackLight();
}
private void CreateBackLight()
{
GameObject gameObject2 = new GameObject("ARBackLight");
gameObject2.layer = this.gameObject.layer;
gameObject2.transform.SetParent(this.transform);
this.arBackLight = gameObject2.AddComponent<Light>();
this.arBackLight.type = LightType.Directional;
this.arBackLight.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
this.arBackLight.shadows = LightShadows.None;
this.arBackLight.intensity = 0.5f;
this.arBackLight.cullingMask = 512;
}
#if UNITY_EDITOR
float timers = 0f;
double weight = 70;
double bikeWeight = 20;
private void Update()
{
timers -= Time.deltaTime;
while (timers < 0)
{
foreach (var item in rides)
{
item.Speed = (float)(Assets.Scenes.Ride.Scripts.Helper.CalculateSpeed(0, 0, item.TestPower, weight, bikeWeight) / 3.6d);
item.Distance += item.Speed;
item.RouteDistance = item.Distance;
item.Route = Route;
item.VideoSync = videoPointsSync;
if (!this.riderObjects.ContainsKey(item.GetInstanceID()))
this.riderObjects.Add(item.GetInstanceID(), item);
}
timers += 1f;
}
this.FollowedRiderId = 1;
this.UpdateCameraFollowDistance();
VideoPlayerControl.UpdateVideoPlaybackSpeed(mainObject.Speed, mainObject.distance-this.CameraDistance);
this.FrameIndexDistanceCorrection = this.VideoPlayerControl.FrameIndexDistanceCorrection;
base.Update();
this.UpdateRidersVisibility();
this.UpdateRidersLean();
if (Input.GetKeyDown(KeyCode.F))
this.SetVideoControlMode(VideoControlMode.Front);
if (Input.GetKeyDown(KeyCode.P))
this.SetVideoControlMode(VideoControlMode.AutoPanorama);
if (!Input.GetKeyDown(KeyCode.B))
return;
this.SetVideoControlMode(VideoControlMode.Rear);
}
private IEnumerator PlayPosition(ARLaneObject aRLaneObject,double prePos, double offset)
{
float t = 0;
while (t <= 1)
{
t += Time.deltaTime * 5f;
double result = prePos + offset * t;
aRLaneObject.distance = (float)result;
aRLaneObject.RouteDistance = (float)result ;
yield return null;
}
}
public VideoControlMode VideoControlMode { get; private set; }
private float autoCameraSwitchTimeCounter = 80f;
public void SetVideoControlMode(VideoControlMode mode)
{
if (mode == this.VideoControlMode)
return;
if (!this.AR360Version)
mode = VideoControlMode.Front;
this.VideoControlMode = mode;
this.autoCameraSwitchTimeCounter = 80f;
if (mode == VideoControlMode.AutoPanorama)
return;
this.videoPlayer.IntendedRear = mode == VideoControlMode.Rear;
}
public RiderCameraDistance RiderCameraDistance { get; set; }
//更新摄像机的位置
private void UpdateCameraFollowDistance()
{
this.RiderCameraDistance = RiderCameraDistance.Near;
this.NearViewMode = this.RiderCameraDistance == RiderCameraDistance.Near;
float cameraFollowDistance = GetCameraFollowDistance(this.RiderCameraDistance);
this.VideoPlayerControl.CameraFollowDistance = this.videoPlayer.IsRear ? cameraFollowDistance * -1f : cameraFollowDistance;
}
protected override bool IsArObjectActive(ARObject arObject)
{
bool flag = base.IsArObjectActive(arObject);
if ((UnityEngine.Object)arObject != (UnityEngine.Object)this.mainObject)
return flag;
if ((double)this.VideoPlayerControl.CameraFollowDistance > 0.0 || this.AR360Version)
return flag;
return flag && (double)this.VideoPlayerControl.CameraDistanceError > 5.0;
}
//获取摄像机的位置
public static float GetCameraFollowDistance(RiderCameraDistance distance)
{
switch (distance)
{
case RiderCameraDistance.FirstPerson:
return 0.0f;
case RiderCameraDistance.Near:
return 1.5f;
case RiderCameraDistance.Middle:
return 5f;
case RiderCameraDistance.Far:
return 10f;
default:
throw new ArgumentException("Unknown rider's camera distance.");
}
}
private void UpdateRidersVisibility()
{
//if (!this.videoPlayer.Initialized)
// return;
//this.UpdateVisibleRiders();
////删除当前道路上应该消失的骑手
//foreach (int num in this.riderObjects.Keys.ToArray<int>())
//{
// if (!this.visibleRiders.ContainsKey(num))
// {
// ARLaneObject riderObject = this.riderObjects[num];
// if (!riderObject.IsAtFinish || (double)riderObject.VisibilityLevel <= 0.0)
// {
// this.DestroyRider(num);
// this.DestroyRiderTitle(num);
// }
// }
//}
////新增应该显示的骑手
//foreach (TrainingARController.VisibleRiderItem visibleRiderItem in this.visibleRiders.Values)
//{
// IRouteRider rider = visibleRiderItem.Rider;
// bool showModel = visibleRiderItem.ShowModel;
// ARLaneObject arLaneObject;
// //二次检查
// if (this.riderObjects.TryGetValue(rider.Id, out arLaneObject))
// {
// if (arLaneObject is BaseRenderer)
// {
// if (!showModel)
// {
// float lane = arLaneObject.Lane;
// this.DestroyRider(rider.Id);
// this.CreateRiderObject(rider, lane);
// }
// }
// else if (showModel)
// {
// float lane = arLaneObject.Lane;
// this.DestroyRider(rider.Id);
// this.CreateRiderModel(rider, lane);
// }
// }
// else
// {
// if (showModel)
// this.CreateRiderModel(rider, visibleRiderItem.Lane);
// else
// this.CreateRiderObject(rider, visibleRiderItem.Lane);
// this.CreateRiderTitleObject(rider);
// }
//}
}
//更新骑手的偏移角度
private void UpdateRidersLean()
{
foreach (ARLaneObject riderObject in this.riderObjects.Values)
{
float num1 = this.Route.GetTrajectoryCurvature(riderObject.Frame) + riderObject.Curvature;
float z1;
if ((double)num1 == 0.0)
{
z1 = 0.0f;
}
else
{
double speed = riderObject.Speed;
float f = 57.29578f * Mathf.Atan((float)(speed * speed * (double)num1 / 9.81));
float num2 = (double)f >= 0.0 ? 1f : -1f;
float num3 = Mathf.Abs(f);
if ((double)num3 > 20.0)
f = (float)((double)Mathf.Atan((float)(((double)num3 - 20.0) / 10.5)) * 10.5 + 20.0) * num2;
float num4 = Mathf.Clamp(f, -35f, 35f);
float z2 = riderObject.Lean.z;
z1 = Mathf.Clamp(num4, z2 - 60f * Time.deltaTime, z2 + 60f * Time.deltaTime);
}
float y = Mathf.Clamp(riderObject.LaneChangingDirection, -6f, 6f);
riderObject.Lean = new Vector3(0.0f, y, z1);
}
}
DateTime lastPlaybackSpeedChange = DateTime.UtcNow;
bool pausedByPlaybackSpeed = false;
bool pausedByTrainingPause = false;
float frame = 0f;
public bool SetPlaybackSpeed(float playbackSpeed)
{
if (this.mediaPlayer.Control.IsSeeking() || DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds < 1.0)
return false;
if ((double)playbackSpeed == 0.0 && !this.pausedByPlaybackSpeed)
{
this.pausedByPlaybackSpeed = true;
this.mediaPlayer.Pause();
}
else if ((double)playbackSpeed > 0.0 && this.pausedByPlaybackSpeed)
{
this.pausedByPlaybackSpeed = false;
if (!this.pausedByTrainingPause)
this.mediaPlayer.Play();
}
this.mediaPlayer.Control.SetPlaybackRate(playbackSpeed);
this.lastPlaybackSpeedChange = DateTime.UtcNow;
mediaPlayer.Play();
return true;
}
#endif
//人物状态
private string ConfigPath = Application.streamingAssetsPath + "/newdirection.txt";
public const int HERO_UP = 0;
public const int HERO_RIGHT = 1;
public const int HERO_DOWN = 2;
public const int HERO_LEFT = 3;
public const int UP = 4;
public const int DOWN = 5;
private Vector3 rotation = Vector3.zero;
private void keyBordControl()
{
#region
var zdelta = 0.05f;
var delta = 0.2f;
if (Input.GetKey(KeyCode.W))
{
//mediaPlayer.Play();
//mediaPlayer.PlaybackRate = 1f;
var z = transform.position.z + zdelta;
//transform.DOMoveZ(z, 0);
}
if (Input.GetKey(KeyCode.A))
{
mediaPlayer.PlaybackRate = 1f;
mediaPlayer.Play();
var z = transform.position.x - zdelta;
//transform.DOMoveX(z, 0);
}
if (Input.GetKey(KeyCode.D))
{
mediaPlayer.PlaybackRate = 1f;
mediaPlayer.Play();
var z = transform.position.x + zdelta;
//transform.DOMoveX(z, 0);
}
if (Input.GetKey(KeyCode.S))
{
mediaPlayer.PlaybackRate = 1f;
mediaPlayer.Play();
var z = transform.position.z - zdelta;
//transform.DOMoveZ(z, 0);
}
//控制人物方向
if (Input.GetKey(KeyCode.Q))
{
rotation.y -= delta;
transform.DORotate(rotation, 0);
Camera.main.transform.DORotate(rotation, 0);
}
if (Input.GetKey(KeyCode.E))
{
rotation.y += delta;
transform.DORotate(rotation, 0);
Camera.main.transform.DORotate(rotation, 0);
}
//控制人物左右倾斜
if (Input.GetKey(KeyCode.J))
{
rotation.z += zdelta;
transform.DORotate(rotation, 0);
}
if (Input.GetKey(KeyCode.K))
{
rotation.z -= zdelta;
transform.DORotate(rotation, 0);
}
if (Input.GetKey(KeyCode.UpArrow))
{
var z = transform.position.y + zdelta;
transform.DOMoveY(z, 0);
}
if (Input.GetKey(KeyCode.DownArrow))
{
var z = transform.position.y - zdelta;
transform.DOMoveY(z, 0);
}
#endregion
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 523f7d25735c76b4ea28ecc390829ed7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

131
Assets/AR/VTMath.cs Normal file
View File

@ -0,0 +1,131 @@
using System;
using UnityEngine;
namespace Assets
{
public static class VTMath
{
public const double Deg2Rad = 0.017453292519943295;
public const double Rad2Deg = 57.295779513082323;
public static int Clamp(int value, int min, int max)
{
if (value < min)
return min;
return value <= max ? value : max;
}
public static double Clamp(double value, double min, double max)
{
if (value < min)
return min;
return value <= max ? value : max;
}
public static float Clamp(float value, float min, float max)
{
if ((double)value < (double)min)
return min;
return (double)value <= (double)max ? value : max;
}
public static float Clamp01(float value) => VTMath.Clamp(value, 0.0f, 1f);
public static double Clamp01(double value) => VTMath.Clamp(value, 0.0, 1.0);
public static bool InBounds(double value, double min, double max) => min <= value && value <= max;
public static bool InBounds(int value, int min, int max) => min <= value && value <= max;
public static double Lerp(double x1, double y1, double x2, double y2, double x)
{
double t = x1 != x2 ? VTMath.InverseLerp(x1, x2, x) : 0.5;
return VTMath.Lerp(y1, y2, t);
}
public static float Lerp(float x1, float y1, float x2, float y2, float x)
{
float t = (double)x1 != (double)x2 ? VTMath.InverseLerp(x1, x2, x) : 0.5f;
return VTMath.Lerp(y1, y2, t);
}
public static double Lerp(double a, double b, double t) => (1.0 - t) * a + t * b;
public static float Lerp(float a, float b, float t) => (float)((1.0 - (double)t) * (double)a + (double)t * (double)b);
public static double InverseLerp(double a, double b, double value) => a != b ? (value - a) / (b - a) : 0.0;
public static float InverseLerp(float a, float b, float value) => (double)a != (double)b ? (float)(((double)value - (double)a) / ((double)b - (double)a)) : 0.0f;
public static double SmoothStep(double x) => x * x * (3.0 - 2.0 * x);
public static float SmoothStep(float x) => (float)((double)x * (double)x * (3.0 - 2.0 * (double)x));
public static double SmoothStep(double a, double b, double t) => VTMath.Lerp(a, b, VTMath.SmoothStep(t));
public static float SmoothStep(float a, float b, float t) => VTMath.Lerp(a, b, VTMath.SmoothStep(t));
public static double SmoothStep(double x1, double y1, double x2, double y2, double x)
{
double t = x1 != x2 ? VTMath.InverseLerp(x1, x2, x) : 0.5;
return VTMath.SmoothStep(y1, y2, t);
}
public static float SmoothStep(float x1, float y1, float x2, float y2, float x)
{
float t = (double)x1 != (double)x2 ? VTMath.InverseLerp(x1, x2, x) : 0.5f;
return VTMath.SmoothStep(y1, y2, t);
}
public static double InverseSmoothStep(double a, double b, double value) => VTMath.InverseSmoothStep(VTMath.InverseLerp(a, b, value));
public static double InverseSmoothStep(double x)
{
x = 1.0 - 2.0 * x;
return 0.5 - Math.Sin(Math.Asin(x) / 3.0);
}
public static double SmoothStepDerivative(double x) => 6.0 * x * (1.0 - x);
public static double SmoothStepDerivative(double a, double b, double t) => 6.0 * t * (b - a) * (1.0 - t);
public static double Round(double value, double step) => step * Math.Round(value / step);
public static float Round(float value, float step) => step * Mathf.Round(value / step);
public static double Floor(double value, double step) => step * Math.Floor(value / step);
public static float Floor(float value, float step) => step * Mathf.Floor(value / step);
public static double Ceil(double value, double step) => step * Math.Ceiling(value / step);
public static float Ceil(float value, float step) => step * Mathf.Ceil(value / step);
public static double DistancePointToLineSegment(
Vector3d point,
Vector3d lineStart,
Vector3d lineEnd)
{
return Vector3d.Magnitude(VTMath.ProjectPointToLineSegment(point, lineStart, lineEnd) - point);
}
public static Vector3d ProjectPointToLineSegment(
Vector3d point,
Vector3d lineStart,
Vector3d lineEnd)
{
double lineParameter = VTMath.ProjectPointToLineParameter(point, lineStart, lineEnd);
return Vector3d.LerpClamped(lineStart, lineEnd, lineParameter);
}
public static double ProjectPointToLineParameter(
Vector3d point,
Vector3d lineStart,
Vector3d lineEnd)
{
Vector3d rhs = point - lineStart;
Vector3d vector3d = lineEnd - lineStart;
return Vector3d.Dot(vector3d, rhs) / Vector3d.SqrMagnitude(vector3d);
}
}
}

11
Assets/AR/VTMath.cs.meta Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: edfe6b3cfb01f654bb5045ca7a9217f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

154
Assets/AR/Vector3d.cs Normal file
View File

@ -0,0 +1,154 @@
using System;
namespace Assets
{
public struct Vector3d : IEquatable<Vector3d>
{
private static readonly Vector3d ZeroVector = new Vector3d(0.0, 0.0, 0.0);
private static readonly Vector3d OneVector = new Vector3d(1.0, 1.0, 1.0);
public double x;
public double y;
public double z;
public Vector3d(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Vector3d(double[] c)
{
this.x = c[0];
this.y = c[1];
this.z = c[2];
}
public static Vector3d Zero => Vector3d.ZeroVector;
public static Vector3d One => Vector3d.OneVector;
public Vector3d Normalized => Vector3d.Normalize(this);
public double this[int index]
{
get
{
switch (index)
{
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.z;
default:
throw new IndexOutOfRangeException("Invalid Vector3d index!");
}
}
set
{
switch (index)
{
case 0:
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
this.z = value;
break;
default:
throw new IndexOutOfRangeException("Invalid Vector3d index!");
}
}
}
public void Set(double newX, double newY, double newZ)
{
this.x = newX;
this.y = newY;
this.z = newZ;
}
public static double Magnitude(Vector3d v) => Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
public static double SqrMagnitude(Vector3d v) => v.x * v.x + v.y * v.y + v.z * v.z;
public static Vector3d Lerp(Vector3d a, Vector3d b, double t) => new Vector3d((1.0 - t) * a.x + t * b.x, (1.0 - t) * a.y + t * b.y, (1.0 - t) * a.z + t * b.z);
public static Vector3d LerpClamped(Vector3d a, Vector3d b, double t)
{
t = VTMath.Clamp01(t);
return Vector3d.Lerp(a, b, t);
}
public static Vector3d Scale(Vector3d a, Vector3d b) => new Vector3d(a.x * b.x, a.y * b.y, a.z * b.z);
public void Scale(Vector3d scale)
{
this.x *= scale.x;
this.y *= scale.y;
this.z *= scale.z;
}
public static Vector3d Cross(Vector3d lhs, Vector3d rhs) => new Vector3d(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
public override int GetHashCode() => this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2;
public override bool Equals(object other) => other is Vector3d other1 && this.Equals(other1);
public bool Equals(Vector3d other) => this == other;
public static Vector3d Normalize(Vector3d value)
{
double num = Vector3d.Magnitude(value);
return num > 0.0 ? value / num : Vector3d.Zero;
}
public void Normalize()
{
double num = Vector3d.Magnitude(this);
if (num > 0.0)
this = this / num;
else
this = Vector3d.Zero;
}
public static double Dot(Vector3d lhs, Vector3d rhs) => lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
public static double Distance(Vector3d a, Vector3d b)
{
double num1 = a.x - b.x;
double num2 = a.y - b.y;
double num3 = a.z - b.z;
return Math.Sqrt(num1 * num1 + num2 * num2 + num3 * num3);
}
public static Vector3d operator +(Vector3d a, Vector3d b) => new Vector3d(a.x + b.x, a.y + b.y, a.z + b.z);
public static Vector3d operator -(Vector3d a, Vector3d b) => new Vector3d(a.x - b.x, a.y - b.y, a.z - b.z);
public static Vector3d operator -(Vector3d a) => new Vector3d(-a.x, -a.y, -a.z);
public static Vector3d operator *(Vector3d a, double d) => new Vector3d(a.x * d, a.y * d, a.z * d);
public static Vector3d operator *(double d, Vector3d a) => new Vector3d(a.x * d, a.y * d, a.z * d);
public static Vector3d operator /(Vector3d a, double d) => new Vector3d(a.x / d, a.y / d, a.z / d);
public static bool operator ==(Vector3d lhs, Vector3d rhs) => lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
public static bool operator !=(Vector3d lhs, Vector3d rhs) => !(lhs == rhs);
public override string ToString() => this.ToString((string)null);
public string ToString(string format)
{
if (string.IsNullOrEmpty(format))
format = "F2";
return "(" + this.x.ToString(format) + ", " + this.y.ToString(format) + ", " + this.z.ToString(format) + ")";
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8454158d7f8e40a47b7134e3fcb68882
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.AR
{
public class VideoPlayerControl
{
private const float MinVideoPlaybackSpeedChangeInterval = 0.2f;
private const float MaxPlaybackSpeed = 1.5f;
private const float MaxCameraDistanceError = 200f;
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
private float fixedTimeFrame;
private DateTime fixedTimeSeekFinished = DateTime.MinValue;
private int lapCount = 1;
private double lapLength;
public float FixedVideoFrame => this.fixedTimeFrame;
//public IDistanceSource RiderDistance { get; set;
public AVProVideoPlayer VideoPlayer { get; private set; }
//public ISpeedSource RiderSpeed { get; set; }
public VideoPointsSync VideoSyncSource { get; set; }
public ARRoute Route { get; set; }
public int VideoFrameOffset { get; set; }
public float CameraFollowDistance { get; set; }
public bool AllowUpdate { get; set; } = true;
public float CameraDistanceError { get; private set; }
public bool IsTimeFixed { get; private set; }
public float FrameIndexDistanceCorrection { get; private set; }
public bool IsMultilap => this.lapCount > 1;
public void SetVideoPlayer(AVProVideoPlayer player) => this.VideoPlayer = player;
public void SetMultiLap(int lapCount, double lapLength)
{
this.lapCount = lapCount;
this.lapLength = lapLength;
}
public void FixTimeByDistance(float distance) => this.FixTimeByFrame(this.VideoSyncSource.GetVideoFrameAtDistance(distance));
public void FixTimeByFrame(float frame)
{
this.IsTimeFixed = true;
this.fixedTimeFrame = frame;
this.fixedTimeSeekFinished = DateTime.MinValue;
if (this.VideoPlayer.IsPaused)
this.VideoPlayer.Resume();
this.VideoPlayer.SetPlaybackSpeed(0.25f);
this.VideoPlayer.Seek((long)frame, true);
}
//public void UnFixTime()
//{
// this.IsTimeFixed = false;
// float videoFrameAtDistance = this.VideoSyncSource.GetVideoFrameAtDistance(this.RiderDistance.LapDistance);
// float num = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance, videoFrameAtDistance);
// float playbackSpeed = (double)num != 0.0 ? this.RiderSpeed.Speed / num : 0.0f;
// if (this.VideoPlayer.IsPaused)
// this.VideoPlayer.Resume();
// this.VideoPlayer.SetPlaybackSpeed(playbackSpeed);
// this.lastPlaybackSpeedChange = DateTime.UtcNow;
// this.VideoPlayer.Seek((long)videoFrameAtDistance, true);
//}
private void SkipVideoToDistance(float distance) => this.SkipVideoToFrame((long)this.VideoSyncSource.GetVideoFrameAtDistance(distance));
private void SkipVideoToFrame(long frame) => this.VideoPlayer.Seek(frame);
public void UpdateVideoPlaybackSpeed(float speed, float routeDistance)
{
if (!this.AllowUpdate)
return;
if (this.IsTimeFixed)
{
if (this.VideoPlayer.IsSeeking)
return;
if (this.fixedTimeSeekFinished == DateTime.MinValue)
this.fixedTimeSeekFinished = DateTime.UtcNow;
if (DateTime.UtcNow.Subtract(this.fixedTimeSeekFinished).TotalSeconds < 0.25)
return;
if ((double)this.VideoPlayer.CurrentFrame > (double)this.fixedTimeFrame)
this.VideoPlayer.Pause();
this.VideoPlayer.UpdateCurrentFrame();
this.FrameIndexDistanceCorrection = 0.0f;
}
else
{
float videoFrameAtDistance1 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance);
float val2 = routeDistance - this.CameraFollowDistance;
//if (this.IsMultilap && (double)this.RiderDistance.RouteDistance > (double)distance && (double)val2 < 0.0)
// val2 += (float)this.lapLength;
float distance = Math.Max(0.0f, val2);
float frame = this.VideoSyncSource.GetVideoFrameAtDistance(distance) + (float)this.VideoFrameOffset;
if (this.Route != null && (double)this.Route.GetVisibility(frame) > 10.0)
frame = (float)this.Route.GetFrameAtDistance(Math.Max(0.0, this.Route.GetDistanceForFrame((double)videoFrameAtDistance1) - (double)this.CameraFollowDistance)) + (float)this.VideoFrameOffset;
this.VideoPlayer.UpdateCurrentFrame();
float distanceForVideoFrame = this.VideoSyncSource.GetDistanceForVideoFrame(this.VideoPlayer.CurrentFrame - (float)this.VideoFrameOffset);
float f;
if (this.Route != null)
{
double frameAtDistance = this.Route.GetFrameAtDistance(this.Route.GetDistanceForFrame((double)this.VideoPlayer.CurrentFrame - (double)this.VideoFrameOffset) + (double)Mathf.Min(routeDistance, this.CameraFollowDistance));
f = videoFrameAtDistance1 - (float)frameAtDistance;
}
else
f = frame - (this.VideoPlayer.CurrentFrame - (float)this.VideoFrameOffset);
float num1 = Mathf.Clamp01(VTMath.Lerp(0.0f, 1f, 100f, 0.0f, Mathf.Abs(f)));
this.FrameIndexDistanceCorrection = f * num1;
this.CameraDistanceError = distance - distanceForVideoFrame;
if (this.IsMultilap)
{
float num2 = distance - (distanceForVideoFrame + (float)this.lapLength);
if ((double)Math.Abs(num2) < (double)Math.Abs(this.CameraDistanceError) && (double)Math.Abs(num2) < 200.0)
return;
}
if ((double)Math.Abs(this.CameraDistanceError) > 200.0)
{
this.SkipVideoToDistance(distance);
}
else
{
double totalSeconds = DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds;
if (totalSeconds >= 0.0 && totalSeconds < 0.20000000298023224)
return;
float num3 = 1f;
float num4 = num3 * speed;
if ((double)Math.Abs(distance + num4 - this.VideoSyncSource.GetDistanceForVideoFrame((float)((double)this.VideoPlayer.CurrentFrame - (double)this.VideoFrameOffset + (double)num3 * (double)this.VideoPlayer.PlaybackSpeed * (double)this.VideoPlayer.FrameRate))) <= (double)Math.Abs(this.CameraDistanceError))
return;
float videoFrameAtDistance2 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance + num4);
float num5 = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance1, videoFrameAtDistance2);
float playbackSpeed = Mathf.Clamp(((double)num5 != 0.0 ? speed / num5 : 0.0f) + (float)(((double)frame - ((double)this.VideoPlayer.CurrentFrame - (double)this.VideoFrameOffset)) / 2.0) / this.VideoPlayer.FrameRate, 0.0f, 1.5f);
if ((double)playbackSpeed == (double)this.VideoPlayer.PlaybackSpeed || !this.VideoPlayer.SetPlaybackSpeed(playbackSpeed))
return;
this.lastPlaybackSpeedChange = DateTime.UtcNow;
}
}
}
internal void UpdateVideoPlaybackSpeed(double speed, float distance)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f244e092373e2d40935fd6ec79c8af7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets
{
public class VideoPoint
{
public float Distance { get; set; }
public float Time { get; set; }
}
public class VideoPointsSync
{
private const float DefaultFps = 29.97f;
protected float[] videoDistances;
protected float[] videoTimes;
protected float fps;
public int Count => this.videoDistances.Length;
public float LastVideoFrame => this.videoTimes[this.videoTimes.Length - 1] * this.fps;
public VideoPointsSync(IEnumerable<VideoPoint> videoPoints, float fps = 29.97f)
{
List<VideoPoint> list = videoPoints.ToList<VideoPoint>();
list.Sort((Comparison<VideoPoint>)((x, y) => x.Distance.CompareTo(y.Distance)));
VideoPoint videoPoint1 = list[0];
for (int index = 1; index < list.Count; ++index)
{
VideoPoint videoPoint2 = list[index];
if ((double)videoPoint2.Distance == (double)videoPoint1.Distance)
{
list.RemoveAt(index);
--index;
}
else
videoPoint1 = videoPoint2;
}
this.videoDistances = list.Select<VideoPoint, float>((Func<VideoPoint, float>)(x => x.Distance)).ToArray<float>();
this.videoTimes = list.Select<VideoPoint, float>((Func<VideoPoint, float>)(x => x.Time)).ToArray<float>();
this.fps = fps;
}
public float GetVideoSpeedAtDistance(float distance)
{
int index = this.IndexOfVideoPointForDistance(distance);
return index == 0 || index == this.Count ? 0.0f : (float)(((double)this.videoDistances[index] - (double)this.videoDistances[index - 1]) / ((double)this.videoTimes[index] - (double)this.videoTimes[index - 1]));
}
public int IndexOfVideoPointForDistance(float distance)
{
int num = Array.BinarySearch<float>(this.videoDistances, distance);
return num < 0 ? ~num : num;
}
public int IndexOfVideoPointForTime(float time)
{
int num = Array.BinarySearch<float>(this.videoTimes, time);
return num < 0 ? ~num : num;
}
public float GetVideoFrameAtDistance(float distance)
{
int index = this.IndexOfVideoPointForDistance(distance);
if (index == 0)
return this.videoTimes[0] * this.fps;
if (index == this.Count)
return this.videoTimes[this.Count - 1] * this.fps;
float t = Mathf.InverseLerp(this.videoDistances[index - 1], this.videoDistances[index], distance);
return Mathf.Lerp(this.videoTimes[index - 1], this.videoTimes[index], t) * this.fps;
}
public float GetDistanceForVideoFrame(float frame)
{
float time = frame / this.fps;
int index = this.IndexOfVideoPointForTime(time);
if (index == 0)
return this.videoDistances[0];
if (index == this.Count)
return this.videoDistances[this.Count - 1];
float t = Mathf.InverseLerp(this.videoTimes[index - 1], this.videoTimes[index], time);
return Mathf.Lerp(this.videoDistances[index - 1], this.videoDistances[index], t);
}
public float AverageVideoSpeed(float startFrame, float endFrame) => (double)startFrame == (double)endFrame ? this.GetVideoSpeedAtDistance(this.GetDistanceForVideoFrame(startFrame)) : (float)(((double)this.GetDistanceForVideoFrame(endFrame) - (double)this.GetDistanceForVideoFrame(startFrame)) * ((double)this.fps / ((double)endFrame - (double)startFrame)));
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe1742dfacafb6e429b9388feba5699a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 341c9bc6edccecd498b3d3b74b08f3b9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f2e696010ab476541b5d4458dbc3b21e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 329bdb26604fbd6499707e6457df4921
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

494553
Assets/Resources/UI/ArData.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 874a748024ffda74a841855f69348615
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

213633
Assets/Resources/UI/camera.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4d018f8014dec174390f06f9fa947a05
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5a1f568492ae0ed498af496a6a4fb796
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8553de40c8498114ebee6f2d9d3e8641
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7611371c02fe34b43a5205f80056dd82
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b5f405e85b6fce54eb64e445b8a7997f
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -226,7 +226,7 @@ public static class App
//TcpAddress = new IPEndPoint(IPAddress.Parse("192.168.0.102"), 21001);
Debug.unityLogger.logEnabled = false;
#else
Host = "http://pf.juze.pro/"; //"http://192.168.0.102:5082/";//
//Host = "http://pf.juze.pro/"; //"http://192.168.0.102:5082/";//
UdpAddress = new IPEndPoint(IPAddress.Parse("47.97.84.8"), 21000);
TcpAddress = new IPEndPoint(IPAddress.Parse("47.97.84.8"), 21001);
#endif

View File

@ -17,4 +17,7 @@ EditorBuildSettings:
- enabled: 1
path: Assets/Scenes/VideoPlay.unity
guid: f25b9f482e27079448d130ae1ed0ea34
- enabled: 1
path: Assets/Scenes/TestVideoPlay.unity
guid: b5f405e85b6fce54eb64e445b8a7997f
m_configObjects: {}