From fd370eab7e4959895763514526efc878e53d4886 Mon Sep 17 00:00:00 2001 From: yum Date: Tue, 28 Oct 2025 16:07:36 -0700 Subject: add logical time feature the idea is that a remote piece of software s.a. TiXL sends in its logical time every once in a while. udon recovers it, interpolates and smooths it, and feeds it to the shader. Anything which is periodic on units of 1.0 "seconds" retains its periodicity under changes to the rate of passage of time. --- Scripts/DataDecoder.asset | 206 ++++++++++++++++++++++++++++++++++++++++------ Scripts/DataDecoder.cs | 40 +++++++-- 2 files changed, 214 insertions(+), 32 deletions(-) (limited to 'Scripts') diff --git a/Scripts/DataDecoder.asset b/Scripts/DataDecoder.asset index 26b5e70..b8be961 100644 --- a/Scripts/DataDecoder.asset +++ b/Scripts/DataDecoder.asset @@ -12,7 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3} m_Name: DataDecoder m_EditorClassIdentifier: - serializedUdonProgramAsset: {fileID: 11400000, guid: b63b58ca1fad83a46a36891e4e44e019, + serializedUdonProgramAsset: {fileID: 11400000, guid: 38593ce802cabb24286414629c53980c, type: 2} udonAssembly: assemblyError: @@ -44,7 +44,7 @@ MonoBehaviour: Data: - Name: Entry: 12 - Data: 7 + Data: 10 - Name: Entry: 7 Data: @@ -104,19 +104,19 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: tileToCheck + Data: target - Name: $v Entry: 7 Data: 5|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 - Data: tileToCheck + Data: target - Name: k__BackingField Entry: 7 Data: 6|System.RuntimeType, mscorlib - Name: Entry: 1 - Data: System.Int32, mscorlib + Data: UnityEngine.MeshRenderer, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -166,11 +166,17 @@ MonoBehaviour: Entry: 1 Data: tileSize - Name: k__BackingField - Entry: 9 - Data: 6 + Entry: 7 + Data: 9|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Int32, mscorlib + - Name: + Entry: 8 + Data: - Name: k__BackingField Entry: 9 - Data: 6 + Data: 9 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -185,7 +191,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 9|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 10|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -209,13 +215,13 @@ MonoBehaviour: Data: pixelData - Name: $v Entry: 7 - Data: 10|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 11|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: pixelData - Name: k__BackingField Entry: 7 - Data: 11|System.RuntimeType, mscorlib + Data: 12|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Color32[], UnityEngine.CoreModule @@ -224,7 +230,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 11 + Data: 12 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -239,7 +245,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 12|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -263,13 +269,13 @@ MonoBehaviour: Data: hasData - Name: $v Entry: 7 - Data: 13|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: hasData - Name: k__BackingField Entry: 7 - Data: 14|System.RuntimeType, mscorlib + Data: 15|System.RuntimeType, mscorlib - Name: Entry: 1 Data: System.Boolean, mscorlib @@ -278,7 +284,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 14 + Data: 15 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -293,7 +299,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 16|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -317,16 +323,16 @@ MonoBehaviour: Data: readWidth - Name: $v Entry: 7 - Data: 16|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: readWidth - Name: k__BackingField Entry: 9 - Data: 6 + Data: 9 - Name: k__BackingField Entry: 9 - Data: 6 + Data: 9 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -341,7 +347,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 17|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -365,16 +371,166 @@ MonoBehaviour: Data: readHeight - Name: $v Entry: 7 - Data: 18|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: readHeight - Name: k__BackingField Entry: 9 - Data: 6 + Data: 9 - Name: k__BackingField Entry: 9 - Data: 6 + Data: 9 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 20|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: wallSyncTime + - Name: $v + Entry: 7 + Data: 21|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: wallSyncTime + - Name: k__BackingField + Entry: 7 + Data: 22|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Single, mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 22 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 23|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: logicalSyncTimeMs + - Name: $v + Entry: 7 + Data: 24|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: logicalSyncTimeMs + - Name: k__BackingField + Entry: 9 + Data: 22 + - Name: k__BackingField + Entry: 9 + Data: 22 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 25|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: logicalTimeFactor + - Name: $v + Entry: 7 + Data: 26|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: logicalTimeFactor + - Name: k__BackingField + Entry: 9 + Data: 22 + - Name: k__BackingField + Entry: 9 + Data: 22 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -389,7 +545,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 19|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 27|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 diff --git a/Scripts/DataDecoder.cs b/Scripts/DataDecoder.cs index 96f4a7d..9715d81 100644 --- a/Scripts/DataDecoder.cs +++ b/Scripts/DataDecoder.cs @@ -9,7 +9,7 @@ using VRC.Udon.Common.Interfaces; public class DataDecoder : UdonSharpBehaviour { public RenderTexture sourceTexture; - public int tileToCheck = 0; + public MeshRenderer target; private int tileSize = 8; // Minimum size (in pixels) of a tile. This is shared with our tixl operator. @@ -20,6 +20,13 @@ public class DataDecoder : UdonSharpBehaviour private int readWidth; private int readHeight; + // The wall time at which we last saw a sync event + private float wallSyncTime; + // The logical time corresponding to the last sync event + private float logicalSyncTimeMs; + // The rate at which logical time passes every second. + private float logicalTimeFactor; + // Top-level data types. private const int kT_TimeSyncData = 0; @@ -65,6 +72,14 @@ public class DataDecoder : UdonSharpBehaviour ProcessTiles(); hasData = false; } + + if (wallSyncTime != null) { + float logicalTime = logicalSyncTimeMs * 0.001f + + logicalTimeFactor * (Time.time - wallSyncTime); + if (target != null) { + target.material.SetFloat("_Logical_Time", logicalTime); + } + } } public override void OnAsyncGpuReadbackComplete(VRCAsyncGPUReadbackRequest request) @@ -146,10 +161,12 @@ public class DataDecoder : UdonSharpBehaviour int checksumLocal = tileSize + lengthSubpixels; Color32 parsed_first = GetTileRGB(0); + /* Debug.Log($"First tile: {parsed_first.r} {parsed_first.g} {parsed_first.b}"); Debug.Log($"Parsed size {tileSize}"); Debug.Log($"Parsed length {lengthSubpixels}"); Debug.Log($"Parsed checksum {checksumRemote}"); + */ // Collect all nibbles into a flat array. Note that these are still // encoded. @@ -173,10 +190,10 @@ public class DataDecoder : UdonSharpBehaviour checksumLocal += (nibbles[i] >> 4) & 0x0F; } - Debug.Log($"Local checksum {checksumLocal}"); + //Debug.Log($"Local checksum {checksumLocal}"); if (checksumLocal != checksumRemote) { - Debug.LogWarning($"Checksums don't match. Attempting error recovery."); + //Debug.LogWarning($"Checksums don't match. Attempting error recovery."); // Data is submitted in triplicate. Perform a bitwise majority vote // with `(a & b) | (a & c) | (b & c)`. @@ -219,8 +236,9 @@ public class DataDecoder : UdonSharpBehaviour // See DataEncoder.cs. It puts the upper 4 bits before the lower 4 bits. bytes[i] = (byte) ((nibbles[2*i] & 0xF0) | ((nibbles[2*i+1] & 0xF0) >> 4)); } - Debug.Log($"Parsed {bytes.Length} bytes from {nibbles.Length} subpixels"); + //Debug.Log($"Parsed {bytes.Length} bytes from {nibbles.Length} subpixels"); + // Parse input. int bOff = 0; while (HasBytesLeft(bytes, bOff, 8)) { int type = GetInt(ref bytes, ref bOff); @@ -232,9 +250,17 @@ public class DataDecoder : UdonSharpBehaviour switch (type) { case kT_TimeSyncData: { - float lastSyncTimeMs = GetFloat(ref bytes, ref bOff); - float measureTimeUs = GetFloat(ref bytes, ref bOff); - Debug.Log($"Parsed time sync data: {lastSyncTimeMs} {measureTimeUs}"); + float syncTimeMs = GetFloat(ref bytes, ref bOff); + float measureTime = GetFloat(ref bytes, ref bOff) * 1e-6f; + //Debug.Log($"Parsed time sync data: {syncTimeMs} {measureTimeUs}"); + + if (logicalSyncTimeMs != syncTimeMs) { + // Indicate that we have seen a sync event. + wallSyncTime = Time.time; + Debug.Log($"Sync time updated: t0={logicalSyncTimeMs} ms, k=${measureTime}"); + } + logicalSyncTimeMs = syncTimeMs; + logicalTimeFactor = 1.0f / measureTime; break; } } -- cgit v1.2.3