- Home /
Use compute shader to convert RenderTexture to Vector4 array
I am making a picture analyzer which needs the accurate values of color. When I tried to parse float values from compute shader to my script via Texture2D, it's not accurate. For example, when parsing float 0.5 via the r channel texture, it will first convert to value 127, which represents "half of a channel". Then in my script, I use Texture2D.GetPixel(x, y) to read the color, it will convert 127 to 127/255 back. So float 0.5 from compute shader to my script will be converted to 0.498039……, which isn't I expected.
Therefore, I want to use an array to read the output value but not the texture.
However, It has some problem. I do a test. Here are my codes:
Compute shader
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> input;
RWStructuredBuffer<float4> output;
[numthreads(16,16,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
uint index = id.x * 16 + id.y;
//There should be some operations here, then I get the final value
//Operations.....................
//Then get the result here
float4 finalValue = input[id.xy];
output[index] = finalValue;
}
Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestParse : MonoBehaviour
{
public ComputeShader shader;
public RenderTexture input;
public Material material;
private Vector4[] output;
private ComputeBuffer buffer;
private int kernel;
private Texture2D texture;
// Start is called before the first frame update
void Start()
{
output = new Vector4[16 * 16];
buffer = new ComputeBuffer(16 * 16, 4 * sizeof(float));
kernel = shader.FindKernel("CSMain");
input.enableRandomWrite = true;
shader.SetTexture(kernel, "input", input);
shader.SetBuffer(kernel, "output", buffer);
texture = new Texture2D(16, 16, TextureFormat.RGBA32, false);
texture.filterMode = FilterMode.Point;
material.SetTexture("_MainTex", texture);
}
// Update is called once per frame
void Update()
{
shader.Dispatch(kernel, 16, 16, 1);
buffer.GetData(output);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int index = i * 16 + j;
texture.SetPixel(i, j, new Color(output[index].x, output[index].y, output[index].z, output[index].w));
}
}
texture.Apply();
}
private void OnDisable()
{
buffer.Release();
}
}
In this example, I can parse the RenderTexture to the compute shader, then copy the value to a Vector4 array, then set the color of the test Texture2D based on the array. So in theory, the colors of the test Texture2D will be the same as the colors of the input RenderTexture.
However, this is what I get:
Does anyone knows how to solve this problem? If it can't be solve, do you know why? Thanks.
Answer by kosowski · Sep 22, 2020 at 05:25 PM
If your input texture is 16x16, and your numthreads is [numthreads(16,16,1)], I think you should call Dispatch like Dispatch(kernel, 1, 1, 1).
Unity reference has a short description on this https://docs.unity3d.com/ScriptReference/ComputeShader.Dispatch.html
Your answer
Follow this Question
Related Questions
Writing to render texture in for loop not working (metal) 0 Answers
Problem with ComputeShader and RHalf RenderTexture 0 Answers
Can Image Effects Be Applied To Render Textures? 0 Answers
Prevent Render Texture clearing 1 Answer
How do I create a reflection render texture and assign it to be used as part of a shader? 0 Answers