A simple question concerning Attribute-arrays

#1

Hi there,

as i now have a transform-feedback function, that fills a VAO with data for rendering, i would like to reealy feedback it. But somehow it seems, that i still have some problems in understanding how to really use all this array-objects.

I understood, how to fill an array by CPU or - in between - with feedback-varyings. But inside my rendering-shader i was still using the old gl_xxx-system.

In my working feedback-function, that i postet here some days ago, i use this:


        GLint tffInput     = glGetAttribLocation (curPRG, (char*)list[2]);      CheckGL("glGetAttribLocation");  
        glEnableVertexAttribArray (tffInput);                                   CheckGL("glEnableVertexAttribArray"); 
        glVertexAttribPointer     (tffInput, 1, GL_FLOAT, GL_FALSE, 0, 0);      CheckGL("glVertexAttribPointer"); 

and this:


        glBeginTransformFeedback(GL_POINTS);                                    CheckGL("glBeginTransformFeedback");              
            glDrawArrays     (GL_POINTS, 0, numPrims);                          CheckGL("glDrawArrays"); 
        glEndTransformFeedback();                                               CheckGL("glEndTransformFeedback"); 

to fill VAO with GL_T2F_N3F_V3F-data, that is drawn later.

In this special case, the data in the source VAO (that is “drawn”, with the glDrawArrays-call) is not needed. The InstanceID and the horizonatal and vertical size, of the object to be created, are enough, to generate the vertex-data. Therefore i use an emty VAO to be “drawn”, which is generatrd like this:


        GLuint vbo;
        glGenBuffers         (1, &vbo);
        glBindBuffer         (GL_ARRAY_BUFFER, vbo);
        glBufferData         (GL_ARRAY_BUFFER, numPrims, NULL/*data*/, GL_STATIC_DRAW);  CheckGL("VBO-Creation");  

What i want to do now is, to use the data given to the shader, but not only one float per call. Per call, i want to access the whole GL_T2F_N3F_V3F-data previously generated, to manipulate it. Best would be to have it in a single array (“in float in_data[8]”) or in a struct. But somehow (i thought about for a while now) i don’t find the correct solution, which must be quiet simple.
The VBO exists and i can draw it normally, but i don’t get the data in my feedback-shader. Only single floats i undersood.

Would be nice, if someone could give me a hint, or the (possibly) three lines of code that are needed, to do this…

Best,
Frank

#2

Update:

The code that i use currently is this:


            GLint tffInput     = glGetAttribLocation (curPRG, "tff_in");            CheckGL("glGetAttribLocation");  

            glEnableVertexAttribArray (tffInput+0);                                            CheckGL("glEnableVertexAttribArray"); 
            glVertexAttribPointer     (tffInput+0, 2, GL_FLOAT, GL_FALSE, 48, 0);              CheckGL("glVertexAttribPointer"); 

            glEnableVertexAttribArray (tffInput+1);
            glVertexAttribPointer     (tffInput+1, 4, GL_FLOAT, GL_FALSE, 48, 0);     CheckGL("glVertexAttribPointer"); 

            glEnableVertexAttribArray (tffInput+2);
            glVertexAttribPointer     (tffInput+2, 3, GL_FLOAT, GL_FALSE, 48, 0);    CheckGL("glVertexAttribPointer"); 

            glEnableVertexAttribArray (tffInput+3);
            glVertexAttribPointer     (tffInput+3, 3, GL_FLOAT, GL_FALSE, 48, 0);    CheckGL("glVertexAttribPointer"); 

The input of the shader is:


in float tff_in[
      12   //GL_T2F_C4F_N3F_V3F
    ];

The shader return what it shold return if all inputs are zero, except of the first two values, which really feed back. All other values are obvously not passed to the shader.

#3

The input of the shader is:

That’s not how arrays of vertex shader inputs work. Each element of your array is a separate attribute.

#4

Thank you for replieing…

I know that i missunderstood something here, but the link (which i alread know) dosn’t really help me.

I tried a lot of versions since hours, like i.e. a shader with this input:


in vec2 T2F_in;
in vec4 C4F_in;
in vec3 N3F_in;
in vec3 V3F_in;

and c-code like this:


        int stride = 0;
        for (int i = 0; i < list.size; i+=2)     stride += list[i][0];   stride = stride * sizeof(GLfloat);
        for (int i = 0; i < list.size; i+=2) {   int pos = 0;
            GLint tffInput     = glGetAttribLocation (curPRG, (char*)list[1]);            CheckGL("glGetAttribLocation");  
            glEnableVertexAttribArray (tffInput);                                            CheckGL("glEnableVertexAttribArray"); 
            glVertexAttribPointer     (tffInput, list[i][0], .............

Also i red a lot of references, but sometimes my english is not good enough. Also i did not stdied programming. So smetimes the terminology is too complicated for me.

But what sould i do? The program crashes, or - as best result - i’ve got the first two values.

Im tired of recomiling hundrets of times with different values for stride and offset and different versions of inputs.

My complete function (full fo trash) is currentl this one:


void ParsePrepareFeedback (clsControl *Control, clsLst &list) {                 CheckGL("Errors left in cue");
  // wxMessageBox("ParsePrepareFeedback");
  
        if (!Control->cVAO) {      //     wxMessageBox("ParsePrepareFeedback 2");                          //return;
            Control->cVAO  = new clsVAO (1000, GL_T2F_C4F_N3F_V3F);               
            GLfloat *fp = Control->cVAO->Open (1000, GL_T2F_C4F_N3F_V3F);   
            //wxMessageBox(tostr(Control->cVAO->NumV * Control->cVAO->Stride));                 
            for (int i=0; i < Control->cVAO->NumV * Control->cVAO->Stride /  sizeof(float); i++) fp[i] = 0;
            Control->cVAO->Close();
        }
     //   wxMessageBox("ParsePrepareFeedback 3");
        int numPrims = Control->cVAO->NumV;                                 
        int numVerts = numPrims   * 1 /*GL_POINTS*/;
        int bufSize  = numVerts   * Control->cVAO->Stride/*GL_T2F_C4F_N3F_V3F*/;        CheckGL("Error left in cue"); 
      
////  VAO erzeugen (ist standard. Ggf. wird default benutzt)
//      GLuint vao;
//      glGenVertexArrays    (1, &vao);
//      glBindVertexArray    (vao);                                             CheckGL("VAO-Creation");  

//    VBO von array" erzeugen
        GLuint vbo = Control->cVAO->VBO;
//        glGenBuffers         (1, &vbo);
        glBindBuffer         (GL_ARRAY_BUFFER, vbo);
//        glBufferData         (GL_ARRAY_BUFFER, numPrims, NULL/*data*/, GL_STATIC_DRAW);  CheckGL("VBO-Creation");  
     //   GLfloat *sfp = Control->cVAO->Open();
//    Übergabeadress für Attribut "inValue" ermitteln
        int stride = 0;
//        for (int i = 0; i < list.size; i+=2)     stride += list[i][0];   stride = stride * sizeof(GLfloat);
        Print("Stride: "+tostr(stride));
//        for (int i = 0; i < list.size; i+=2) {   int pos = 0;
            GLint tffInput     = glGetAttribLocation (curPRG, "tff_in");            CheckGL("glGetAttribLocation");  
//            Print(wxString("Index of ") + (char*)list[i+1] + ": "+tostr(tffInput));
            glEnableVertexAttribArray (tffInput+0);                                            CheckGL("glEnableVertexAttribArray"); 
            glVertexAttribPointer     (tffInput+0, 2, GL_FLOAT, GL_FALSE, 48, 0);              CheckGL("glVertexAttribPointer"); 
            glEnableVertexAttribArray (tffInput+1);
            glVertexAttribPointer     (tffInput+1, 4, GL_FLOAT, GL_FALSE, 48, (GLvoid*) (2 * sizeof(GLfloat)) );     CheckGL("glVertexAttribPointer"); 
            glEnableVertexAttribArray (tffInput+2);
            glVertexAttribPointer     (tffInput+2, 3, GL_FLOAT, GL_FALSE, 48, (GLvoid*) (6 * sizeof(GLfloat)) );    CheckGL("glVertexAttribPointer"); 
            glEnableVertexAttribArray (tffInput+3);
            glVertexAttribPointer     (tffInput+3, 3, GL_FLOAT, GL_FALSE, 48, (GLvoid*) (9 * sizeof(GLfloat)) );    CheckGL("glVertexAttribPointer"); 
//        }
      //    Control->cVAO->Close();
       glBindBuffer         (GL_ARRAY_BUFFER, vbo);   
//        return;  
//    Gleich großen Zielbuffer erzeugen mit
        GLuint tbo;
        glGenBuffers         (1, &tbo);
        glBindBuffer         (GL_ARRAY_BUFFER, tbo);
        glBufferData         (GL_ARRAY_BUFFER, bufSize, NULL, GL_STATIC_READ);  CheckGL("TBO-Creation");  
        
//    PROZESS:
        glEnable             (GL_RASTERIZER_DISCARD);                           CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glBindBufferBase     (GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);            CheckGL("glBindBufferBase"); 

        glBeginTransformFeedback(GL_POINTS);                                    CheckGL("glBeginTransformFeedback");              
            glDrawArrays     (GL_POINTS, 0, numPrims);                          CheckGL("glDrawArrays"); 
        glEndTransformFeedback();                                               CheckGL("glEndTransformFeedback"); 
    
        glFlush              ();                                                CheckGL("glFlush"); 
   
//    Alles freigeben, bis auf tbo mit Ergebnis
//        glBindBuffer         (GL_ARRAY_BUFFER, 0);
//        glDeleteBuffers      (1, &vbo);
//      glDeleteVertexArrays (1, &vao);

//    Ergebnis in cVAO übertragen:
        if (!Control->cVAO)   Control->cVAO = new clsVAO (numVerts, GL_T2F_C4F_N3F_V3F);
        GLfloat *fp = Control->cVAO->Open (numVerts, GL_T2F_C4F_N3F_V3F);   
        glGetBufferSubData   (GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufSize, fp );
        Print("
" + tostr(fp[ 0]) + " - " + tostr(fp[ 1]) 
            + "
" + tostr(fp[ 2]) + " - " + tostr(fp[ 3]) + " - " + tostr(fp[ 4]) + " - " + tostr(fp[ 5]) 
            + "
" + tostr(fp[ 6]) + " - " + tostr(fp[ 7]) + " - " + tostr(fp[ 8]) 
            + "
" + tostr(fp[ 9]) + " - " + tostr(fp[10]) + " - " + tostr(fp[11]));
        Control->cVAO->Close ();
        
//    tbo freigeben        
        glDeleteBuffers      (1, &tbo);

        glUseProgram         (0);        
}

But as i alread said (and as you maybe see) i tried around a lot, without success…

Best,
Frank

#5

That would result in 12 separate attributes. So you’d need 12 glVertexAttribPointer() calls. Vertex shader inputs cannot be structures; you’d need to either use 4 separate variables, or an array of 4 vec4s (the attribute arrays don’t actually need to have 4 components; missing components will be set to 0 for y and z and 1 for w).

#6

I’m not sure if i understand you.

You mean, that i have to call both (“glEnableVertexAttribArray” and “glVertexAttribPointer”) 12 times?
What is with the second parameter of glVertexAttribPointer? Always 1 because 12 separate attributes with size of one float?
What is ith the last parameter if data alredy exists? Should i give physical pointers?

#7

You mean, that i have to call both (“glEnableVertexAttribArray” and “glVertexAttribPointer”) 12 times?
What is with the second parameter of glVertexAttribPointer? Always 1 because 12 separate attributes with size of one float?

That’s what in float tff_in[12]; means. It means you want twelve attributes, each of which is a single float. I even linked you to a page that told you that, and you said that you already knew that.

It’s likely that this is not what you really want. But you haven’t really explained what exactly you want, so it’s hard to help you.

#8

[QUOTE=art-ganseforth;1292678]I’m not sure if i understand you.

You mean, that i have to call both (“glEnableVertexAttribArray” and “glVertexAttribPointer”) 12 times?
What is with the second parameter of glVertexAttribPointer? Always 1 because 12 separate attributes with size of one float?
[/QUOTE]
Yes. [var]in float tff_in[12][/var] declares 12 separate attributes, ttf_in[0] to ttf_in[11] inclusive. Those attributes will be consecutively numbered, so you’d only need to call glGetAttribLocation(“ttf_in”) and can then add 0…11 to the result. Each attribute will be a single float; if you pass a value other than 1 for the size parameter of glVertexAttribPointer(), the additional components will be ignored.

You can have multiple glVertexAttribPointer() calls all use the same data, with each one having a “pointer” offset by the appropriate multiple of sizeof(float). But this will actually use a vec4 for for each float, so if you want additional attributes, you’ll hit the limit on the maximum number of attributes (GL_MAX_VERTEX_ATTRIBS, must be at least 16) much earlier than if you pass each of T/C/N/V as a vector attribute (which would only use 4 attributes rather than 12).

You should store the data in a buffer object, bind the buffer to the GL_ARRAY_BUFFER target, and pass the offset within the buffer, cast to a GLvoid*.

In the compatibility profile, you can pass a pointer to client memory provided that no buffer is bound to the GL_ARRAY_BUFFER target.

#9

Just tried it immideatly, and now i have a result :wink:

I think wouldn’t have found this by myself. For me this seems so redundat, that i would not have considered this.

On the other hand, this is quiet good for me, because there are only two parameters needed: The name of the in-variable and the number of floats.
I think most that i really need, i have now (even if there is still much to learn)…

By the way (not so important): As written i use this code


        glBeginTransformFeedback(GL_POINTS);                                    CheckGL("glBeginTransformFeedback");              
            glDrawArrays     (GL_POINTS, 0, numPrims);                          CheckGL("glDrawArrays"); 
        glEndTransformFeedback();                                               CheckGL("glEndTransformFeedback"); 

for the feedback. I wondered but failed to imagine, what will happen if i use other types then GL_POINT and if this useful for something.

And one more thing: I had a short try with a version, where source and destination-array are identical. That seemed not to work. Am i right, that his is not possible?

Best,
Frank

#10

The type passed to glBeginTransformFeedback() must match the type of primitives generated by draw calls. If no geometry shader is active, then glBeginTransformFeedback(GL_POINTS) requires all draw calls to use GL_POINTS.

If you’re using transform feedback as a substitute for compute shaders, there isn’t any reason to use any other mode. Using GL_LINES or GL_TRIANGLES (with the same mode for both glBeginTransformFeedback() and the draw call) will produce identical results but require the number of vertices to be multiples of 2 or 3 respectively. Other modes (line strips/loops, triangle strips/fans) will just duplicate some of the vertices.

It’s not possible; §13.2.2 says:

Buffers should not be bound or in use for both transform feedback and other purposes in the GL. Specifically, if a buffer object is simultaneously bound to a transform feedback buffer binding point and elsewhere in the GL, any writes to or reads from the buffer generate undefined values. Examples of such bindings include ReadPixels to a pixel buffer object binding point and client access to a buffer mapped with MapBuffer. Commands that attempt to read or write to an active and unpaused transform feedback buffer will have undefined results. Generating an [var]INVALID_OPERATION[/var] error is recommended in this case.

#11

Best! Thank you. So i’ll prepare the possibility to call the feedback-function with a parameter for the draw-type, to be used later (still dreaming of compute-shaders, but it’ll take surely at least one more year until…)

For the moment, i’ve lots to do, to implement and debug, what i learned the last days.

By the way: Here’s screenshot of the UI of my program with the new tff-generated VBO (i’m a little bit proud about…)
[ATTACH=CONFIG]1857[/ATTACH]

Best,
Frank