Accessing VBO in vertex shaders
category: code [glöplog]
Hi,
I'm trying to get access to a VBO from inside a vertex shader. At the moment I have a valid buffer which I bind as
glBindBuffer(GL_ARRAY_BUFFER, BufferA);
This buffer is quite large (about 0.5m - I hope that's not a problem). I want to access this in the vertex shader as I would with an array (of xyzw structs or consecutive floats) so that I can iterate through them. Is this possible?
I thought that something like this would be the first step (in GLSL):
layout(std140) uniform TheVBO {
float x;
float y;
float z;
float w;
};
and
float myx = TheVBO[index].x
and then accessing through (in C:)
int ind=glGetUniformBlockIndex (programHandle, "TheVBO");
(I would assume I know what to do from that point on). But nothing works of course.... any ideas?
I'm trying to get access to a VBO from inside a vertex shader. At the moment I have a valid buffer which I bind as
glBindBuffer(GL_ARRAY_BUFFER, BufferA);
This buffer is quite large (about 0.5m - I hope that's not a problem). I want to access this in the vertex shader as I would with an array (of xyzw structs or consecutive floats) so that I can iterate through them. Is this possible?
I thought that something like this would be the first step (in GLSL):
layout(std140) uniform TheVBO {
float x;
float y;
float z;
float w;
};
and
float myx = TheVBO[index].x
and then accessing through (in C:)
int ind=glGetUniformBlockIndex (programHandle, "TheVBO");
(I would assume I know what to do from that point on). But nothing works of course.... any ideas?
You can use TBOs and access the buffer via texelFetch.
Besides you could also use SSBOs (if you really need structs) or "Images"(imageStore/imageLoad).
If you only need read access and your struct is nothing really fancy I would go for TBOs.
Setup the proper uniforms for the samplers &
use a gsamplerBuffer then to access your texture via texelFetch.
You can directly fetch vec4's.
You could first create the "VBO" as TBO and then use glBindBuffer in order to use it as GL_ARRAY_BUFFER if you need to do so. TBOs can be up to 512 MB in recent NV implementations.
Besides you could also use SSBOs (if you really need structs) or "Images"(imageStore/imageLoad).
If you only need read access and your struct is nothing really fancy I would go for TBOs.
Code:
struct TBO {
TBO() : tbo(0), texture(0) {}
GLuint tbo;
GLuint texture;
};
TBO createTBO(GLuint sizeInBytes, const void* data, GLuint usage, GLuint internalformat) {
TBO tbo;
glGenBuffers(1, &tbo.tbo);
glBindBuffer(GL_TEXTURE_BUFFER, tbo.tbo);
glBufferData(GL_TEXTURE_BUFFER, sizeInBytes, data, usage);
glGenTextures(1, &tbo.texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, tbo.texture);
glTexBuffer(GL_TEXTURE_BUFFER, internalformat, tbo.tbo);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
return tbo;
}
void bindTBO(TBO& tbo, unsigned int texture) {
glActiveTexture(texture);
glBindTexture(GL_TEXTURE_BUFFER, tbo.texture);
}
Setup the proper uniforms for the samplers &
use a gsamplerBuffer then to access your texture via texelFetch.
You can directly fetch vec4's.
You could first create the "VBO" as TBO and then use glBindBuffer in order to use it as GL_ARRAY_BUFFER if you need to do so. TBOs can be up to 512 MB in recent NV implementations.
(You are currently trying to bind the thing as UBO or something like that... I don't think that's so much of a good idea)
I think I get it. I need to pass as a texture buffer, read as 4xfloat and sample in the shader as if it was a normal texture. I ll try tm , many thanks. Lets hope it works.
It usually works ;). If not, feel free to ask for more details.
I can't believe my luck but this combination seems to work (for future reference):
--------- Initialize
glGenBuffers(1, &BufferA);
glBindBuffer(GL_ARRAY_BUFFER, BufferA);
glBindBuffer(GL_TEXTURE_BUFFER, BufferA);
glBufferData(GL_ARRAY_BUFFER, sizeof(MyVertex)*m_X*m_Y, 0, GL_STREAM_DRAW);
glGenTextures (1,&TextureBufferA);
glBindTexture (GL_TEXTURE_BUFFER,TextureBufferA);
glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA32F_ARB,BufferA);
glBindBuffer(GL_ARRAY_BUFFER, 0);
--- then
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_BUFFER, TextureBufferB);
my_sampler_uniform_location = glGetUniformLocation(programHandle, "Positions");
glUniform1i(my_sampler_uniform_location, 5);
--- and in shader
uniform samplerBuffer Positions;
texelFetch (Positions, gl_VertexID+1).xyz;
Not sure about that
glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA32F_ARB,BufferA);
though... shouldn't that be TextureBufferA? (in which case it doesn't work)
--------- Initialize
glGenBuffers(1, &BufferA);
glBindBuffer(GL_ARRAY_BUFFER, BufferA);
glBindBuffer(GL_TEXTURE_BUFFER, BufferA);
glBufferData(GL_ARRAY_BUFFER, sizeof(MyVertex)*m_X*m_Y, 0, GL_STREAM_DRAW);
glGenTextures (1,&TextureBufferA);
glBindTexture (GL_TEXTURE_BUFFER,TextureBufferA);
glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA32F_ARB,BufferA);
glBindBuffer(GL_ARRAY_BUFFER, 0);
--- then
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_BUFFER, TextureBufferB);
my_sampler_uniform_location = glGetUniformLocation(programHandle, "Positions");
glUniform1i(my_sampler_uniform_location, 5);
--- and in shader
uniform samplerBuffer Positions;
texelFetch (Positions, gl_VertexID+1).xyz;
Not sure about that
glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA32F_ARB,BufferA);
though... shouldn't that be TextureBufferA? (in which case it doesn't work)
Nope it shouldn't - a TBO consists of a texture (you call it TextureBufferB) and a "bufferobject" (BufferA). You can bind that buffer thing as almost everything else (e.g. GL_ARRAY_BUFFER). glTexBuffer expects the "bufferobject" of the TBO as parameter. Everything should be fine.
Replace TextureBufferB with TextureBufferA in my post above.
You are using two TBOs? ;) B should also be A in your post in the "--then" snippet.
You are using two TBOs? ;) B should also be A in your post in the "--then" snippet.
yeah, everything seems to be fine apart from the fact that it fails to work sometimes - and this is pretty much not easy to reproduce. For example:
texelFetch (TheVBO,0).xyz;
this will work
but not this:
texelFetch (TheVBO,1).xyz;
although I have seen under slightly different code both working.
It is as if I'm reading from the same buffer I'm writing to, although it can't be the case as I've tried all possible combinations.
texelFetch (TheVBO,0).xyz;
this will work
but not this:
texelFetch (TheVBO,1).xyz;
although I have seen under slightly different code both working.
It is as if I'm reading from the same buffer I'm writing to, although it can't be the case as I've tried all possible combinations.
basically the very same code will work one time but not the other.
Well it should work. I don't know your complete codebase, so it is kind of hard to judge where that happens.
If you want to discuss it in private - you can find me on IRC in one of the common demoscene channels on IRCnet.
If you want to discuss it in private - you can find me on IRC in one of the common demoscene channels on IRCnet.
thanks for the offer, I think I can find out myself what is wrong - as you say, the code is pretty straightforward (for setting up the buffer objects). I believe that there must be some problem with the ping-ponging of the buffers - I am using 2. It's just a shame that the very same code produces different results each time, something that I haven't seen before!
I actually wonder what happens if you go out of bounds with the texelFetch?
Navis: undefined behaviour. as far as i remember, under nvidia you either get corrupt output or total lack of thereof - depends what you're doing.
yeah I guess that must be it, so nothing to do with the VBOs themselves... :-)
anyway, thanks again, I think I solved it. Coming to a demo near you soon...
Wheeeeeeeeeee! Le Navis is BACK! :D