将SSBO绑定到片段着色器 [英] Bind an SSBO to a fragment shader

查看:89
本文介绍了将SSBO绑定到片段着色器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个SSBO,它存储屏幕上每个像素的vec4颜色值,并在主循环之前由计算着色器预先填充这些值.

I have a an SSBO which stores vec4 colour values for each pixel on screen and is pre populated with values by a compute shader before the main loop.

我现在正在尝试将这些数据显示在屏幕上,我想这涉及使用片段着色器(尽管如果您知道一种更好的方法,我欢迎您提出建议)

I'm now trying to get this data onscreen which I guess involves using the fragment shader (Although if you know a better method for this I'm open to suggestions)

因此,我试图将缓冲区或至少其中的数据获取到片段着色器,以便可以将每个片段的颜色设置为缓冲区中的相应值,但是找不到任何方法?

So I'm trying to get the buffer or at least the data in it to the fragment shader so that I can set the colour of each fragment to the corresponding value in the buffer but I cannot find any way of doing this?

有人告诉我可以将SSBO绑定到片段着色器,但是我不知道该怎么做?我的其他想法是将数据从SSBO移到纹理上,但我也无法解决

I have been told that I can bind the SSBO to the fragment shader but I don't know how to do this? Other thoughts I had was somehow moving the data from the SSBO to a texture but I can't work that out either

更新:

为响应thokra的出色回答,以下是设置我的缓冲区的代码:

In response thokra's excellent answer and following comments here is the code to set up my buffer:

//Create the buffer
GLuint pixelBufferID;
glGenBuffers(1, &pixelBufferID);

//Bind it
glBindBuffer(GL_SHADER_STORAGE_BUFFER, pixelBufferID);

//Set the data of the buffer
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * window.getNumberOfPixels, new vec4[window.getNumberOfPixels], GL_DYNAMIC_DRAW);

//Bind the buffer to the correct interface block number
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, pixelBufferID);

然后,我调用计算着色器,并且此部分正常工作,我检查数据是否已正确填充.然后在我的片段着色器中,作为一个测试:

Then I call the compute shader and this part works, I check the data has been populated correctly. Then in my fragment shader, just as a test:

layout(std430, binding=0) buffer PixelBuffer
{
    vec4 data[];
} pixelBuffer

void main()
{
    gl_FragColor = pixelBuffer.data[660000];
}

我注意到,索引越高似乎花费的时间越来越长,所以在660000时,它实际上并不需要花费很长的时间就崩溃.

What I've noticed is that it seems to take longer and longer the higher the index so at 660000 it doesn't actually crash its just taking an silly amount of time.

推荐答案

存储缓冲区的工作方式与统一缓冲区非常相似.为了了解它们的工作原理,我建议使用类似.主要区别在于存储缓冲区可以容纳大量数据,并且您可以从中随机读取并写入.

Storage buffers work quite similarly to uniform buffers. To get a sense of how those work I suggest something like this. The main differences are that storage buffer can hold substantially higher amounts of data and the you can randomly read from and write to them.

有多种工作方式,但我将从最基本的角度开始-着色器内部的接口块.我将仅描述使用接口块时可能性的子集,但这应该足以使您入门.

There are multiple angles of working this, but I'll start with the most basic one - the interface block inside your shader. I will only describe a subset of the possibilities when using interface blocks but it should be enough to get you started.

与普通"变量相反,您不能在全局范围内指定 buffer 变量.您需要根据第4.3.7节-GLSL 4.40规范使用接口模块(第4.3.9节-GLSL 4.40规范):

In contrast to "normal" variables, you cannot specify buffer variables in the global scope. You need to use an interface block (Section 4.3.9 - GLSL 4.40 Spec) as per Section 4.3.7 - GLSL 4.40 Spec:

缓冲区限定符可用于声明接口块(第4.3.9节接口块"),然后将其称为着色器存储块.在全局范围(块外)声明缓冲区变量是编译时错误.

The buffer qualifier can be used to declare interface blocks (section 4.3.9 "Interface Blocks"), which are then referred to as shader storage blocks. It is a compile-time error to declare buffer variables at global scope (outside a block).

请注意,上述部分与 ARB扩展略有不同

Note that the above mentioned section differs slightly from the ARB extension.

因此,要访问存储缓冲区中的内容,您需要在片段着色器(或任何其他适用的阶段)内定义一个 buffer 接口块:

So, to get access to stuff in your storage buffer you'll need to define a buffer interface block inside your fragment shader (or any other applicable stage):

layout (binding = 0) buffer BlockName
{
  float values[]; // just as an example
}; 

与其他没有实例名称的块一样,您将引用缓冲区存储,就像 values 位于全局范围内一样,例如:

Like with any other block without an instance name, you'll refer to the buffer storage as if values were at global scope, e.g.:

void main()
{
  // ...

  values[0] = 1.f;

  // ...
}    

在应用程序级别,您现在唯一需要知道的是 buffer 接口块 BlockName 在程序后具有绑定 0 已成功链接.

On the application level the only thing you now need to know is that the buffer interface block BlockName has the binding 0 after the program has been successfully linked.

在使用您的应用程序创建存储缓冲区对象之后,首先使用

After creating a storage buffer object with your application, you first bind the buffer to the binding you specified for the corresponding interface block using

glBindBufferBase(GLenum target​, GLuint index​, GLuint buffer​);

用于将完整的 buffer 绑定到 index

glBindBufferRange(GLenum target​, GLuint index​, GLuint buffer​, GLintptr offset​, GLsizeiptr size​);

用于将由偏移量和许多 buffer 指定的子集绑定到 index .

for binding a subset specified by an offset and a number of of the buffer to the index.

请注意, index 指的是在 layout 中为相应的接口块指定的 binding .

Note that index refers to the binding specified in your layout for the corresponding interface block.

基本上就是这样.请注意,存储缓冲区大小,绑定点数,最大存储块大小等都有一定的限制.我请您参考GL和GLSL规范中的相应部分.

And that's basically it. Be aware that there are certain limits for the storage buffer size, the number of binding points, maximum storage block sizes and so on. I refer you to the corresponding sections in the GL and GLSL specs.

此外, ARB扩展中有一个最小的示例.阅读扩展的问题部分通常还可以提供对所公开功能及其背后原理的进一步了解.我建议您通读它.

Also, there is a minimal example in the ARB extension. Reading the issues sections of extension also often provides further insight into the exposed functionality and the rationale behind it. I advise you to read through it.

如果遇到问题,请发表评论.

Leave a comment if you run into problems.

这篇关于将SSBO绑定到片段着色器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆