From 46a383e36d21ef72997e36ac99909e120164e39c Mon Sep 17 00:00:00 2001 From: Max Barashev <33381533+nemestniy@users.noreply.github.com> Date: Fri, 5 Jun 2026 21:02:56 +0300 Subject: [PATCH] Added RpcFunctions - Added RpcFunction.cs with init static functions - Extend BlendShaderController for getting needed data - Added CrpcExtensions for server api --- Assets/Scenes/MainScene.unity | 8 +- Assets/Scripts/BlendShaderController.cs | 180 +++++++++++++++---- Assets/Scripts/CrpcApi.cs | 47 ++++- Assets/Scripts/DepthRenderPassFeature.cs | 8 +- Assets/Scripts/RpcFunctions.cs | 218 +++++++++++++++++++++++ Assets/Scripts/RpcFunctions.cs.meta | 11 ++ Assets/Shaders/BlendShader.compute | 19 ++ 7 files changed, 454 insertions(+), 37 deletions(-) create mode 100644 Assets/Scripts/RpcFunctions.cs create mode 100644 Assets/Scripts/RpcFunctions.cs.meta diff --git a/Assets/Scenes/MainScene.unity b/Assets/Scenes/MainScene.unity index 827a2ca..7953c8b 100644 --- a/Assets/Scenes/MainScene.unity +++ b/Assets/Scenes/MainScene.unity @@ -252,7 +252,7 @@ PrefabInstance: - target: {fileID: 919132149155446097, guid: cadef6a45e22b304aafd4c21eb84340f, type: 3} propertyPath: m_IsActive - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 919132149155446097, guid: cadef6a45e22b304aafd4c21eb84340f, type: 3} @@ -1424,7 +1424,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: FrameRes: 256 - Offset: 0.02 + Offset: -0.07 texture2D: {fileID: 0} --- !u!1 &686694433 GameObject: @@ -1624,7 +1624,7 @@ MonoBehaviour: m_GameObject: {fileID: 763126624} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c61b6ef6bca767e42a8ec8ea380a4ac6, type: 3} + m_Script: {fileID: 11500000, guid: b06971fce09a875489a2898f4f2cbaec, type: 3} m_Name: m_EditorClassIdentifier: --- !u!1 &858903265 @@ -1726,7 +1726,7 @@ Transform: m_GameObject: {fileID: 858903265} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 1.5} + m_LocalPosition: {x: 0, y: 0, z: 2} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] diff --git a/Assets/Scripts/BlendShaderController.cs b/Assets/Scripts/BlendShaderController.cs index 8263d06..3c9e20b 100644 --- a/Assets/Scripts/BlendShaderController.cs +++ b/Assets/Scripts/BlendShaderController.cs @@ -19,6 +19,9 @@ public class BlendShaderController : MonoBehaviour private static int resXProp = Shader.PropertyToID("ResX"); private static int farClipPlaneProp = Shader.PropertyToID("FarClipPlane"); private static int monoChanelResProp = Shader.PropertyToID("MonoChannelResult"); + private static int Depths1Id = Shader.PropertyToID("Depths1"); + private static int Depths2Id = Shader.PropertyToID("Depths2"); + private static int ResDepthsId = Shader.PropertyToID("MergedDepths"); private static string savePath = Application.streamingAssetsPath + '\\'; private const string filename = "dsitMap"; @@ -65,6 +68,10 @@ public class BlendShaderController : MonoBehaviour Task task1; Task task2; + private ComputeBuffer depthsBuffer1; + private ComputeBuffer depthsBuffer2; + private ComputeBuffer resDepthsBuffer; + private int uvOffset; // Start is called before the first frame update @@ -81,6 +88,10 @@ public class BlendShaderController : MonoBehaviour depthBuffer = new ComputeBuffer(currentRes * currentRes, 1 * sizeof(float)); depthMaterial = CoreUtils.CreateEngineMaterial(DepthShader); depthMaterial.SetBuffer("distBuffer", depthBuffer); + + depthsBuffer1 = new ComputeBuffer(currentRes * currentRes, 1 * sizeof(float)); + depthsBuffer2 = new ComputeBuffer(currentRes * currentRes, 1 * sizeof(float)); + resDepthsBuffer = new ComputeBuffer(currentRes * currentRes, 1 * sizeof(float)); } void InitializeTextures() @@ -120,24 +131,6 @@ public class BlendShaderController : MonoBehaviour SetCameraDistance(testDistance); ComputeUVOffset(); - if (Input.GetKeyDown(KeyCode.F)) - { - flag = !flag; - } - - // if (flag) - // { - // GenerateDepth(); - // } - - // if(flag) - // { - // RenderTexture tempRt = new RenderTexture(cameraTexture1); - // Graphics.Blit(tempRt, cameraTexture1, depthMaterial); - // tempRt = new RenderTexture(cameraTexture2); - // Graphics.Blit(tempRt, cameraTexture2, depthMaterial); - // } - UpdateShader(cameraTexture1, cameraTexture2); } @@ -153,6 +146,21 @@ public class BlendShaderController : MonoBehaviour BlendShader.Dispatch(0, Result.width / 8, Result.height / 8, 1); } + void UpdateShader(float[] depths1, float[] depths2) + { + depthsBuffer1.SetData(depths1); + depthsBuffer2.SetData(depths2); + + BlendShader.SetFloat(offsetProp, uvOffset); + BlendShader.SetFloat(resXProp, currentRes); + + BlendShader.SetBuffer(1, Depths1Id, depthsBuffer1); + BlendShader.SetBuffer(1, Depths2Id, depthsBuffer2); + BlendShader.SetBuffer(1, ResDepthsId, resDepthsBuffer); + + BlendShader.Dispatch(1, currentRes / 8, currentRes / 8, 1); + } + void ComputeUVOffset() { if (camera1 && camera2) @@ -171,15 +179,6 @@ public class BlendShaderController : MonoBehaviour uvOffset = (int)(camera2.transform.localPosition.x * OffsetMultiplier); } - void GenerateDepth() - { - //camera1.RenderWithShader(DepthShader, "RenderType"); - //camera2.RenderWithShader(DepthShader, "RenderType"); - - Graphics.Blit(depth1, cameraTexture1); //Depth generated due to format of render texture - Graphics.Blit(depth2, cameraTexture2); - } - void SwapRenderTargets() { if (flag) @@ -227,9 +226,20 @@ public class BlendShaderController : MonoBehaviour Save(result); } - public void GetDistArray() + public async void GetDistArray(TaskCompletionSource tcs) { - + int cameraId1 = camera1.GetInstanceID(); + int cameraId2 = camera2.GetInstanceID(); + float[] depths1 = await DepthRenderPassFeature.DepthRenderPass.RequestDepthDataAsync(cameraId1); + float[] depths2 = await DepthRenderPassFeature.DepthRenderPass.RequestDepthDataAsync(cameraId2); + UpdateShader(depths1, depths2); + float[] depths = new float[currentRes * currentRes]; + resDepthsBuffer.GetData(depths); + byte[] bytes = new byte[depths.Length * sizeof(float)]; + Buffer.BlockCopy(depths, 0, bytes, 0, bytes.Length); + string base64 = Convert.ToBase64String(bytes); + string result = "{\"width\":" + currentRes + ",\"height\":" + currentRes + ",\"data\":\"" + base64 + "\"}"; + tcs.SetResult(result); } private async Task SavingProcessAsync(string data) @@ -248,12 +258,17 @@ public class BlendShaderController : MonoBehaviour } private string SerializeArray() + { + return SerializeArray(resultArray); + } + + private string SerializeArray(float[] arr) { string result = string.Empty; Debug.Log("StartSerializing"); for (int i = 0; i < resultArray.Length; i += currentRes) { - result += string.Join(", ", resultArray[i..(i + currentRes)]) + '\n'; + result += string.Join("; ", arr[i..(i + currentRes)]) + '\n'; } Debug.Log("EndSerializing"); return result; @@ -293,6 +308,54 @@ public class BlendShaderController : MonoBehaviour return new double[] { fx, 0, cx, 0, fy, cy, 0, 0, 1 }; } + public string GetIntrinsicParametersAsBase64(Camera camera) + { + double[] intrinsics = GetIntrinsicParameters(camera); + byte[] bytes = new byte[intrinsics.Length * sizeof(double)]; + Buffer.BlockCopy(intrinsics, 0, bytes, 0, bytes.Length); + return Convert.ToBase64String(bytes); + } + + public string GetLeftIntrinsicParametersAsBase64() + { + return GetIntrinsicParametersAsBase64(camera1); + } + + public string GetRightIntrinsicParametersAsBase64() + { + return GetIntrinsicParametersAsBase64(camera2); + } + + public double[] GetExtrinsicParameters(Camera camera) + { + Matrix4x4 m = camera.worldToCameraMatrix; + return new double[] + { + m.m00, m.m01, m.m02, m.m03, + m.m10, m.m11, m.m12, m.m13, + m.m20, m.m21, m.m22, m.m23, + m.m30, m.m31, m.m32, m.m33 + }; + } + + public string GetExtrinsicParametersAsBase64(Camera camera) + { + double[] extrinsics = GetExtrinsicParameters(camera); + byte[] bytes = new byte[extrinsics.Length * sizeof(double)]; + Buffer.BlockCopy(extrinsics, 0, bytes, 0, bytes.Length); + return Convert.ToBase64String(bytes); + } + + public string GetLeftExtrinsicParametersAsBase64() + { + return GetExtrinsicParametersAsBase64(camera1); + } + + public string GetRightExtrinsicParametersAsBase64() + { + return GetExtrinsicParametersAsBase64(camera2); + } + public float GetCameraDistance() { if (camera1 == null || camera2 == null) @@ -312,6 +375,56 @@ public class BlendShaderController : MonoBehaviour camera1.transform.position = center - direction * distance * 0.5f; } + public RenderTexture CombineTexturesSideBySide(RenderTexture left, RenderTexture right) + { + if (left == null || right == null) + { + Debug.LogError("Both render textures must be provided"); + return null; + } + if (left.width != right.width || left.height != right.height) + { + Debug.LogError("Both render textures must have the same dimensions"); + return null; + } + + int w = left.width; + int h = left.height; + + RenderTexture combined = new RenderTexture(w * 2, h, 0, RenderTextureFormat.ARGBFloat); + combined.Create(); + + Graphics.CopyTexture(left, 0, 0, 0, 0, w, h, combined, 0, 0, 0, 0); + Graphics.CopyTexture(right, 0, 0, 0, 0, w, h, combined, 0, 0, w, 0); + + return combined; + } + + public string GetCombinedTexturesAsBase64Json() + { + RenderTexture combined = CombineTexturesSideBySide(cameraTexture1, cameraTexture2); + if (combined == null) return null; + + int w = combined.width; + int h = combined.height; + + RenderTexture activeRT = RenderTexture.active; + RenderTexture.active = combined; + + Texture2D tex = new Texture2D(w, h, TextureFormat.RGBAFloat, false); + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); + tex.Apply(); + RenderTexture.active = activeRT; + + byte[] rawData = tex.GetRawTextureData(); + Destroy(tex); + combined.Release(); + + string base64 = Convert.ToBase64String(rawData); + + return "{\"width\":" + w + ",\"height\":" + h + ",\"data\":\"" + base64 + "\"}"; + } + private void OnDisable() { computeBuffer.Release(); @@ -320,6 +433,13 @@ public class BlendShaderController : MonoBehaviour depthBuffer.Release(); depthBuffer = null; + depthsBuffer1.Release(); + depthsBuffer1 = null; + depthsBuffer2.Release(); + depthsBuffer2 = null; + resDepthsBuffer.Release(); + resDepthsBuffer = null; + Destroy(depthMaterial); depthMaterial = null; } diff --git a/Assets/Scripts/CrpcApi.cs b/Assets/Scripts/CrpcApi.cs index 078d0c4..b38439c 100644 --- a/Assets/Scripts/CrpcApi.cs +++ b/Assets/Scripts/CrpcApi.cs @@ -71,7 +71,7 @@ namespace CloudPointRpc public RpcString(string data) { - var bytes = Encoding.UTF8.GetBytes(data); + var bytes = Encoding.ASCII.GetBytes(data); _handle = CrpcServerApi.crpc_str_create(bytes, (ulong)bytes.Length); } @@ -113,6 +113,51 @@ namespace CloudPointRpc } } + public static class CrpcExtensions + { + public static string CrpcStrGetData(IntPtr rpcString) + { + var dataPtr = CrpcServerApi.crpc_str_get_data(rpcString); + var size = CrpcServerApi.crpc_str_get_size(rpcString); + if (dataPtr == IntPtr.Zero || size == 0) + return string.Empty; + return Marshal.PtrToStringAnsi(dataPtr, (int)size) ?? string.Empty; + } + + public static ulong CrpcStrGetSize(IntPtr rpcString) + { + return CrpcServerApi.crpc_str_get_size(rpcString); + } + + public static IntPtr CrpcStrCreate(string data) + { + var bytes = Encoding.UTF8.GetBytes(data); + return CrpcServerApi.crpc_str_create(bytes, (ulong)bytes.Length); + } + + public static void CrpcStrDestroy(IntPtr rpcString) + { + CrpcServerApi.crpc_str_destroy(rpcString); + } + + public static void CrpcInit(string configPath) + { + var bytes = Encoding.UTF8.GetBytes(configPath + '\0'); + CrpcServerApi.crpc_init(bytes); + } + + public static void CrpcDeinit() + { + CrpcServerApi.crpc_deinit(); + } + + public static void CrpcAddMethod(CrpcTestApi.RpcStringCallback cb, string name) + { + using var nameRpc = new RpcString(name); + CrpcServerApi.crpc_add_method(cb, nameRpc.Handle); + } + } + public static class CrpcTestExtensions { public static void CrpcTestAddMethod(CrpcTestApi.RpcStringCallback cb, string name) diff --git a/Assets/Scripts/DepthRenderPassFeature.cs b/Assets/Scripts/DepthRenderPassFeature.cs index 66249ee..2838e2e 100644 --- a/Assets/Scripts/DepthRenderPassFeature.cs +++ b/Assets/Scripts/DepthRenderPassFeature.cs @@ -13,12 +13,11 @@ public class DepthRenderPassFeature : ScriptableRendererFeature internal class DepthRenderPass : ScriptableRenderPass { - public static Task RequestDepthDataAsync(int id) + public static Task RequestDepthDataAsync(int id, TaskCompletionSource tcs) { if(m_PendingRequests == null) m_PendingRequests = new Dictionary>>(); - var tcs = new TaskCompletionSource(); int key = id; if (!m_PendingRequests.TryGetValue(key, out var queue)) { @@ -28,6 +27,11 @@ public class DepthRenderPassFeature : ScriptableRendererFeature queue.Enqueue(tcs); return tcs.Task; } + public static Task RequestDepthDataAsync(int id) + { + var tcs = new TaskCompletionSource(); + return RequestDepthDataAsync(id, tcs); + } ProfilingSampler m_ProfilingSampler = new ProfilingSampler("ColorBlit"); private Material material; diff --git a/Assets/Scripts/RpcFunctions.cs b/Assets/Scripts/RpcFunctions.cs new file mode 100644 index 0000000..04c8492 --- /dev/null +++ b/Assets/Scripts/RpcFunctions.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using CloudPointRpc; +using UnityEngine; + +public class RpcFunctions : MonoBehaviour +{ + private static Queue _callbackTasks = new Queue(); + private static BlendShaderController controller; + private static CancellationTokenSource cts; + + void Start() + { + controller = GetComponent(); + cts = new CancellationTokenSource(); + + CrpcExtensions.CrpcInit("config.json"); + + CrpcExtensions.CrpcAddMethod(RpcGetCloudPoint, "get_cloud_point"); + CrpcExtensions.CrpcAddMethod(RpcGetImage, "get_image"); + CrpcExtensions.CrpcAddMethod(RpcGetIntrinsicsLeft, "get_intrinsics_left"); + CrpcExtensions.CrpcAddMethod(RpcGetIntrinsicsRight, "get_intrinsics_right"); + CrpcExtensions.CrpcAddMethod(RpcGetExtrinsicsLeft, "get_extrinsics_left"); + CrpcExtensions.CrpcAddMethod(RpcGetExtrinsicsRight, "get_extrinsics_right"); + + Debug.Log("[RpcFunctions] Initialized and methods added"); + } + + private void OnDestroy() + { + lock (_callbackTasks) + { + _callbackTasks.Clear(); + } + cts.Cancel(); + CrpcServerApi.crpc_deinit(); + } + + private void Update() + { + lock (_callbackTasks) + { + while (_callbackTasks.Count > 0) + { + var task = _callbackTasks.Dequeue(); + task.RunSynchronously(); + } + } + } + + public static IntPtr RpcGetCloudPoint(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + var tcs = new TaskCompletionSource(); + + var task = new Task(() => { + Debug.Log($"[RpcTest] Callback received: {message}"); + controller.GetDistArray(tcs); + }, cts.Token); + + lock (_callbackTasks) + { + _callbackTasks.Enqueue(task); + } + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } + + public static IntPtr RpcGetImage(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + + var tcs = new TaskCompletionSource(); + var task = new Task(() => + { + string result = controller.GetCombinedTexturesAsBase64Json(); + tcs.SetResult(result); + }); + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } + + public static IntPtr RpcGetIntrinsicsLeft(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + + var tcs = new TaskCompletionSource(); + var task = new Task(() => + { + string result = controller.GetLeftIntrinsicParametersAsBase64(); + tcs.SetResult(result); + }); + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } + + public static IntPtr RpcGetIntrinsicsRight(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + + var tcs = new TaskCompletionSource(); + var task = new Task(() => + { + string result = controller.GetRightIntrinsicParametersAsBase64(); + tcs.SetResult(result); + }); + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } + + public static IntPtr RpcGetExtrinsicsLeft(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + + var tcs = new TaskCompletionSource(); + var task = new Task(() => + { + string result = controller.GetLeftExtrinsicParametersAsBase64(); + tcs.SetResult(result); + }); + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } + + public static IntPtr RpcGetExtrinsicsRight(IntPtr rpcString) + { + var rpc = new RpcString(rpcString); + var message = rpc.Data; + rpc.Dispose(); + + var tcs = new TaskCompletionSource(); + var task = new Task(() => + { + string result = controller.GetRightExtrinsicParametersAsBase64(); + tcs.SetResult(result); + }); + + try + { + task.Wait(cts.Token); + tcs.Task.Wait(cts.Token); + } + catch (OperationCanceledException) + { + Debug.Log("Waiting was canceled"); + } + + var responce = new RpcString(tcs.Task.Result); + return responce.Handle; + } +} diff --git a/Assets/Scripts/RpcFunctions.cs.meta b/Assets/Scripts/RpcFunctions.cs.meta new file mode 100644 index 0000000..104ec48 --- /dev/null +++ b/Assets/Scripts/RpcFunctions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b06971fce09a875489a2898f4f2cbaec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Shaders/BlendShader.compute b/Assets/Shaders/BlendShader.compute index ade67cf..a44d524 100644 --- a/Assets/Shaders/BlendShader.compute +++ b/Assets/Shaders/BlendShader.compute @@ -1,5 +1,6 @@ // Each #kernel tells which function to compile; you can have many kernels #pragma kernel CSMain +#pragma kernel CSBlendDepths // Create a RenderTexture with enableRandomWrite flag and set it // with cs.SetTexture @@ -7,6 +8,11 @@ RWTexture2D Camera1; RWTexture2D Camera2; RWTexture2D Result; RWStructuredBuffer MonoChannelResult; + +StructuredBuffer Depths1; +StructuredBuffer Depths2; +RWStructuredBuffer MergedDepths; + float ResX; float Offset; float FarClipPlane; @@ -29,3 +35,16 @@ void CSMain (uint3 id : SV_DispatchThreadID) Result[id.xy] = resVal; MonoChannelResult[id.x + id.y * ResX] = resVal.r * FarClipPlane; } + +[numthreads(8, 8, 1)] +void CSBlendDepths(uint3 id : SV_DispatchThreadID) +{ + int2 idx1 = int2(clamp(id.x + Offset, 0, ResX), id.y); + int2 idx2 = int2(clamp(id.x - Offset, 0, ResX), id.y); + float col1 = Depths1[idx1.x + ResX * idx1.y]; + float col2 = Depths1[idx2.x + ResX * idx2.y]; + float diffFactorL = saturate(id.x - Offset); + float diffFactorR = saturate(ResX - (id.x + Offset)); + float resCol = (col1 * diffFactorR + col2 * diffFactorL) / ((diffFactorL && diffFactorR) == false ? 1 : 2); + MergedDepths[id.x + id.y * ResX] = resCol; +}