Jump to content

  • Log In with Google      Sign In   
  • Create Account

Getting data from multiple vertex data


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 Maxjen   Members   -  Reputation: 191

Like
0Likes
Like

Posted 30 December 2012 - 06:40 AM

Hi,

I'm trying to write a 2D map editor. It is based on triangles. The problem I have is drawing the selection. Here is how it should look like when I select one vertex:
selection.png

What I have is Triangle class which creates a vertex buffer where all the triangle vertex positions, colors and texture coordinates are. I have a separate class where I store the data for the selection. It has a stl map which maps two integers (vertex indices, lower first) to a structure which contains two bool values to decide if the vertices are selected or not. Now all I need is a way too use that information too draw the edges like in the picture. So for every entry in that map I want to draw a line which gets the positions of the vertices from the vertex buffer of the Triangle class and the information whether or not the vertices are selected from e.g. another vertex buffer in the Selection class. The problem is that I don't know how or if it is possible to bind two vertex buffer at once. If anyone knows or can think of a better way to do this please tell me.

Oh, the picture is not exactly what I want. In my case there should be a third half selected edge that goes down from the selected vertex.

Edited by Maxjen, 30 December 2012 - 07:26 AM.


Sponsor:

#2 haegarr   Crossbones+   -  Reputation: 4586

Like
0Likes
Like

Posted 30 December 2012 - 08:45 AM

The kind of primitive is not encoded in the VBO directly but given as argument in the glDraw* routines. You can of course use the same VBO for rendering triangle faces followed by rendering lines of the same mesh. All you need is a separate index buffer (IBO) for the lines, although it is usually a good thing to draw the faces using indices, too. Then the latter IBO addresses the vertices in the VBO in a face manner, while the former one does so in a line manner.



#3 Waterlimon   Crossbones+   -  Reputation: 2636

Like
1Likes
Like

Posted 30 December 2012 - 09:30 AM

If you mean you want 2 buffers, the vertices, and lets say colors to tell you the color of the vertex (you only need a boolean or something like that but i thought it would be nice to be able to use different colors etc. for other things) you can probably do it using a VAO

 

Im not perfectly familiar with using OpenGL though so it might be possible without one too.


o3o


#4 haegarr   Crossbones+   -  Reputation: 4586

Like
1Likes
Like

Posted 30 December 2012 - 09:48 AM

If you mean you want 2 buffers, the vertices, and lets say colors to tell you the color of the vertex (you only need a boolean or something like that but i thought it would be nice to be able to use different colors etc. for other things) you can probably do it using a VAO

Indeed is it possible to pass the geometric vertex attributes in one VBO (still sticking to VBOs here because the OP mentioned them explicitly) and the color attribute in another one, assembling them on the GPU to yield in the full featured vertex. This is more a question of how the selection is encoded when sighted from the GPU side. For example, the selection can be processed on the CPU in a way that writes the color in dependence to the selection state into the 2nd VBO. This would allow to load just the color to the graphics card instead of the entire vertex data. However, whether this makes sense depends on the purpose of the selection: In an editor it is probable that the geometry is changed on the selected vertices. Hence loading the geometry as well may be done anyway, so that splitting into 2 VBOs may introduce needless work.



#5 Waterlimon   Crossbones+   -  Reputation: 2636

Like
0Likes
Like

Posted 30 December 2012 - 09:54 AM

If you mean you want 2 buffers, the vertices, and lets say colors to tell you the color of the vertex (you only need a boolean or something like that but i thought it would be nice to be able to use different colors etc. for other things) you can probably do it using a VAO

 

Indeed is it possible to pass the geometric vertex attributes in one VBO (still sticking to VBOs here because the OP mentioned them explicitly) and the color attribute in another one, assembling them on the GPU to yield in the full featured vertex. This is more a question of how the selection is encoded when sighted from the GPU side. For example, the selection can be processed on the CPU in a way that writes the color in dependence to the selection state into the 2nd VBO. This would allow to load just the color to the graphics card instead of the entire vertex data. However, whether this makes sense depends on the purpose of the selection: In an editor it is probable that the geometry is changed on the selected vertices. Hence loading the geometry as well may be done anyway, so that splitting into 2 VBOs may introduce needless work.

But if you keep the line drawing and vertex drawing in separate buffers, wouldnt that allow you to use the same vertex position buffer for the triangles AND the lines?

Because id imagine if they are interleaved, you would either need 2 copies of the vertex position, 1 with line data mixed in, or you would need to keep the line data there even when youre not using it (not much of a problem probably though)


o3o


#6 haegarr   Crossbones+   -  Reputation: 4586

Like
0Likes
Like

Posted 30 December 2012 - 10:28 AM

...

But if you keep the line drawing and vertex drawing in separate buffers, wouldnt that allow you to use the same vertex position buffer for the triangles AND the lines?
Because id imagine if they are interleaved, you would either need 2 copies of the vertex position, 1 with line data mixed in, or you would need to keep the line data there even when youre not using it (not much of a problem probably though)

It is also possible when the vertex data are not separate (which seems ATM be the case when looking at the OP). The problem with discussing this is that we don't know so far how drawing is actually done.

 

For sure, a clean way under the condition of not replicating data would be to use 3 VBOs (1 with the data shared between face and line drawing, 1 with the data used for face drawing only, and 1 with the data used for line drawing only), and 2 IBOs (1 for face drawing and 1 for line drawing). On the other hand there is the possibility to ignore data passed in, at least easily when using shader scripts.

 

We don't know the frequency of selections, the frequency of alterations to the vertex data, the amount of vertex data (but this is probably relatively small-sized because the OP mentioned a 2D map editor), and how drawing is performed, but I assume that it is possible performance-wise that the entire vertex data is updated on each iteration.

 

BTW: To go to the extremes, it is also possible to draw the faces and lines in a single pass by using appropriate shader scripts. For each pixel when being computed in the fragment shader, one can determine the distance from the edge of the face and use it to decide whether to pass the face color or the line color to the framebuffer. However, this all is speculative as long as the OP doesn't tell / ask for more ;)



#7 Waterlimon   Crossbones+   -  Reputation: 2636

Like
0Likes
Like

Posted 30 December 2012 - 10:43 AM

Though i wouldnt suggest doing it that low level.

 

What if you want to make the game objects out of multiple triangles for some technical reason?

 

I think you should instead make a higher level "triangle" object and use that data for the line drawing, so that you dont even need to render the triangles if you dont want to, isntead of relying on the triangle rendering data.


o3o


#8 haegarr   Crossbones+   -  Reputation: 4586

Like
0Likes
Like

Posted 30 December 2012 - 11:10 AM

Though i wouldnt suggest doing it that low level.
 
What if you want to make the game objects out of multiple triangles for some technical reason?
 
I think you should instead make a higher level "triangle" object and use that data for the line drawing, so that you dont even need to render the triangles if you dont want to, isntead of relying on the triangle rendering data.

I don't understand. What "low level" do you mean?

 

If you meant "drawing faces and lines in a single pass": I would not call this low level (I would not suggest it for the given problem though, at least not without having more informations). First, the method is in no way limited to a single triangle. Second, it doesn't suffer from z-fighting (what is a simple to solve problem here because of the use case in a 2D map, but you mentioned "game objects" where in general z-fighting is a problem when doing  multi-pass drawing). Third, for drawing you ever have the need to come to a structure that can be used by OpenGL (in this case), and this is ever "low level" so to say; whether the editor manages the map data in addition in a more sophisticated structure is another question, but the OP especially targeted drawing.



#9 Waterlimon   Crossbones+   -  Reputation: 2636

Like
0Likes
Like

Posted 30 December 2012 - 11:17 AM

I meant that the line drawing shouldnt perhaps be so strongly tied with the rendering of the triangles.

 

Its a 2D map editor and not a mesh editor, so i would imagine that some day OP might face a situation where he needs multiple triangles for some more complex effect, but wants it to act like a single triangle.

 

So it might make more sense to have a more abstract representation for the triangles, and then the rendering of triangles, and then the rendering of the lines, which is based on the abstract representation of the triangles and not the rendering of them.

 

Performance shouldnt be a problem for a 2D map editor, but flexibility/extensibility is probably important.


o3o


#10 haegarr   Crossbones+   -  Reputation: 4586

Like
0Likes
Like

Posted 30 December 2012 - 12:01 PM

Notice please that the suggested method of using 2 IBOs and 2 passes allows for drawing with different line styles, including to elide edges as well. There is neither a need to use all attributes of a vertex nor the need to use all vertices listed in a VBO. It just allows for re-using vertex positions.

 

Using the one-pass method is, as already said, an extreme solution, nevertheless able to fulfill the given requirements of the OP. I don't suggest it but have mentioned it to demonstrate that splitting vertex data is not needed at all. For sure, if the requirements are changed afterwards, any solution working so far may break then. I think that the suggested solution is in accordance with your thoughts of a flexible enough method, just to make the chance of breaking it less probable.



#11 Maxjen   Members   -  Reputation: 191

Like
0Likes
Like

Posted 30 December 2012 - 01:26 PM

Wow, so many replies! Thanks!

 

To clarify what I want to do: The Triangle class will be used only for the ground. For other type of objects I will make seperate classes. And I want to perform the most basic actions on the vertices like move, rotate, scale.(like in blender) This is inspired by the game soldat. This is an example of a map in soldat.

 

How the drawing is done: In two passes. Somewhere in my main loop I call triangles->draw() and later selection->draw(). The Triangle class manages the vertex buffer for the triangles. It has functions to add/remove triangles and if the buffer is full it automatically creates a new buffer with twice the size and copies the data. The buffer has this structure:

 


struct Vertex {
    float x, y;      // position
    float u, v;      // texturecoords
    char r, g, b, a; // color
};

The Triangle class also has the index buffer for drawing the triangles.

This is the draw function for the triangles:

 

void Triangles::draw() {
    glUseProgram(shaderProgram);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
    // vertex
    glVertexAttribPointer(vertexPositionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    // texCoord
    glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(2 * sizeof(float)));
    // color
    glVertexAttribPointer(vertexColorLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (GLvoid*)(4 * sizeof(float)));
    glEnableVertexAttribArray(vertexPositionLocation);
    glEnableVertexAttribArray(texCoordLocation);
    glEnableVertexAttribArray(vertexColorLocation);
	
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);

    glEnable(GL_TEXTURE_2D);
    for(int i = 0; i < triangleCount; ++i) {
        if(trianglesData[i].isUsed) {
            glBindTexture(GL_TEXTURE_2D, trianglesData[i].texture->id);
            glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (GLvoid*)(sizeof(Triangle)*i));
        }
    }
    glDisable(GL_TEXTURE_2D);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glDisableVertexAttribArray(vertexColorLocation);
    glDisableVertexAttribArray(texCoordLocation);
    glDisableVertexAttribArray(vertexPositionLocation);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glUseProgram(0);
}

 

I will also replace the for loop in the future and instead use the spatial tree from Box2D to draw only currently visible triangles.

 

Now the problem is the draw method of the selection class. Currently I already render white points for the vertices and I reuse the vertex buffer from the Triangle class with a new index buffer. I want to do the same for the edges, however I need additional information. For every edge where at least one vertex is selected I need two booleans to know how to draw the line. e.g. if only one vertex is selected then the line should fade from full white to transparent. I think this information doesn't belong into the Triangle class because I might e.g. use the Triangle class later in the game itself where I don't need selections. So instead I want to create a new buffer with the booleans. What I don't know is how to use them both at once. e.g. can I even do something like this:

 


glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferId);
glVertexAttribPointer(vertexPositionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
glBindBuffer(GL_ARRAY_BUFFER, selectionVertexBufferId);
glVertexAttribPointer(vertexSelectionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Selection), 0);
...
glDrawElements(GL_LINES, ...);

Wouldn't the result be that only the second buffer is bound when I draw the lines? But I need both.

 



#12 Maxjen   Members   -  Reputation: 191

Like
0Likes
Like

Posted 03 January 2013 - 07:51 AM

No help? Basically I only want to do what was already suggested I just don't know exactly how to do it in openGL.

 

For sure, a clean way under the condition of not replicating data would be to use 3 VBOs (1 with the data shared between face and line drawing, 1 with the data used for face drawing only, and 1 with the data used for line drawing only), and 2 IBOs (1 for face drawing and 1 for line drawing).

 

I want 2 VBOs but how? If I bind one buffer and then the next will the first buffer not be unbound? Or is it enough to bind the buffer, set the vertex attrib pointers and then unbind it again before the draw call?



#13 Brother Bob   Moderators   -  Reputation: 8596

Like
1Likes
Like

Posted 03 January 2013 - 08:34 AM

I want 2 VBOs but how? If I bind one buffer and then the next will the first buffer not be unbound? Or is it enough to bind the buffer, set the vertex attrib pointers and then unbind it again before the draw call?

Bind a VBO and set a pointer, then bind another VBO and set another pointer. Yes, the second binding will unbind the first one, but a vertex attribute pointer depends on the VBO binding when the pointer is set, not when the arrays are drawn.



#14 haegarr   Crossbones+   -  Reputation: 4586

Like
1Likes
Like

Posted 03 January 2013 - 08:40 AM

I want 2 VBOs but how? If I bind one buffer and then the next will the first buffer not be unbound? Or is it enough to bind the buffer, set the vertex attrib pointers and then unbind it again before the draw call?
There is perhaps still a misunderstanding. The vertex positions are the same for the faces, edges, and point handles. You need only 1 VBO with the position, and that is the VBO I've mentioned as "shared". However, you need to transport the edge color as well, and that attribute is unique to edge rendering. Hence create another VBO for the edge color (but notice that it is still given for each vertex; but that isn't a problem with your kind of coloring the edges).

Then do as follows (schematic):
1. bind (shared) VBO with positions
2. set attribute pointer for positions
3. bind VBO with colors
4. set attribute pointer for colors
5. bind index buffer for edges
6. draw edges
7. clean up

If the shared VBO contains colors, too, because you deal with it in face rendering ... it doesn't matter, because you ignore it (i.e. you don't use it with the attribute pointer setting) during edge rendering.

Edited by haegarr, 03 January 2013 - 08:41 AM.


#15 Maxjen   Members   -  Reputation: 191

Like
0Likes
Like

Posted 03 January 2013 - 11:09 AM

Bind a VBO and set a pointer, then bind another VBO and set another pointer. Yes, the second binding will unbind the first one, but a vertex attribute pointer depends on the VBO binding when the pointer is set, not when the arrays are drawn.

Thank you very much, that is all I needed to know!

There is perhaps still a misunderstanding. The vertex positions are the same for the faces, edges, and point handles. You need only 1 VBO with the position, and that is the VBO I've mentioned as "shared". However, you need to transport the edge color as well, and that attribute is unique to edge rendering. Hence create another VBO for the edge color (but notice that it is still given for each vertex; but that isn't a problem with your kind of coloring the edges).

There is no misunderstanding but thanks! What you described is exactly how I was going to do it. There was only the technical problem of how to use more than one vertex buffer.rolleyes.gif






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS