Last active
May 17, 2023 00:39
-
-
Save stonstad/8db9bfd80d189b55ec7d9edf810e18b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.IO; | |
using Unity.Collections; | |
using UnityEngine; | |
using UnityEngine.Rendering; | |
namespace Sample | |
{ | |
public struct Buffer | |
{ | |
public NativeArray<byte> NativeArray; | |
public uint Width; | |
public uint Height; | |
} | |
[RequireComponent(typeof(Camera))] | |
public class SampleColor : MonoBehaviour | |
{ | |
private RenderTexture _RenderTexture; | |
private Queue<Buffer> _InactiveBuffers = new Queue<Buffer>(); | |
private Queue<Buffer> _ActiveBuffers = new Queue<Buffer>(); | |
[Header("Settings")] | |
public Vector2 Scale = new Vector2(1.0f, 1.0f); | |
public Vector2 Offset = new Vector2(0.0f, 0.0f); | |
public float SizeScalar = 0.25f; | |
public int SampleN = 3; | |
[Header("Color")] | |
public Color SampledColor; | |
public Color InterpolatedColor; | |
public static Color SharedInterpolatedColor; | |
[Header("Debug")] | |
public bool WriteDebugOutput = false; | |
private Action<AsyncGPUReadbackRequest> _Callback; | |
public SampleColor() | |
{ | |
_Callback = OnCompleteReadback; | |
} | |
private void Update() | |
{ | |
InterpolatedColor = Color.Lerp(InterpolatedColor, SampledColor, SampleN * Time.deltaTime); | |
SharedInterpolatedColor = InterpolatedColor; | |
} | |
private void OnRenderImage(RenderTexture source, RenderTexture destination) | |
{ | |
if (Time.frameCount % SampleN != 0) | |
{ | |
RenderTexture.active = destination; | |
return; | |
} | |
int width = (int)(Screen.width * SizeScalar); | |
int height = (int)(Screen.height * SizeScalar); | |
if (_RenderTexture != null && (_RenderTexture.width != width || _RenderTexture.height != height)) | |
{ | |
Destroy(_RenderTexture); | |
_RenderTexture = null; | |
} | |
if (_RenderTexture == null) | |
{ | |
_RenderTexture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32); | |
_RenderTexture.useMipMap = true; | |
} | |
Graphics.Blit(source, _RenderTexture, Scale, Offset); | |
// acquire or create unused buffer with matching dimensions | |
Buffer buffer; | |
if (_InactiveBuffers.Count > 0) | |
{ | |
buffer = _InactiveBuffers.Dequeue(); | |
if (buffer.Width != width || buffer.Height != height) | |
{ | |
buffer.NativeArray.Dispose(); | |
buffer = CreateBuffer(width, height); | |
} | |
} | |
else | |
buffer = CreateBuffer(width, height); | |
_ActiveBuffers.Enqueue(buffer); | |
if (WriteDebugOutput) | |
AsyncGPUReadback.RequestIntoNativeArray(ref buffer.NativeArray, _RenderTexture, 0, _Callback); | |
else | |
AsyncGPUReadback.RequestIntoNativeArray(ref buffer.NativeArray, _RenderTexture, _RenderTexture.mipmapCount - 1, _Callback); | |
RenderTexture.active = destination; | |
} | |
private void OnDestroy() | |
{ | |
AsyncGPUReadback.WaitAllRequests(); | |
Destroy(_RenderTexture); | |
foreach (Buffer buffer in _ActiveBuffers) | |
buffer.NativeArray.Dispose(); | |
foreach (var buffer in _InactiveBuffers) | |
buffer.NativeArray.Dispose(); | |
} | |
private void OnCompleteReadback(AsyncGPUReadbackRequest request) | |
{ | |
if (request.hasError) | |
{ | |
Debug.Log("GPU readback error detected."); | |
return; | |
} | |
Buffer buffer = _ActiveBuffers.Dequeue(); | |
{ | |
// output render target texture | |
if (WriteDebugOutput && Time.renderedFrameCount % 20 == 0) | |
{ | |
using var encoded = ImageConversion.EncodeNativeArrayToPNG(buffer.NativeArray, _RenderTexture.graphicsFormat, buffer.Width, buffer.Height); | |
File.WriteAllBytes("output.png", encoded.ToArray()); | |
} | |
else | |
SampledColor = new Color(buffer.NativeArray[0] / 255.0f, buffer.NativeArray[1] / 255.0f, buffer.NativeArray[2] / 255.0f); | |
} | |
_InactiveBuffers.Enqueue(buffer); | |
} | |
private Buffer CreateBuffer(int width, int height) | |
{ | |
if (WriteDebugOutput) | |
return new Buffer() | |
{ | |
NativeArray = new NativeArray<byte>(width * height * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory), | |
Width = (uint)width, | |
Height = (uint)height | |
}; | |
else | |
return new Buffer() | |
{ | |
NativeArray = new NativeArray<byte>(1 * 1 * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory), | |
Width = (uint)width, | |
Height = (uint)height | |
}; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment