aha
This commit is contained in:
221
Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs
Normal file
221
Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs
Normal file
@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.SnapshotInterpolationDemo
|
||||
{
|
||||
public class ClientCube : MonoBehaviour
|
||||
{
|
||||
[Header("Components")]
|
||||
public ServerCube server;
|
||||
public Renderer render;
|
||||
|
||||
[Header("Toggle")]
|
||||
public bool interpolate = true;
|
||||
|
||||
// snapshot interpolation settings
|
||||
[Header("Snapshot Interpolation")]
|
||||
public SnapshotInterpolationSettings snapshotSettings =
|
||||
new SnapshotInterpolationSettings();
|
||||
|
||||
// runtime settings
|
||||
public double bufferTime => server.sendInterval * snapshotSettings.bufferTimeMultiplier;
|
||||
|
||||
// <servertime, snaps>
|
||||
public SortedList<double, Snapshot3D> snapshots = new SortedList<double, Snapshot3D>();
|
||||
|
||||
// for smooth interpolation, we need to interpolate along server time.
|
||||
// any other time (arrival on client, client local time, etc.) is not
|
||||
// going to give smooth results.
|
||||
double localTimeline;
|
||||
|
||||
// catchup / slowdown adjustments are applied to timescale,
|
||||
// to be adjusted in every update instead of when receiving messages.
|
||||
double localTimescale = 1;
|
||||
|
||||
// we use EMA to average the last second worth of snapshot time diffs.
|
||||
// manually averaging the last second worth of values with a for loop
|
||||
// would be the same, but a moving average is faster because we only
|
||||
// ever add one value.
|
||||
ExponentialMovingAverage driftEma;
|
||||
ExponentialMovingAverage deliveryTimeEma; // average delivery time (standard deviation gives average jitter)
|
||||
|
||||
// debugging ///////////////////////////////////////////////////////////
|
||||
[Header("Debug")]
|
||||
public Color catchupColor = Color.green; // green traffic light = go fast
|
||||
public Color slowdownColor = Color.red; // red traffic light = go slow
|
||||
Color defaultColor;
|
||||
|
||||
[Header("Simulation")]
|
||||
bool lowFpsMode;
|
||||
double accumulatedDeltaTime;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// show vsync reminder. too easy to forget.
|
||||
Debug.Log("Reminder: Snapshot interpolation is smoothest & easiest to debug with Vsync off.");
|
||||
|
||||
|
||||
defaultColor = render.sharedMaterial.color;
|
||||
|
||||
// initialize EMA with 'emaDuration' seconds worth of history.
|
||||
// 1 second holds 'sendRate' worth of values.
|
||||
// multiplied by emaDuration gives n-seconds.
|
||||
driftEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.driftEmaDuration);
|
||||
deliveryTimeEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.deliveryTimeEmaDuration);
|
||||
}
|
||||
|
||||
// add snapshot & initialize client interpolation time if needed
|
||||
public void OnMessage(Snapshot3D snap)
|
||||
{
|
||||
// set local timestamp (= when it was received on our end)
|
||||
// Unity 2019 doesn't have Time.timeAsDouble yet
|
||||
snap.localTime = NetworkTime.localTime;
|
||||
|
||||
// (optional) dynamic adjustment
|
||||
if (snapshotSettings.dynamicAdjustment)
|
||||
{
|
||||
// set bufferTime on the fly.
|
||||
// shows in inspector for easier debugging :)
|
||||
snapshotSettings.bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment(
|
||||
server.sendInterval,
|
||||
deliveryTimeEma.StandardDeviation,
|
||||
snapshotSettings.dynamicAdjustmentTolerance
|
||||
);
|
||||
}
|
||||
|
||||
// insert into the buffer & initialize / adjust / catchup
|
||||
SnapshotInterpolation.InsertAndAdjust(
|
||||
snapshots,
|
||||
snapshotSettings.bufferLimit,
|
||||
snap,
|
||||
ref localTimeline,
|
||||
ref localTimescale,
|
||||
server.sendInterval,
|
||||
bufferTime,
|
||||
snapshotSettings.catchupSpeed,
|
||||
snapshotSettings.slowdownSpeed,
|
||||
ref driftEma,
|
||||
snapshotSettings.catchupNegativeThreshold,
|
||||
snapshotSettings.catchupPositiveThreshold,
|
||||
ref deliveryTimeEma);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// accumulated delta allows us to simulate correct low fps + deltaTime
|
||||
// if necessary in client low fps mode.
|
||||
accumulatedDeltaTime += Time.unscaledDeltaTime;
|
||||
|
||||
// simulate low fps mode. only update once per second.
|
||||
// to simulate webgl background tabs, etc.
|
||||
// after a while, disable low fps mode and see how it behaves.
|
||||
if (lowFpsMode && accumulatedDeltaTime < 1) return;
|
||||
|
||||
// only while we have snapshots.
|
||||
// timeline starts when the first snapshot arrives.
|
||||
if (snapshots.Count > 0)
|
||||
{
|
||||
// snapshot interpolation
|
||||
if (interpolate)
|
||||
{
|
||||
// step
|
||||
SnapshotInterpolation.Step(
|
||||
snapshots,
|
||||
// accumulate delta is Time.unscaledDeltaTime normally.
|
||||
// and sum of past 10 delta's in low fps mode.
|
||||
accumulatedDeltaTime,
|
||||
ref localTimeline,
|
||||
localTimescale,
|
||||
out Snapshot3D fromSnapshot,
|
||||
out Snapshot3D toSnapshot,
|
||||
out double t);
|
||||
|
||||
// interpolate & apply
|
||||
Snapshot3D computed = Snapshot3D.Interpolate(fromSnapshot, toSnapshot, t);
|
||||
transform.position = computed.position;
|
||||
}
|
||||
// apply raw
|
||||
else
|
||||
{
|
||||
Snapshot3D snap = snapshots.Values[0];
|
||||
transform.position = snap.position;
|
||||
snapshots.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
// reset simulation helpers
|
||||
accumulatedDeltaTime = 0;
|
||||
|
||||
// color material while catching up / slowing down
|
||||
if (localTimescale < 1)
|
||||
render.material.color = slowdownColor;
|
||||
else if (localTimescale > 1)
|
||||
render.material.color = catchupColor;
|
||||
else
|
||||
render.material.color = defaultColor;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
// display buffer size as number for easier debugging.
|
||||
// catchup is displayed as color state in Update() already.
|
||||
const int width = 30; // fit 3 digits
|
||||
const int height = 20;
|
||||
Vector2 screen = Camera.main.WorldToScreenPoint(transform.position);
|
||||
string str = $"{snapshots.Count}";
|
||||
GUI.Label(new Rect(screen.x - width / 2, screen.y - height / 2, width, height), str);
|
||||
|
||||
// client simulation buttons on the bottom of the screen
|
||||
float areaHeight = 100;
|
||||
GUILayout.BeginArea(new Rect(0, Screen.height - areaHeight, Screen.width, areaHeight));
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Client Simulation:");
|
||||
if (GUILayout.Button((lowFpsMode ? "Disable" : "Enable") + " 1 FPS"))
|
||||
{
|
||||
lowFpsMode = !lowFpsMode;
|
||||
}
|
||||
|
||||
GUILayout.Label("|");
|
||||
|
||||
if (GUILayout.Button("Timeline 10s behind"))
|
||||
{
|
||||
localTimeline -= 10.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 1s behind"))
|
||||
{
|
||||
localTimeline -= 1.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 0.1s behind"))
|
||||
{
|
||||
localTimeline -= 0.1;
|
||||
}
|
||||
|
||||
GUILayout.Label("|");
|
||||
|
||||
if (GUILayout.Button("Timeline 0.1s ahead"))
|
||||
{
|
||||
localTimeline += 0.1;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 1s ahead"))
|
||||
{
|
||||
localTimeline += 1.0;
|
||||
}
|
||||
if (GUILayout.Button("Timeline 10s ahead"))
|
||||
{
|
||||
localTimeline += 10.0;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
// thresholds need to be <0 and >0
|
||||
snapshotSettings.catchupNegativeThreshold = Math.Min(snapshotSettings.catchupNegativeThreshold, 0);
|
||||
snapshotSettings.catchupPositiveThreshold = Math.Max(snapshotSettings.catchupPositiveThreshold, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51b244c3535d474aaf0a7a679f86185f
|
||||
timeCreated: 1654065994
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,80 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: ClientMaterial
|
||||
m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f17cbcb3229954975ab0818845a2c17f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/ClientMaterial.mat
|
||||
uploadId: 736421
|
@ -0,0 +1,447 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.12731749, g: 0.13414757, b: 0.1210787, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_LightingSettings: {fileID: 0}
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &89338751
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 89338755}
|
||||
- component: {fileID: 89338756}
|
||||
m_Layer: 0
|
||||
m_Name: Client Cube
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &89338755
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 89338751}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -5, y: 0.5, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1292704308}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &89338756
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 89338751}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 51b244c3535d474aaf0a7a679f86185f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
server: {fileID: 474480122}
|
||||
render: {fileID: 1292704310}
|
||||
interpolate: 1
|
||||
snapshotSettings:
|
||||
bufferTimeMultiplier: 2
|
||||
catchupNegativeThreshold: -1
|
||||
catchupPositiveThreshold: 1
|
||||
catchupSpeed: 0.019999999552965164
|
||||
slowdownSpeed: 0.03999999910593033
|
||||
driftEmaDuration: 1
|
||||
dynamicAdjustment: 1
|
||||
dynamicAdjustmentTolerance: 1
|
||||
deliveryTimeEmaDuration: 2
|
||||
catchupColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
slowdownColor: {r: 0, g: 0, b: 1, a: 1}
|
||||
--- !u!1 &474480117
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 474480121}
|
||||
- component: {fileID: 474480120}
|
||||
- component: {fileID: 474480119}
|
||||
- component: {fileID: 474480122}
|
||||
m_Layer: 0
|
||||
m_Name: Server Cube
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!23 &474480119
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 474480117}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 163b909ba60cc435a95bb35396edda15, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &474480120
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 474480117}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!4 &474480121
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 474480117}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -5, y: 0.5, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &474480122
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 474480117}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9a53730695f274a8aaa7ffdcf50d1008, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
client: {fileID: 89338756}
|
||||
distance: 10
|
||||
speed: 3
|
||||
sendRate: 30
|
||||
latency: 0.05
|
||||
jitter: 0.05
|
||||
loss: 0.05
|
||||
scramble: 0.05
|
||||
--- !u!1 &1292704307
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1292704308}
|
||||
- component: {fileID: 1292704311}
|
||||
- component: {fileID: 1292704310}
|
||||
m_Layer: 0
|
||||
m_Name: Visual Offset
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1292704308
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1292704307}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: -1, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 89338755}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &1292704310
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1292704307}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: f17cbcb3229954975ab0818845a2c17f, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &1292704311
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1292704307}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!1 &1961486736
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1961486739}
|
||||
- component: {fileID: 1961486738}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!20 &1961486738
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1961486736}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 2
|
||||
m_BackGroundColor: {r: 0.26415092, g: 0.26415092, b: 0.26415092, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 7
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1961486739
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1961486736}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -11.22}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 612a705077c16479db7b167ab1599ae8
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/MirrorSnapshotInterpolation.unity
|
||||
uploadId: 736421
|
3
Assets/Mirror/Examples/Snapshot Interpolation/README.txt
Normal file
3
Assets/Mirror/Examples/Snapshot Interpolation/README.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Snapshot Interpolation is a standalone, Unity / netcode independent algorithm.
|
||||
This is a simple demo to test it, without Mirror.
|
||||
We want this to be usable in all game engines.
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc8afa2efb5b4af1a983b5de47226e1e
|
||||
timeCreated: 1686584563
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/README.txt
|
||||
uploadId: 736421
|
108
Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs
Normal file
108
Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.SnapshotInterpolationDemo
|
||||
{
|
||||
public class ServerCube : MonoBehaviour
|
||||
{
|
||||
[Header("Components")]
|
||||
public ClientCube client;
|
||||
|
||||
[Header("Movement")]
|
||||
public float distance = 10;
|
||||
public float speed = 3;
|
||||
Vector3 start;
|
||||
|
||||
[Header("Snapshot Interpolation")]
|
||||
[Tooltip("Send N snapshots per second. Multiples of frame rate make sense.")]
|
||||
public int sendRate = 30; // in Hz. easier to work with as int for EMA. easier to display '30' than '0.333333333'
|
||||
public float sendInterval => 1f / sendRate;
|
||||
float lastSendTime;
|
||||
|
||||
[Header("Latency Simulation")]
|
||||
[Tooltip("Latency in seconds")]
|
||||
public float latency = 0.05f; // 50 ms
|
||||
[Tooltip("Latency jitter, randomly added to latency.")]
|
||||
[Range(0, 1)] public float jitter = 0.05f;
|
||||
[Tooltip("Packet loss in %")]
|
||||
[Range(0, 1)] public float loss = 0.1f;
|
||||
[Tooltip("Scramble % of unreliable messages, just like over the real network. Mirror unreliable is unordered.")]
|
||||
[Range(0, 1)] public float scramble = 0.1f;
|
||||
|
||||
// random
|
||||
// UnityEngine.Random.value is [0, 1] with both upper and lower bounds inclusive
|
||||
// but we need the upper bound to be exclusive, so using System.Random instead.
|
||||
// => NextDouble() is NEVER < 0 so loss=0 never drops!
|
||||
// => NextDouble() is ALWAYS < 1 so loss=1 always drops!
|
||||
System.Random random = new System.Random();
|
||||
|
||||
// hold on to snapshots for a little while before delivering
|
||||
// <deliveryTime, snapshot>
|
||||
List<(double, Snapshot3D)> queue = new List<(double, Snapshot3D)>();
|
||||
|
||||
// latency simulation:
|
||||
// always a fixed value + some jitter.
|
||||
float SimulateLatency() => latency + Random.value * jitter;
|
||||
|
||||
void Start()
|
||||
{
|
||||
start = transform.position;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// move on XY plane
|
||||
float x = Mathf.PingPong(Time.time * speed, distance);
|
||||
transform.position = new Vector3(start.x + x, start.y, start.z);
|
||||
|
||||
// broadcast snapshots every interval
|
||||
if (Time.time >= lastSendTime + sendInterval)
|
||||
{
|
||||
Send(transform.position);
|
||||
lastSendTime = Time.time;
|
||||
}
|
||||
|
||||
Flush();
|
||||
}
|
||||
|
||||
void Send(Vector3 position)
|
||||
{
|
||||
// create snapshot
|
||||
// Unity 2019 doesn't have Time.timeAsDouble yet
|
||||
Snapshot3D snap = new Snapshot3D(NetworkTime.localTime, 0, position);
|
||||
|
||||
// simulate packet loss
|
||||
bool drop = random.NextDouble() < loss;
|
||||
if (!drop)
|
||||
{
|
||||
// simulate scramble (Random.Next is < max, so +1)
|
||||
bool doScramble = random.NextDouble() < scramble;
|
||||
int last = queue.Count;
|
||||
int index = doScramble ? random.Next(0, last + 1) : last;
|
||||
|
||||
// simulate latency
|
||||
float simulatedLatency = SimulateLatency();
|
||||
// Unity 2019 doesn't have Time.timeAsDouble yet
|
||||
double deliveryTime = NetworkTime.localTime + simulatedLatency;
|
||||
queue.Insert(index, (deliveryTime, snap));
|
||||
}
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
// flush ready snapshots to client
|
||||
for (int i = 0; i < queue.Count; ++i)
|
||||
{
|
||||
(double deliveryTime, Snapshot3D snap) = queue[i];
|
||||
|
||||
// Unity 2019 doesn't have Time.timeAsDouble yet
|
||||
if (NetworkTime.localTime >= deliveryTime)
|
||||
{
|
||||
client.OnMessage(snap);
|
||||
queue.RemoveAt(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a53730695f274a8aaa7ffdcf50d1008
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,80 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: ServerMaterial
|
||||
m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 163b909ba60cc435a95bb35396edda15
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/ServerMaterial.mat
|
||||
uploadId: 736421
|
26
Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs
Normal file
26
Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// a simple snapshot with timestamp & interpolation
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.SnapshotInterpolationDemo
|
||||
{
|
||||
public struct Snapshot3D : Snapshot
|
||||
{
|
||||
public double remoteTime { get; set; }
|
||||
public double localTime { get; set; }
|
||||
public Vector3 position;
|
||||
|
||||
public Snapshot3D(double remoteTime, double localTime, Vector3 position)
|
||||
{
|
||||
this.remoteTime = remoteTime;
|
||||
this.localTime = localTime;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public static Snapshot3D Interpolate(Snapshot3D from, Snapshot3D to, double t) =>
|
||||
new Snapshot3D(
|
||||
// interpolated snapshot is applied directly. don't need timestamps.
|
||||
0, 0,
|
||||
// lerp unclamped in case we ever need to extrapolate.
|
||||
Vector3.LerpUnclamped(from.position, to.position, (float)t));
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2c9bdffb0b934b52b2c337a5c8a5698
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,2 @@
|
||||
otherwise it may not look entirely smooth.
|
||||
even on 120 hz.
|
@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7db50a51601fe4b3c8c929f6868bffbc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Examples/Snapshot Interpolation/_DISABLE VSYNC_
|
||||
uploadId: 736421
|
Reference in New Issue
Block a user