从rwtexture2d读取计算着色器统一的数据

发布于 2025-01-31 21:35:55 字数 4403 浏览 2 评论 0原文

我正在学习具有Unity的计算着着色器,但是在将翻译延迟转移到Compute着色器时,我遇到了一个错误。基本上,传输了2个纹理,RenderTextureCopytex。步骤如下:

  1. CopertexrenderTexture带有graphics.copytexture()
  2. 都将两个都传输到Compute Shader,以及一个新的呈现文化将从Copytex计算着
  3. 着色器完成,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:

  1. copyTex copy from renderTexture with Graphics.CopyTexture()
  2. Both are transferred to compute shader, and a new renderTexture would be calculated from copyTex
  3. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽心 2025-02-07 21:35:55

我发现使用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 used Copy[id.xy].a. Switched to Copy[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 accessing a actually access the alpha of the texture. As my alpha is always 1.0, the result are always white.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文