View Full Version : Transform feedback and VAO + Indices

12-21-2013, 01:03 PM
Hey, it seems, like i don't quite get how does TF interact with VAO's and GL_ELEMENT_ARRAY_BUFFER's. I try to make my animation system to work with transform feedback. So i have initial VAO1 containing all necessary attributes and i want to draw it with transform feedback enabled, outputting results into ARRAY_BUFFER, which is bound to another VAO2 used to finally draw.

Here's initialization of TF and related buffers:

//transform feedback
if(isAnimated) {
//setup transform feedback
glGenTransformFeedbacks(1, &transformFeedbackObject);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackObject);

//create output VAO
glGenVertexArrays(1, &animationOutputVAO);

glGenBuffers(1, &animationOutputBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, animationOutputBufferObject);
glBufferData(GL_ARRAY_BUFFER, modelStorage[modelId].data.numVertices * sizeof(float), NULL, GL_DYNAMIC_COPY);

glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, animationOutputBufferObject); //bind as TF output

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelStorage[modelId].data.indexObject); //use original indices

//i thought, maybe i can't just bind orginal element array here, but this doesn't make any difference:
/*glGenBuffers(1, &animationOutputIndexObject);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, animationOutputIndexObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, modelStorage[modelId].data.indices.size() * sizeof(short), &modelStorage[modelId].data.indices[0], GL_DYNAMIC_DRAW);*/

//vx, nx, tx
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * attributeStride, BUFFER_OFFSET(0));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * attributeStride, BUFFER_OFFSET(12));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * attributeStride, BUFFER_OFFSET(24));

//bone ids, bone weight
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * attributeStride, BUFFER_OFFSET(32));
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(float) * attributeStride, BUFFER_OFFSET(44));


glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
disclamer: some function call order is a consequence of a bit of desperation.

Drawing to TF:

glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackObject);

currentShader.applyProgram(15, 0);
glUniformMatrix4fv(currentShader.uniform_bones, maxNumBones, GL_FALSE, &boneMatrices[0]);

glBindVertexArray(modelStorage[modelId].data.vertexArrayObject); //source VAO

for(unsigned s = 0, off = 0; s < modelStorage[modelId].data.numSurfaces; s++)
glDrawElements(GL_TRIANGLES, modelStorage[modelId].data.numIndices[s], GL_UNSIGNED_SHORT, BUFFER_OFFSET(off));
off += modelStorage[modelId].data.numIndices[s] * sizeof(short);

glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);

So... When i draw animationOutputVAO with glDrawElements, i get just a mess of triangles. Any clues on what am i doing wrong? The problem is that couple of examples on TF i found are used for particles and they don't use neither VAO, nor element buffers, so i'm not sure how do i accomplish what i'm trying to do. So i'm resorting to forum and heavy documentation + source code googling.

Dark Photon
12-21-2013, 02:36 PM
Hey, it seems, like i don't quite get how does TF interact with VAO's and GL_ELEMENT_ARRAY_BUFFER's.

Separate TF from the latter two in your mind. TF is just another way to run the graphics pipeline.

VAOs capture all of the vertex array and element array bindings and enables within the VAO. The ELEMENT_ARRAY_BUFFER binding is one piece of information stored within a VAO. Bind a VAO and all of the bindings and enables stored within it are re-bound and re-enabled.

Search for the "vertex array object state" table in the OpenGL 4.4 Spec (http://www.opengl.org/registry/doc/glspec44.compatibility.pdf). You'll notice there there are no bindings here related to transform feedback. So basically you don't need your TF object bound while you are initializing your VAO state. It shouldn't make any difference as nothing about it is stored within the VAO.

The TF object is what captures your TF buffer binding. Search for the "transform feedback state" table in the spec for what's captured within a TF object.

12-21-2013, 11:29 PM
Hey, Dark Photon, thanks for the clarification. That's how i kind of expected things to be.

I've also forgot to post vertex shader i use for TF. it's going to be a lot bigger, but it outputs garbage even with a passthrough VS:

#version 330
layout(location=0) in vec3 inVertex;
layout(location=1) in vec3 inNormal;
layout(location=2) in vec2 inTexCoord;

layout(location=3) in vec3 inBoneIds;
layout(location=4) in vec3 inBoneWeight;

out vec3 outVertex;
out vec3 outNormal;
out vec2 outTexCoord;

out vec3 outBoneIds;
out vec3 outBoneWeight;

void main() {
outVertex = inVertex;
outNormal = inNormal;
outTexCoord = inTexCoord;
outBoneIds = inBoneIds;
outBoneWeight = inBoneWeight;

i do specify all the TF varyings and program links correctly. also, if i fill output buffer with correct data and disable tranform feedback, it renders correctly. but as soon as i execute drawing with transform feedback, it's filled with garbage.

upd: if i use glDrawArrays to render TF output, it also draws random garbage.

12-22-2013, 09:51 AM
fixed it. it turns out i've actually forgot about one of my vertex attributes, ruining output vertex layout. it does work, but the fact that i need to use glDrawArrays is really inconvenient. i would really like to have same drawing code for animated and non-animated objects, only binding different VAO's. - nevermind me being a silly dummy. i was drawing to transform feedback with glDrawElements, so it was, predictably, unfolding indices. if i draw with glDrawArrays, it doesn't happen and i can use pre-setup VAO with original indices to draw results.