diff options
| author | yum <yum.food.vr@gmail.com> | 2025-10-28 16:07:36 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-10-28 17:19:38 -0700 |
| commit | fd370eab7e4959895763514526efc878e53d4886 (patch) | |
| tree | 5ecb9f4d1710f737f96f68a6ab7d7b80e5d6c4d0 /Scripts/DataDecoder.cs | |
| parent | 0af84f011446496dd85a1cc6b139121ac99b139b (diff) | |
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.
Diffstat (limited to 'Scripts/DataDecoder.cs')
| -rw-r--r-- | Scripts/DataDecoder.cs | 40 |
1 files changed, 33 insertions, 7 deletions
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; } } |
