using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Rendering.Universal.Internal; using UnityEngine.UI; public class BlendShaderController : MonoBehaviour { private static string savePath = Application.streamingAssetsPath + '\\'; private const string filename = "dsitMap"; private const string ext = ".txt"; private Vector3 center { get { if (camera1 && camera2) return camera1.transform.position + camera1.transform.right * camera2.transform.localPosition.x * 0.5f; else return Vector3.zero; } } [Range(0.0f, 2.0f)] public float testDistance = 0.08f; public Shader DepthShader; public ComputeShader BlendShader; public Camera camera1; public Camera camera2; public int QuadResolution = 256; public float Multiplier; public RawImage Reciever; [Range(0, 1000)] public float OffsetMultiplier = 1000; public RenderTexture test; private RenderTexture depth1; private RenderTexture depth2; private RenderTexture cameraTexture1; private RenderTexture cameraTexture2; private RenderTexture Result; private int currentRes; private bool flag = false; private ComputeBuffer computeBuffer; private float[] resultArray; Thread savingThread; Task task1; Task task2; private int uvOffset; // Start is called before the first frame update void Start() { InitializeTextures(); InitializeComputeBuffer(); } void InitializeComputeBuffer() { computeBuffer = new ComputeBuffer(currentRes * currentRes, 1 * sizeof(float));//2 dimensional array of 1 value type of float } void InitializeTextures() { currentRes = QuadResolution; RenderTexture[] defaultTextures = CreateTextures(2, currentRes, currentRes); cameraTexture1 = defaultTextures[0]; cameraTexture2 = defaultTextures[1]; RenderTexture[] depthTextures = CreateTextures(2, currentRes, currentRes, true); depth1 = depthTextures[0]; depth2 = depthTextures[1]; Result = CreateTextures(1, currentRes, currentRes)[0]; Reciever.texture = Result; camera1.targetTexture = cameraTexture1; camera2.targetTexture = cameraTexture2; } public static RenderTexture[] CreateTextures(int count, int resX, int resY, bool depth = false) { RenderTexture[] result = new RenderTexture[count]; for (int i = 0; i < count; i++) { result[i] = new RenderTexture(resX, resY, 32, depth ? RenderTextureFormat.Depth : RenderTextureFormat.ARGBFloat); result[i].enableRandomWrite = !depth; result[i].Create(); } return result; } // Update is called once per frame void Update() { SetCameraDistance(testDistance); ComputeUVOffset(); if (Input.GetKeyDown(KeyCode.F)) { SetFlag(); } if (flag) { GenerateDepth(); } UpdateShader(cameraTexture1, cameraTexture2); if(Input.GetKeyDown(KeyCode.S)) { SaveTexture(); } if (Input.GetKeyDown(KeyCode.J)) { Debug.Log(GetDistanceByDepth()); } if (Input.GetKeyDown(KeyCode.K)) { Debug.Log(GetDistanceByRayCast()); } if (Input.GetKeyDown(KeyCode.T)) { camera1.targetTexture = test; camera1.RenderWithShader(DepthShader, "fragment"); camera1.targetTexture = cameraTexture1; } } void UpdateShader(RenderTexture tex1, RenderTexture tex2) { BlendShader.SetTexture(0, "Camera1", tex1); BlendShader.SetTexture(0, "Camera2", tex2); BlendShader.SetTexture(0, "Result", Result); BlendShader.SetFloat(Shader.PropertyToID("Offset"), uvOffset); BlendShader.SetFloat(Shader.PropertyToID("ResX"), Result.width); BlendShader.SetBuffer(0, "MonoChannelResult", computeBuffer); //BlendShader.SetTexture(0, "Test", test); BlendShader.Dispatch(0, Result.width / 8, Result.height / 8, 1); } void ComputeUVOffset() { if (camera1 && camera2) { if (Physics.Raycast(center, camera1.transform.forward, out var hit, 1000)) { Vector3 target = hit.point; Vector3 clipPoint1 = camera1.WorldToScreenPoint(target); Vector3 clipPoint2 = camera2.WorldToScreenPoint(target); float diff = clipPoint1.x - clipPoint2.x; uvOffset = (int)(diff * 0.5f); return; } } 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) { camera1.targetTexture = depth1; camera2.targetTexture = depth2; } else { camera1.targetTexture = cameraTexture1; camera2.targetTexture = cameraTexture2; } } public void SetFlag() { flag = !flag; SwapRenderTargets(); } private async void SaveTexture() { Debug.Log("Start Saving"); resultArray = new float[currentRes * currentRes]; computeBuffer.GetData(resultArray); Debug.Log("Data copied"); task1 = Task.Run(() => SerializeArray()); await task1; string result = task1.Result; task2 = SavingProcessAsync(result); await task2; } private async Task SavingProcessAsync(string data) { int filesCount = Directory.EnumerateFiles(savePath, filename + '*' + ext).Count(); await File.WriteAllTextAsync(savePath + filename + filesCount.ToString() + ext, data); Debug.Log("File saved"); } private string SerializeArray() { string result = string.Empty; for (int i = 0; i < resultArray.Length; i += currentRes) { result += string.Join(", ", resultArray[i..(i + currentRes)]) + '\n'; } return result; } private float GetDistanceByDepth() { resultArray = new float[currentRes * currentRes]; computeBuffer.GetData(resultArray); int idx = (int)(currentRes * (0.5f + currentRes * 0.5f)); float zDepth = resultArray[idx]; float far = camera1.farClipPlane; return zDepth * far; } private float GetDistanceByRayCast() { Vector3 position = camera1.transform.position + camera1.transform.right * camera2.transform.localPosition.x * 0.5f; if (Physics.Raycast(position, camera1.transform.forward, out var hit, 100)) { return hit.distance; } return -1; } public double[] GetIntrinsicParameters(Camera camera) { int width = camera.targetTexture != null ? camera.targetTexture.width : camera.pixelWidth; int height = camera.targetTexture != null ? camera.targetTexture.height : camera.pixelHeight; double fovRad = camera.fieldOfView * Math.PI / 180.0; double fy = (height * 0.5) / Math.Tan(fovRad * 0.5); double aspect = (double)width / height; double fx = fy * aspect; double cx = width * 0.5; double cy = height * 0.5; return new double[] { fx, 0, cx, 0, fy, cy, 0, 0, 1 }; } public float GetCameraDistance() { if (camera1 == null || camera2 == null) return -1f; return camera2.transform.localPosition.x; } public void SetCameraDistance(float distance) { if (camera1 == null || camera2 == null) return; Vector3 direction = camera1.transform.right; distance = Mathf.Max(0, distance); Vector3 camera2LocPos = camera2.transform.localPosition; camera2.transform.localPosition = new Vector3(distance, camera2LocPos.y, camera2LocPos.z); camera1.transform.position = center - direction * distance * 0.5f; } private void OnDisable() { computeBuffer.Release(); computeBuffer = null; } }