从rwtexture2d读取计算着色器统一的数据
我正在学习具有Unity的计算着着色器,但是在将翻译延迟转移到Compute着色器时,我遇到了一个错误。基本上,传输了2个纹理,RenderTexture
和Copytex
。步骤如下:
Copertex
从renderTexture
带有graphics.copytexture()
- 都将两个都传输到Compute Shader,以及一个新的
呈现文化
将从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
获得显示后,每个像素都是红色的(这意味着激活了语句,并且所有这些像素之前均为白色)。
因此,无法操纵纹理以传输数据,而我必须使用自定义rwStructrucdBuffer
,或者我在某个地方弄乱了?
更新:从此问题中找到有关load()
的信息:从rwtexture2d&lt; float4&gt;加载在计算着色器中。仍然无法从复制
获得任何类型的信息。
I'm learning compute shader with Unity, but I've encountered a bug when transferring RenderTexture to the compute shader. Basically, there're 2 texture being transferred, renderTexture
and copyTex
. The steps are as follow:
copyTex
copy fromrenderTexture
withGraphics.CopyTexture()
- Both are transferred to compute shader, and a new
renderTexture
would be calculated fromcopyTex
- Compute shader finished,
renderTexture
is used to display, then everything looped again
But for some reason, the copyTex
after transferred to the compute shader is blank.
This is the main C# code:
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);
}
}
And the compute shader:
#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
}
}
}
I can conclude the copyTex
is blank because right after copy, I tested it with this piece of code:
RenderTexture.active = copyTex;
tex.ReadPixels(new Rect(0, 0, copyTex.width, copyTex.height), 0, 0);
tex.Apply();
image.material.mainTexture = tex;
and everything show up fine; but after the compute shader ran and the renderTexture
got display, every pixels were red (which means the if statement activated, and all those pixels are previously white).
So texture can't be manipulated to transfer data and I have to use a custom RWStructuredBuffer
instead or I mess up somewhere?
Update: Found out about Load()
from this question: loading from RWTexture2D<float4> in a compute shader. Still can't get any type of info from Copy
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我发现使用
load()
或 [] 操作员不是问题,而是访问的属性。我使用复制[id.xy] .a
。切换到复制[id.xy] .x
,一切都很好。float4
的这些属性在此处讨论: hsls float1,.. .. 。,float4及其字段。基本上,.xyzw
等效于.rgba
因此访问a
实际上访问纹理的alpha。由于我的alpha始终是1.0
,因此结果始终为白色。I've found out that using
Load()
or[]
operator isn't the problem, but the properties accessed. I usedCopy[id.xy].a
. Switched toCopy[id.xy].x
and everything is fine.These properties of
float4
is discussed here: HSLS float1,..., float4 and its fields. Basically,.xyzw
is the equivalent of.rgba
so accessinga
actually access the alpha of the texture. As my alpha is always1.0
, the result are always white.