PDA

View Full Version : strange problm (accessing an ivec4 in vertex shdr)



mobeen
12-28-2010, 11:37 PM
Hi all,
I am trying to do a mass spring vertex shader using VBO and TBO. The mass connection information is stored as GLint as follows,

GLint connections[MAX_MASSES][4] = {
{-1,1,5,0},{1,2,6,0},{2,3,7,1},{3,4,8,2},...,};
In the vertex shader, the connection is attached to attribute location 2 in an ivec4 as follows,

layout(location=2) in ivec4 connection;
when i access the attribute connection like this or using .x to fetch the top neighbor from the TBO using

texelFetchBuffer(tex_position_mass, connection[0]); I get wrong result. However, if i change GLint to GLfloat when attaching the attributelocation (glVertexAttribPointer), change my connection var to float (vec4) and then cast it to int in the vertex shader, the output is correct.
Note that I have already checked the TBO and it contains the correct information.
Why doesn't it work with ivec4?

Regards,
Mobeen

mobeen
12-29-2010, 02:46 AM
Just to append another question to this thread, if i have a single VBO and my data is just plain positions which i render as GL_POINTS, do i need VAO? I cant really seem to understand when I should use a VAO along with my VBO currently i m not using it but I need to understand when VAO should be used. The information about using VAO is scarce (I found some information on the opengl Wiki but thats about it). Where can i get more info. on this topic?

Dark Photon
12-29-2010, 07:50 AM
do i need VAO?
If you're using compatibility profile, no. You can ignore them.

If you're using core profile, then I seem to recall at some point they disallowed the implicit VAO 0. If you still don't want to use VAOs, IIRC the work-around is to just create a VAO, bind it, and then just forget about VAOs.

But don't forget about them. When you're optimizing, you may want to come back and make better use of them. They can sometimes give you a speed-up, though not as much as with display lists or NVidia bindless.

carsten neumann
12-29-2010, 09:00 AM
I get wrong result. However, if i change GLint to GLfloat when attaching the attributelocation (glVertexAttribPointer)


Have you tried to use glVertexAttribIPointer for integer attributes? IIUC it should not be necessary, but you never know... ;)

mobeen
12-29-2010, 09:38 PM
HI carsten neumann,
Thanks for ur reply. Yes I have tried using vertexattributepointer for integer attributes but i dont know why but it doesnot work.

Regards,
Mobeen

mobeen
12-30-2010, 04:31 AM
OK I am trying to follow the discussion of mass spring simulation on page 417 OpenGL superbible. The book says I need 2 TBOs, 2 VBOs and 2VAOs. So I do my setup as follows,

void createVBO()
{
//fill the vertices
int count = 0;
for(int i=0;i<MAX_MASSES;i++) {
vertices[i].position_mass[0]=vSpringMassVerts[i][0];
vertices[i].position_mass[1]=vSpringMassVerts[i][1];
vertices[i].position_mass[2]=vSpringMassVerts[i][2];
vertices[i].position_mass[3]=vSpringMassVerts[i][3];

vertices[i].velocity[0]=0;
vertices[i].velocity[1]=0;
vertices[i].velocity[2]=0;
vertices[i].velocity[3]=0;

vertices[i].connection[0]=connections[i][0];
vertices[i].connection[1]=connections[i][1];
vertices[i].connection[2]=connections[i][2];
vertices[i].connection[3]=connections[i][3];
}


// create buffer object
glGenVertexArrays(2, vaoID);
glGenBuffers( 2, vboID);

glBindVertexArray(vaoID[0]);
glBindBuffer( GL_ARRAY_BUFFER, vboID[0]);
glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &amp;(vertices[0]), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, position_mass));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, velocity));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, connection));

glBindVertexArray(vaoID[1]);
glBindBuffer( GL_ARRAY_BUFFER, vboID[1]);
glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &amp;(vertices[0]), GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, position_mass));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, velocity));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MyVertex), (const GLvoid*) offsetof(MyVertex, connection));

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindBuffer( GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

gltCheckErrors();
}

void createTBO(size_t size) {
glGenTextures( 2, texID);
glGenBuffers( 2, tboID);
for(int i=0;i<2;i++) {
glBindVertexArray(vaoID[i]);
glBindBuffer( GL_TEXTURE_BUFFER, tboID[i]);
glBufferData( GL_TEXTURE_BUFFER, size, vSpringMassVerts, GL_STATIC_DRAW);
glActiveTexture(GL_TEXTURE0+i);
glBindTexture( GL_TEXTURE_BUFFER, texID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[i]);
}
}

And as given in the sample codes of the book, I render my mass spring system using,


glUseProgram(massSpringShader);
glUniformMatrix4fv(mvpLocation, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glUniform4fv(colorLocation,1, vRed);

glUniform1f(tLocation,0.01);
glUniform1f(kLocation, k);
glUniform1f(cLocation, c);
glUniform1f(rLengthLocation, l);


gltCheckErrors();

glBindVertexArray( vaoID[readID]);
glActiveTexture( GL_TEXTURE0+readID);
glBindTexture( GL_TEXTURE_BUFFER, texID[readID]);
glUniform1i( glGetUniformLocation( massSpringShader, "tex_position_mass"), readID);
glBindBuffer( GL_ARRAY_BUFFER, vboID[readID]);
glDrawArrays(GL_POINTS, 0, MAX_MASSES);


int tmp = readID;
readID=writeID;
writeID = tmp;

glBindBuffer( GL_ARRAY_BUFFER, 0);
glBindVertexArray( 0);

glUseProgram(0);

However, the output just gives me flickering nodes which donot move. Am I doing this correctly? As said in the book, the output would be written to the other TBO/VBO pair. One thing I am not sure is how do i assign the output of the vertex shader to a specific TBO/VBO? And here is the vertex shader (copied from the book.


#version 330
precision highp float;

#extension EXT_gpu_shader4 : require
in vec4 position_mass;
in vec4 velocity;
in vec4 connection;

uniform mat4 MVP;
uniform samplerBuffer tex_position_mass;
uniform float t, k, c, rest_length;

const vec3 gravity = vec3(0,0,0);


out Vertex {
vec4 position_mass;
vec4 velocity;
}vertex;


void main(void)
{
vec3 p = position_mass.xyz;

float m = position_mass.w;
vec3 u = velocity.xyz;
vec3 F;
vec3 v = u;
vec3 s = vec3(0);
if(connection[0] != -1) {
F = gravity + c*u;
for(int i=0;i<4;i++) {
if(connection[i]!=gl_VertexID) {
vec3 q = texelFetchBuffer(tex_position_mass, int(connection[i])).xyz;
vec3 d = q-p;
float x = length(d);
F += -k*(rest_length-x)*normalize(d);
}
}
vec3 a = F/m;
s = u*t +0.5*a*t*t;
v = u+a*t;
}
vertex.position_mass = vec4(p+s, m);
vertex.velocity = vec4(v,0);
gl_Position = MVP*vec4(p+s, 1.0);

Regards,
Mobeen

ugluk
12-30-2010, 04:44 AM
How can VAO give a speed-up if you use the VBO caching scheme you so nicely explained? Is there a choice then between using multiple VBOs and VAOs and one VBO and no VAOs?

Which choice is better?

mobeen
12-30-2010, 04:48 AM
Hi ugluk,
Currently, I am just trying to implement the mass spring example missing from the opengl superbible examples. I m not looking on optimization yet. Its just to make it work first which is not working at the moment).

Thanks,
Mobeen

mobeen
12-30-2010, 05:28 AM
I know the reason of flickering. Its due to the vao[1] which is empty. I dont understand why it is empty when I am doing the same thing as I did for vao[0]. Any insights would be appreciated. I am also checking the error bit and it is clear no GL errors.

Thanks,
Mobeen

kRogue
12-30-2010, 08:20 AM
I know the reason of flickering. Its due to the vao[1] which is empty. I dont understand why it is empty when I am doing the same thing as I did for vao[0]. Any insights would be appreciated. I am also checking the error bit and it is clear no GL errors.



You have:



for(int i=0;i<2;i++) {
glBindVertexArray(vaoID[i]);
glBindBuffer( GL_TEXTURE_BUFFER, tboID[i]);
glBufferData( GL_TEXTURE_BUFFER, size, vSpringMassVerts, GL_STATIC_DRAW);
glActiveTexture(GL_TEXTURE0+i);
glBindTexture( GL_TEXTURE_BUFFER, texID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[i]);
}


which makes texture unit $i source from texID[$i]... VAO's only "store" what to use for attributes and index buffers, not any texture jazz. When you switch between the VAO's, you also need to:
once bind texID[i] to GL_TEXTURE0+i AND during rendering set the uniform: glUniform1i(location_of_tex_position_mass, current_i)
Alternatively, one can also:

once set lUniform1i(location_of_tex_position_mass, 0) during rendering change what is bound to GL_TEXTURE0

Also, if you use ivecN in a shader, you MUST use glVertexAttribIPointer.

Dark Photon
12-30-2010, 10:53 AM
How can VAO give a speed-up if you use the VBO caching scheme you so nicely explained?
I was thinking of the more common case for most folks out there (probably) where you're bouncing back and forth between batch data preloaded into static VBOs (where pointers and offsets are essentially fixed per batch). I suspect most folks aren't using the streaming approach yet.

But even with the streaming VBO approach, while VAOs aren't of much benefit on the first batch render (when you had to load it into the VBO), they should be of good use perf-wise on subsequent renders (reuse case; where the batch is already loaded up at a particular offset and ready to rip).

Guess I haven't considered that before much because I use NV bindless, bindless seems to net you more perf++ than VAOs on reuse, and combining bindless and VAOs doesn't net you even more perf++. But yeah, if you aren't using bindless, worth trying VAOs.

mobeen
12-30-2010, 08:21 PM
Hi kRouge,
Thanks for the reply


Also, if you use ivecN in a shader, you MUST use glVertexAttribIPointer.
Indeed, this solved the ivec4 issue. Thanks for pointing this out.


which makes texture unit $i source from texID[$i]... VAO's only "store" what to use for attributes and index buffers, not any texture jazz. When you switch between the VAO's, you also need to:

•once bind texID[i] to GL_TEXTURE0+i AND
•during rendering set the uniform: glUniform1i(location_of_tex_position_mass, current_i)

Alternatively, one can also:


•once set lUniform1i(location_of_tex_position_mass, 0)
•during rendering change what is bound to GL_TEXTURE0

As you said, I have changed the render calls as follows but it is still giving me the same result.


void createTBO(size_t size) {
glGenTextures( 2, texID);
glGenBuffers( 2, tboID);
for(int i=0;i<2;i++) {
glBindBuffer( GL_TEXTURE_BUFFER, tboID[i]);
glBufferData( GL_TEXTURE_BUFFER, size, vSpringMassVerts, GL_STATIC_DRAW);
glBindTexture( GL_TEXTURE_BUFFER, texID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[i]);
}

gltCheckErrors();
}

//and in render func.
glUseProgram(massSpringShader);
glUniformMatrix4fv(mvpLocation, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
//all uniforms set here
gltCheckErrors();
glBindVertexArray( vaoID[readID]);
glActiveTexture( GL_TEXTURE0+readID);
glBindTexture( GL_TEXTURE_BUFFER, texID[readID]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[readID])glUniform1i( glGetUniformLocation( massSpringShader, "tex_position_mass"), readID);
glDrawArrays(GL_POINTS, 0, MAX_MASSES);

//swap read/write buffers
int tmp = readID;
readID=writeID;
writeID = tmp;

glBindBuffer( GL_ARRAY_BUFFER, 0);
glBindVertexArray( 0);
glUseProgram(0);

kRogue
12-31-2010, 10:33 AM
Comment, you do not need to call:



glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[readID])

in your render loop, unless you are calling glBufferData on the tboID[] at each render. To be precise:


Init:



glGenBuffers(2, tboID);
glGenTextures(2, texID);

for(int i=0,i<2;++i)
{
glBindBuffer( GL_TEXTURE_BUFFER, tboID[i]);
glBufferData( GL_TEXTURE_BUFFER, size, vSpringMassVerts, GL_STATIC_DRAW);
glBindTexture( GL_TEXTURE_BUFFER, texID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F_ARB, tboID[i]);
}



Render loop:



glUseProgram(massSpringShader);
glUniformMatrix4fv(mvpLocation, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
//all uniforms set here
gltCheckErrors();
glBindVertexArray( vaoID[readID]);
glActiveTexture( GL_TEXTURE0+readID);
glBindTexture( GL_TEXTURE_BUFFER, texID[readID]);
glUniform1i( glGetUniformLocation( massSpringShader, "tex_position_mass"), readID);
glDrawArrays(GL_POINTS, 0, MAX_MASSES);

//swap read/write buffers
int tmp = readID;
readID=writeID;
writeID = tmp;

glBindBuffer( GL_ARRAY_BUFFER, 0);
glBindVertexArray( 0);
glUseProgram(0);



If you are updating the data of the buffer objects tboID[] at each frame (and that code is not shown) then unless you are resizing the data, call glBufferSubData to change the values (calling glBufferData "allocates" and sets and has additional rules when said buffer object is used as a source for a GL_TEXTURE_BUFFER texture). Also to be paranoid I would change:



glUniform1i( glGetUniformLocation( massSpringShader, "tex_position_mass"), readID);


to at init:



tex_position_mass_location=glGetUniformLocation( massSpringShader, "tex_position_mass");
assert(tex_position_mass_location!=-1);


and to at render:



glUniform1i(tex_position_mass_location, readID);



Also you really do not need to be changing what texture unit you are using, just what texture buffer object, so you can simplify your code to:

Init:


tex_position_mass_location=glGetUniformLocation( massSpringShader, "tex_position_mass");
assert(tex_position_mass_location!=-1);

//use texture unit 0:
glProgramUniform1i(massSpringShader, tex_position_mass_location, 0);


Render:


glUseProgram(massSpringShader);
glUniformMatrix4fv(mvpLocation, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
//all uniforms set here
gltCheckErrors();
glBindVertexArray( vaoID[readID]);
glActiveTexture( GL_TEXTURE0);
glBindTexture( GL_TEXTURE_BUFFER, texID[readID]);
glDrawArrays(GL_POINTS, 0, MAX_MASSES);

//swap read/write buffers
int tmp = readID;
readID=writeID;
writeID = tmp;

glBindBuffer( GL_ARRAY_BUFFER, 0);
glBindVertexArray( 0);
glUseProgram(0);

mobeen
01-01-2011, 10:24 PM
Hi krogue,
Thanks for ur input. I have made all the changes u have said.

I debugged the application using gDebugger and the texture view shows me the correct data for all of the vbos. It tells me that I have 5 vbos in all, 1 grid vbo, 2 vbos attached to array buffer, 2 vbos attached to texture buffer. The contents of these buffers are also correct i.e that data is filled in correctly.

So in the rendering loop i bind to the first vao i.e. vaoID[0], while ping ponging between the two TBOS and pass in my simulation parameters and it works fine. See the snapshot from the app. So this problem is solved. Thanks for your inputs guys.
http://www3.ntu.edu.sg/home2007/mova0002/test/mass_spring.png

EDIT: I dont need two vaos. Only one vao is needed alongwith 2 vbos and 2 tbos.

mobeen
01-02-2011, 08:59 AM
The output seemed correct however using gDebugger, I notice that both of my vbos have data updated per frame however, the texbo data is not updated. Do i need to call glBufferSubData to update the data to the texBO myself?

kRogue
01-03-2011, 02:23 AM
glBufferData and glBufferSubData copy the values into the buffer object, they do not link the buffer object to the pointer you pass.

If you are changing the values of "vSpringMassVerts", and you want those changes visible then you do need to call glBufferSubData to copy those new values into the buffer object. At this point, then, you are streaming data into GL through the buffer object, and chances are your hint GL_STATIC_DRAW for that buffer object is not what you want.. likely GL_STREAM_DRAW. If you are streaming LOTS of data in, the you are to embark into the land of optimal streaming data to GL through buffer objects: ping-ponging, mapping and more!

mobeen
01-03-2011, 02:38 AM
Hi kRogue,
Thanks for your input. Actually, this is what I m doing. I have 2 vaos. Each vao has vboP for position (attrib. loc. 0) and vboV for velocities (attrib. loc. 1). the common connection infor. is in vboC (attribute loc. 2). For convenience the position vbos are also attached to the texture buffer. The vertex shader outputs to location 0 (new position) and 1 (new velocity). I m trying to do as described in opengl superbible 5th ed. (page 417) but since the source code is missing, i thought it would be a good exercise. Now on the same page the book says that


"we can read from one set of buffers and write to the other on one pass. and then swap the buffers around so that the data moves back and forth from one buffer to the other."
What I donot get is how do i read and write to the same attribute location. How do i output to any other location (say 4 or 5) which is not attached to my vaos?

alder
01-03-2011, 11:45 AM
You should either use transform feedback to capture the updated values to the 'write' buffer, or render to texture via a frame buffer object (not sure if there are limitations in rendering to a texture backup by a buffer object, or would you then need to use ReadPixles).

Alfonse Reinheart
01-03-2011, 12:21 PM
The vertex shader outputs to location 0 (new position) and 1 (new velocity).

Unless you are actually using transform feedback (in which case you would need to bind buffers to the transform feedback locations), or rendering to a buffer texture, the vertex shader cannot output to a buffer object.

mobeen
01-03-2011, 06:54 PM
Hi Alfonse and alder,
Thanks for your replies I will check transform feedback and rendering to a buffer texture.

I must say the book OpenGL superbible 5th edition is not structured properly. The mass spring system is given in chapter 11 (the whole vertex shader is given) but no implementation details (buffer handling and vaos) is discussed. The authors say on page 417 that


The code to set this up isn't particularly complex but is repetitive. A complete implementation can be found on the books web site. The example application includes the code to create and initialize the buffers, perform double buffering and visualize the result. ..

However there is no demo code in both the book CD source code nor the SVN repository. I have emailed the authors but there has been no reply by them.

I wanted to see it in action so I started working on the implementation. I learned buffer objects myself. I just saw that the vaos and buffer management is given in a later chapter along with transform feedback. It should have been introduced first and then the mass spring system should have been detailed later after the explanation of the buffer objects.

Thanks guys for your valuable inputs.

Regards,
Mobeen

Alfonse Reinheart
01-03-2011, 08:19 PM
I must say the book OpenGL superbible 5th edition is not structured properly. The mass spring system is given in chapter 11 (the whole vertex shader is given) but no implementation details (buffer handling and vaos) is discussed.

To be fair, buffer objects are dealt with in Chapter 8, going by the table of contents on Amazon. Though I honestly can't imagine what was in the previous 7 chapters if it took them that long to explain buffer objects. Especially since you can't render in core OpenGL without them.

I don't have the book, but I cannot for the life of me think of what would possess them to introduce blending in Chapter 3, but hold off on a detailed discussion of buffer objects until Chapter 8, when you need buffer objects to render at all. And antialiasing? Is someone really ready to understand what antialiasing is all about when they've just rendered their first triangle? Before they even really grok the framebuffer?

I don't want to judge the Superbible based on its table of contents. But it seems to have a very strange layout and order for presenting information. And do they actually discuss sRGB textures and framebuffers without a substantive discussion of linear space vs. gamma-correct space, and the effect this has on lighting?

I guess this is because the Superbible tends to be more focused on imparting OpenGL knowledge than on teaching specific graphics skills. That is, how to use OpenGL features rather than why to use them.