Transform feedback

Greetings:
I am trying to write a simple program to understand transform feedback: two spheres move randomly in world space and when they collide some effect happens. I want to use TF for collision detection which is simple in this case: the spheres collide if the distance between their centers <= sum of their radii.

The code to move the spheres works fine. Below is the TF part I’ve got to so far with the idea at each time step of first outputting the two centers to the TF buffer and checking the distance between them, then if there is no sphere collision draw normally, if there is then do effect.

Main:


init(void)
{...
static GLuint    TFId, TFBuffer; 
...
static const char* varyings[] = {"center0", "center1"};
...
glGenTransformFeedbacks(1, &TFId);
   glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFId);
   glGenBuffers(1, &TFBuffer); 
   glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, TFBuffer);
   glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1024, NULL, GL_DYNAMIC_COPY);
   glTransformFeedbackVaryings(programId, 2, varyings, GL_INTERLEAVED_ATTRIBS);

   glLinkProgram(programId); 
   glUseProgram(programId); 
...}

draw(void)
{...
   glUniform1ui(sphereNoLoc, 0);
   glMultiDrawElements(GL_TRIANGLE_STRIP... draws sphere 0);
   ...
   glUniform1ui(sphereNoLoc, 1);
   glMultiDrawElements(GL_TRIANGLE_STRIP... draws sphere 1);
...}

Vertex shader:

...
out vec3 center0, center1;
...
      // The uniform sphereNo is set to 0 before first sphere is drawn, 1 before second.
      if (sphereNo == 0) center0 = vec3(modelViewMat * vec4(0.0, 0.0, 0.0, 1.0));
      if (sphereNo == 1) center1 = vec3(modelViewMat * vec4(0.0, 0.0, 0.0, 1.0));

Now, I have a bunch of questions:

  1. Is the TF part correct so far? How do I complete it? I know there’s bunch of statements missing like glBegin/EndTransformFeedback(), maybe glBindBufferBase(), etc. I would really appreciate being told exactly how to arrange these given the objective of collision detection.

  2. Particularly, how do I access the values of center0 and center1 in the TF buffer to find the distance between them? (The red book has an example where they seem to use a texture buffer as TF and texelFetch() to randomly access it but don’t say how to set it all up; in any case, I would rather not use a texture buffer if it can be avoided.)

  3. If my understanding of how a vertex buffer works is correct, then there is an obvious inefficiency in the code above: the same value of centeri is going to be written into the TF for every vertex of the current sphere. How to avoid this?

Answer to these questions and any other comments you might have would be highly appreciated.

Thanks a lot,
Sam

The steps to perform TF are:

  1. define array of TF output-variable names you want to capture

  2. call glTransformFeedbackVaryings() for thaose variables

  3. link program

  4. create and bind buffer for TF

  5. call glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index, buffer) - if attributs are mixed in a single buffer, i.e. if GL_INTERLEAVED_ATTRIBS are used in a glTransformFeedbackVaryings() call, then you should bind only index 0. If multiple buffers are used (GL_SEPARATE_ATTRIBS), then for each index you should bind a separate buffer. If you want to use just a part of the buffer, then use glBindBufferRange() instead of glBindBufferBase().

  6. disable rasterization

  7. activate TF by calling glBeginTransformFeedback(GLenum primitiveMode). Depending on the chosen mode, TF expects appropriate primitives.

  8. call glDrawArrays() or similar drawing function

  9. exit TF mode by calling glEndTransformFeedback().

  10. enable rasterization.

P.S. Exercise you are trying to do is not suitable for TF. It can be done much more efficient on the CPU, since centers and radii probably originate from the CPU.

Thanks, Aleksandar.
So in my case center0 and center1 will write into TFBuffer. But after that how do I access their values at each step to check the distance between them?

Btw, this is not any school exercise:-) I am learning on my own. Another thing re your PS comment, since the centers are being transformed by modelViewMat in the VS it might make sense to do the distance checking there using a TF, if I understand correctly…

[QUOTE=sam_thedancer;1252076]Thanks, Aleksandar.
So in my case center0 and center1 will write into TFBuffer. But after that how do I access their values at each step to check the distance between them?[/QUOTE]
Transform-feedback copies the outputs from a vertex shader (or a geometry shader if active) to TFBuffer. You can get the data in the application using glGetBufferSubData() or glMapBuffer(). If you want to use it from a shader, you have to either bind it to a different binding point (e.g. GL_ARRAY_BUFFER) or create a texture from it with glTexBuffer() then bind the texture. Either way, you can’t read the data while it’s being used to store the transform-feedback output.

Thank you, GClements.
That clarifies the situation a lot. Now I understand why an intermediate buffer is needed to access TF output data.

Still if I might bug people a little more: how does one create a texture from the TF output data (a snippet of code would be highly appreciated)?

A buffer texture (which stretches the definition of “texture” a bit) can be created with glTexBuffer, e.g.:


GLuint TFTex;
glGenTextures(1, &TFTex);
glBindTexture(GL_TEXTURE_BUFFER,  TFTex);
glTexBuffer(GL_TEXTURE_BUFFER,  GL_RGB32F,  TFBuffer);

You can then access the data from within a shader with texelFetch(). Buffer textures don’t have filtering, so you can’t use anything which uses floating-point coordinates, e.g. texture().

Normal textures can be created from the contents of a buffer by binding the buffer to the GL_PIXEL_UNPACK_BUFFER target; subsequent calls to glTexImage2D() etc will read from the buffer rather than from application memory.

Thanks again.