在计算着色器 Unity 中从 RWTexture2D 读取数据
Reading data from RWTexture2D in compute shader Unity
我正在学习使用 Unity 计算着色器,但是在 运行将 RenderTexture 传递给计算着色器时我遇到了一个错误。基本上,有 2 个纹理被 t运行 传递,renderTexture
和 copyTex
。步骤如下:
copyTex
从 renderTexture
复制 Graphics.CopyTexture()
- 两者都被 t运行 提交给计算着色器,并且新的
renderTexture
将从 copyTex
计算出来
- 计算着色器完成,
renderTexture
用于显示,然后一切循环
但是由于某些原因,运行 之后传递给计算着色器的 copyTex
是空白的。
这是主要的 C# 代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ComputeShaderTest : MonoBehaviour
{
public ComputeShader computeShader;
public RenderTexture renderTexture;
private RenderTexture copyTex;
[SerializeField] private Image image;
[SerializeField] private Vector2Int size = new Vector2Int(512, 512);
private Texture2D tex;
void Start()
{
InitializeRenderTexture();
StartCoroutine(SlowTest());
}
private void InitializeRenderTexture()
{
if (!renderTexture)
{
renderTexture = new RenderTexture(size.x, size.y, 24);
renderTexture.enableRandomWrite = true;
renderTexture.Create();
copyTex = new RenderTexture(size.x, size.y, 24);
copyTex.enableRandomWrite = true;
copyTex.Create();
}
//populate texture2d with all white and black patch in middle
Vector2Int pos = new Vector2Int(size.x / 2, size.y / 2);
tex = new Texture2D(size.x, size.y, TextureFormat.RGB24, false);
for (int i = 0; i < size.x; i++)
{
for (int j = 0; j < size.y; j++)
{
tex.SetPixel(i, j, Color.white);
}
}
for (int i = pos.x-10; i < pos.x+10; i++)
{
for (int j = pos.y-10; j < pos.y+10; j++)
{
tex.SetPixel(i, j, Color.black);
}
}
tex.Apply();
//copy to rendertexture
RenderTexture.active = renderTexture;
Graphics.Blit(tex, renderTexture);
}
IEnumerator SlowTest()
{
UpdateTexture2D();
while(true)
{
yield return new WaitForSeconds(1f);
TouchTest();
Debug.Log("Passed");
UpdateTexture2D();
}
}
private void UpdateTexture2D()
{
RenderTexture.active = renderTexture;
tex.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
tex.Apply();
image.material.mainTexture = tex;
}
private void TouchTest()
{
Vector2Int pos = new Vector2Int(size.x/2, size.y/2);
Graphics.CopyTexture(renderTexture, copyTex);
computeShader.SetInt("posX", pos.x);
computeShader.SetInt("posY", pos.y);
computeShader.SetInt("resolution", size.x);
computeShader.SetTexture(0, "Result", renderTexture);
computeShader.SetTexture(0, "Copy", copyTex);
computeShader.Dispatch(0, renderTexture.width / 8, renderTexture.height / 8, 1);
}
}
计算着色器:
#pragma kernel CSMain
RWTexture2D<float4> Result;
RWTexture2D<float4> Copy;
int posX;
int posY;
int resolution;
int dx[9] = {-1, 1, 1, 0, 1, -1, -1, 0, 0};
int dy[9] = {1, 0, 1, 1, -1, 0, -1, -1, 0};
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
int x = id.x, y = id.y;
if (x != 0 && x != resolution - 1 && y != 0 && y != resolution - 1)
{
if (Copy[id.xy].a > 0.5) //white
{
Result[id.xy] = float4(1, 0, 0, 1); //set to red
}
}
}
我可以断定 copyTex
是空白的,因为在复制之后,我用这段代码测试了它:
RenderTexture.active = copyTex;
tex.ReadPixels(new Rect(0, 0, copyTex.width, copyTex.height), 0, 0);
tex.Apply();
image.material.mainTexture = tex;
一切都很好;但是在计算着色器 运行 和 renderTexture
得到显示后,每个像素都是红色的(这意味着 if 语句被激活,并且所有这些像素之前都是白色的)。
因此无法操纵纹理来传输数据,我必须使用自定义 RWStructuredBuffer
来代替,否则我会搞砸什么地方?
更新:从这个问题 loading from RWTexture2D<float4> in a compute shader 中找到了关于 Load()
的信息。仍然无法从 Copy
.
获取任何类型的信息
我发现使用 Load()
或 []
运算符不是问题,而是访问的属性。我用了Copy[id.xy].a
。切换到 Copy[id.xy].x
一切正常。
float4
的这些属性在此处讨论:。基本上,.xyzw
等同于 .rgba
,因此访问 a
实际上是访问纹理的 alpha。因为我的 alpha 总是 1.0
,结果总是白色的。
我正在学习使用 Unity 计算着色器,但是在 运行将 RenderTexture 传递给计算着色器时我遇到了一个错误。基本上,有 2 个纹理被 t运行 传递,renderTexture
和 copyTex
。步骤如下:
copyTex
从renderTexture
复制Graphics.CopyTexture()
- 两者都被 t运行 提交给计算着色器,并且新的
renderTexture
将从copyTex
计算出来
- 计算着色器完成,
renderTexture
用于显示,然后一切循环
但是由于某些原因,运行 之后传递给计算着色器的 copyTex
是空白的。
这是主要的 C# 代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ComputeShaderTest : MonoBehaviour
{
public ComputeShader computeShader;
public RenderTexture renderTexture;
private RenderTexture copyTex;
[SerializeField] private Image image;
[SerializeField] private Vector2Int size = new Vector2Int(512, 512);
private Texture2D tex;
void Start()
{
InitializeRenderTexture();
StartCoroutine(SlowTest());
}
private void InitializeRenderTexture()
{
if (!renderTexture)
{
renderTexture = new RenderTexture(size.x, size.y, 24);
renderTexture.enableRandomWrite = true;
renderTexture.Create();
copyTex = new RenderTexture(size.x, size.y, 24);
copyTex.enableRandomWrite = true;
copyTex.Create();
}
//populate texture2d with all white and black patch in middle
Vector2Int pos = new Vector2Int(size.x / 2, size.y / 2);
tex = new Texture2D(size.x, size.y, TextureFormat.RGB24, false);
for (int i = 0; i < size.x; i++)
{
for (int j = 0; j < size.y; j++)
{
tex.SetPixel(i, j, Color.white);
}
}
for (int i = pos.x-10; i < pos.x+10; i++)
{
for (int j = pos.y-10; j < pos.y+10; j++)
{
tex.SetPixel(i, j, Color.black);
}
}
tex.Apply();
//copy to rendertexture
RenderTexture.active = renderTexture;
Graphics.Blit(tex, renderTexture);
}
IEnumerator SlowTest()
{
UpdateTexture2D();
while(true)
{
yield return new WaitForSeconds(1f);
TouchTest();
Debug.Log("Passed");
UpdateTexture2D();
}
}
private void UpdateTexture2D()
{
RenderTexture.active = renderTexture;
tex.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
tex.Apply();
image.material.mainTexture = tex;
}
private void TouchTest()
{
Vector2Int pos = new Vector2Int(size.x/2, size.y/2);
Graphics.CopyTexture(renderTexture, copyTex);
computeShader.SetInt("posX", pos.x);
computeShader.SetInt("posY", pos.y);
computeShader.SetInt("resolution", size.x);
computeShader.SetTexture(0, "Result", renderTexture);
computeShader.SetTexture(0, "Copy", copyTex);
computeShader.Dispatch(0, renderTexture.width / 8, renderTexture.height / 8, 1);
}
}
计算着色器:
#pragma kernel CSMain
RWTexture2D<float4> Result;
RWTexture2D<float4> Copy;
int posX;
int posY;
int resolution;
int dx[9] = {-1, 1, 1, 0, 1, -1, -1, 0, 0};
int dy[9] = {1, 0, 1, 1, -1, 0, -1, -1, 0};
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
int x = id.x, y = id.y;
if (x != 0 && x != resolution - 1 && y != 0 && y != resolution - 1)
{
if (Copy[id.xy].a > 0.5) //white
{
Result[id.xy] = float4(1, 0, 0, 1); //set to red
}
}
}
我可以断定 copyTex
是空白的,因为在复制之后,我用这段代码测试了它:
RenderTexture.active = copyTex;
tex.ReadPixels(new Rect(0, 0, copyTex.width, copyTex.height), 0, 0);
tex.Apply();
image.material.mainTexture = tex;
一切都很好;但是在计算着色器 运行 和 renderTexture
得到显示后,每个像素都是红色的(这意味着 if 语句被激活,并且所有这些像素之前都是白色的)。
因此无法操纵纹理来传输数据,我必须使用自定义 RWStructuredBuffer
来代替,否则我会搞砸什么地方?
更新:从这个问题 loading from RWTexture2D<float4> in a compute shader 中找到了关于 Load()
的信息。仍然无法从 Copy
.
我发现使用 Load()
或 []
运算符不是问题,而是访问的属性。我用了Copy[id.xy].a
。切换到 Copy[id.xy].x
一切正常。
float4
的这些属性在此处讨论:.xyzw
等同于 .rgba
,因此访问 a
实际上是访问纹理的 alpha。因为我的 alpha 总是 1.0
,结果总是白色的。