I've finnaly reached the point that I can add some color to my vertices. But now I want to improve my FPS rate. Here is the current situation. I have a large number of vertices (~200000) , and each of them can be in one of ~150 classes. Each class is differenced by it`s color. I'm currently drawing my vertices like:
glEnableClientState(GL_VERTEX_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferVertices)
glVertexPointer(3, GL_FLOAT, 0, None)
glEnableClientState(GL_NORMAL_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferNormals)
glNormalPointer(GL_FLOAT, 0, None)
glEnableClientState(GL_COLOR_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferColors)
glColorPointer(3, GL_FLOAT, 0, None)
glDrawArrays( GL_POINTS, 0, len(self.vertices) / 3 )
Everything works fine and the FPS is ~60. All my buffers are generated only at init time. But now the colors that represent each class will change rapidly, once about every millisecond. With that the colors will also change so I would have to recreate my color buffer for each draw, and for 200000 vertices I have a feeling the FPS will be close to 0. The fix I'm trying to implement is to keep a fixed color buffer, but instead of the actual colors, they would retain a pointer to the class it`s represented by. That way, only the 200 colors of the classes will change. Problem is I don't know how this could be implemented in OpenGL. Is this doable ? Any pointers in how to do this?
Instead of colors the classes should set a 1D texture coordinate, then instead of changing that huge dataset you have to replace only parts of the texture. To avoid texture sampling interpolation set the texture into GL_NEAREST filtering mode, and sample the texture in the vertex shader per vertex (i.e. no per fragment texture sampling as you'd do usually).
I think you should seriously take a look at shaders. You shouldn't need to recreate your buffer every time. http://en.wikipedia.org/wiki/GLSL. The shaders will use your buffer to perform all kinds of operations in color and geometry.
Related
I would like to bind for example 80 textures on one mesh and put it in my VBO.
How can I achieve this?
I've read glActiveTexture is able to do that, however it allows max around 32 textures (GPU dependant).
My VBO code:
//Generating VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());
glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//Drawing VBO:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_DOUBLE, 0, 0);
glTexCoordPointer(2, GL_DOUBLE, 0, (void*)(vertices.size()*sizeof(Vector3d)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
Binding many (100s of) textures
I'm not sure of a way to bind that many separate textures at once. There are bindless textures but I don't have much experience with that extension. You could also use an array texture if many of your textures are the same size. But the standard approach to this problem is to use a texture atlas, where you pack lots of textures into the one, record where they're placed and adjust the texture coordinates to match.
Update: you could also use many texture arrays to store texture atlases (see comments and #Ethan's answer).
Applying multiple textures to a mesh
How will I tell the VBO, what faces will have which texture?
I think a more immediate problem is is how you go about applying different textures (or materials) to the same mesh. There's a few things to consider...
The most common case for applying multiple textures is where each stores a different material attribute but they all use the same texture coordinates/"UVs". E.g. diffuse, normal, specular maps. I guess in the extreme case when you have 100s of different attributes is where you'd want an array texture.
If each texture needs to be mapped differently you'd have a separate per-vertex texture coordinate VBO for each texture. Then you'll have to decide how the textures interact or blend as they're applied.
You have completely separate materials/texture per face. Commonly there are only a few materials on the mesh. The way you render it is in separate batches, grouping by material. Bind the right texture, set the shader uniforms, draw triangle indices A to B.
If nearly every face has a different material. I guess this might be the case if you're drawing a tile based game with lots of different tiles.
The problem here is the number of draw calls becomes a bottleneck,
so you'll have to combine different materials into the same draw call.
You could do this by storing the material on vertex attributes, such as adding a vertex colour VBO.
Rather than just colour, you could store a per-vertex texture ID, and if you're using a texture atlas, the region in the atlas where your texture can be found.
This starts to get inefficient because you'll have the same material data stored multiple times on each vertex of your triangles.
To minimize the overhead, you could store a material index per vertex, which points to a material defined in a table somewhere (either in a small uniform array, or if you need more materials, another texture).
Then add texture ID and atlas region to the material in the table.
Hopefully this last point answers your question.
To be honest, if you have more than 32 textures for one mesh, you probably have a much bigger problem than binding issues. But if you insist on having that many textures, you have 2 options: Bindless or Texture array. However, there are drawbacks: Bindless will limit your hardware support. Texture array does require the textures to be of the same size and format. Personally I think Texture Array is a workable solution. You can try to resize your textures if possile, then group those with the same size & format into one array. Now, you have 32 arrays to work with, and that should be more than enough, e.g. one array for all albedo textures, one for all normal maps etc. Regarding resizing, consider scaling textures up to the largest size that you have, or maybe split into categories e.g. small, medium, large. Avoid arbitrary sizes.
I need to implement an image reconstruction which involves drawing triangles in a buffer representing the pixels in an image. These triangles are assigned some floating point value to be filled with. If triangles are drawn such that they overlap, the values of the overlapping regions must be added together.
Is it possible to accomplish this with OpenGL? I would like to take advantage of the fact that rasterizing triangles is a basic graphics task that can be accelerated on the graphics card. I have a cpu-only implementation of this algorithm already but it is not fast enough for my purposes. This is due to the huge number of triangles that need to be drawn.
Specifically my questions are:
Can I draw triangles with a real value using openGL? (Or can I come up with a hack using color etc?)
Can OpenGL add the values where triangles overlap? (Once again I could deal with a hack, like color mixing)
Can I recover the real values for the pixels as an array of floats or similar to be further processed?
Do I have misconceptions about the idea that drawing in OpenGL -> using GPU to draw -> likely faster execution?
Additionally, I would like to run this code on a virtual machine so getting acceleration to work with OpenGL is more feasible than rolling my own implementation in something like Cuda as far as I understand. Is this true?
EDIT: Is an accumulation buffer an option here?
If 32-bit floats are sufficient then it looks like the answer is yes: http://www.opengl.org/wiki/Image_Format#Required_formats
Even under the old fixed pipeline you could use a blending mode with the function GL_FUNC_ADD, though I'm sure fragment shaders can do it more easily now.
glReadPixels() will get you the data back out of the buffer after drawing.
There are software implementations of OpenGL, but you get to choose when you set up the context. Using the GPU should be much faster than the CPU.
No idea. I've never used OpenGL or CUDA on a VM. I've never used CUDA at all.
I guess giving pieces of code as an answer wouldn't be appropriate here as your question is extremely broad. So I'll simply answer your questions individually with bits of hints.
Yes, drawing triangles with openGL is a piece of cake. You provide 3 vertice per triangle and with the proper shaders your can draw triangles, with filling or just edges, whatever you want. You seem to require a large set (bigger than [0, 255]) since a lot of triangles may overlap, and the value of each may be bigger than one. This is not a problem. You can fill a 32bit precision one channel frame buffer. In your case only one channel may suffice.
Yes, the blending exists since forever on openGL. So whatever the version of openGL you choose to use, there will be a way to add up the value of the trianlges overlapping.
Yes, depending on you implement it you may have to use glGetSubData() or glReadPixels or something else. However, depending on the size of the matrix you're filling, it may be a bit long to download the full buffer (2000x1000 pixels for a one channel at 32bit would be around 4-5ms). It may be more efficient to do all your processing on the GPU and extract only few valuable information instead of continuing the processing on the CPU.
The execution will be undoubtedly faster. However, the download of data from the GPU memory is often not optimized (upload is). So the time you will win on the processing may be lost on the download. I've never worked with openGL on VM so the additional loss of performance is unknown to me.
//Struct definition
struct Triangle {
float[2] position;
float intensity;
};
//Init
glGenBuffers(1, &m_buffer);
glBindBuffer(GL_ARRAY_BUFFER, 0, m_buffer);
glBufferData(GL_ARRAY_BUFFER,
triangleVector.data() * sizeof(Triangle),
triangleVector.size(),
GL_DYNAMIC_DRAW);
glBindBufferBase(GL_ARRAY_BUFFER, 0, 0);
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
glVertexAttribPointer(
POSITION,
2,
GL_FLOAT,
GL_FALSE,
sizeof(Triangle),
0);
glVertexAttribPointer(
INTENSITY,
1,
GL_FLOAT,
GL_FALSE,
sizeof(Triangle),
sizeof(float)*2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_R32F,
width,
height,
0,
GL_RED,
GL_FLOAT,
NULL);
glBindTexture(GL_FRAMEBUFFER, 0);
glGenFrameBuffers(1, &m_frameBuffer);
glBindFrameBuffer(GL_FRAMEBUFFER, m_frameBuffer);
glFramebufferTexture(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
m_texture,
0);
glBindFrameBuffer(GL_FRAMEBUFFER, 0);
After you just need to write your render function. A simple glDraw*() should be enough. Just remember to bind your buffers correctly. To enable the blending with the proper function. You might also want to disable the anti aliasing for your case. At first I'd say you need an ortho projection but I don't have all the element of your problem so it's up to you.
Long story short, if you never worked with openGL, the piece of code above will be relevant only after you read few documentation/tutorials on openGL/GLSL.
I used to write small games with 'per pixel' drawing,
I mean with some SetPixel(x,y,color) function or such.
I am also interested in OpenGL but do not know it much.
Is it a good (fast) way to do a per pixel drawing in OpenGL ?
It would be good for example to use textured quads as a sprites,
or whole application background screen, with possibility to
set distinct pixel with some kind of my own SetPixel routine
i would write... or any other way - but it should be efficient
as much as it cans
(especialy im interested in basic fundamenta 1.0 version of OGL)
You can set a projection that will map vertex coordinates 1:1 to pixel coordinates:
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, window_width, 0, window_height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
From here on, vertex X,Y coordinates are in pixels with the origin in the lower left corner. In theory you could use the immediate mode with GL_POINT primitives. But it's a much better idea to batch things up. Instead of sending each point indivisually create an array of all the points you want to draw:
struct Vertex
{
GLfloat x,y,red,green,blue;
};
std::vector<Vertex> vertices;
/* fill the vertices vector */
This you can OpenGL point to…
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
/* Those next two calls don't copy the data, they set a pointer, so vertices must not be deallocated, as long OpenGL points to it! */
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].x);
glColorPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].red);
…and have it access and draw it all with a single call:
glDrawArrays(GL_POINTS, 0, vertices.size();
You really don't want to do this.
Is it a good (fast) way to do a per pixel drawing in OpenGL ?
There is no good or fast way to do this. It is highly discouraged due to the speed.
The proper way, although not easy (or in some cases possible) in OGL 1, is to use pixel shaders or blend modes. That is the only correct way, anything else is hacking around the entire system.
Depending on how the data needs modified, vertex colors and blend modes may be able to solve the some uses. It won't tint each pixel individually, but you can modify the texture must faster.
To do it, you can draw single-pixel quads (although care must be taken to offset them and handle filtering to prevent blurring) or you can get texture data and manipulate it later. Both will be unbelievably slow, but could function.
Working with the texture data is probably simpler and may be slightly faster.
I'm looking for a way to improve my particle system performance, since it is very costly in terms of FPS.
This is because I call:
glDrawElements(GL_TRIANGLE_STRIP, mNumberOfIndices,
GL_UNSIGNED_SHORT, 0);
I call this method for every particle in my application (which could be between 1000 and 5000 particles). Note that when increasing to over 1000 particles my application starting to drop down in FPS. I'm using VBO:s, but the performance when calling this method is too costly.
Any ideas how I can make the particle system more efficient?
Edit: This is how my particle system draw things:
glBindTexture(GL_TEXTURE_2D, textureObject);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexBuffer[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboTextureBuffer[0]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexBuffer[0]);
Vector3f partPos;
for (int i = 0; i < m_numParticles; i++) {
partPos = m_particleList[i].m_pos;
glTranslatef(partPos.x, partPos.y, partPos.z);
glDrawElements(GL_TRIANGLE_STRIP, mNumberOfIndices,
GL_UNSIGNED_SHORT, 0);
gl.glTranslatef(-partPos.x, -partPos.y, -partPos.z);
}
The way you describe it, it sounds like you have a own VBO for each particle. This is not how it should be done. Put all particles into a single VBO and draw them all at once using a single glDrawElements or glDrawArrays call. Or even better, if available: Use instancing.
Expanding a bit on what datenwolf said, just pack all your particle indices into a single index buffer and draw all particles with a single glDrawElements call. This means you cannot use triangle strips anymore but a triangle set, but that shouldn't be too much of a problem.
Otherwise, if your hardware supports instanced rendering (or better, instanced arrays), you can do it by just rendering a single particle n times with the position and texCoord data taken from the respective arrays for each particle. You then still need to compute the four corner's position and texCoord data in the vertex shader (assuming you draw a quad for each particle), as with the instanced arrays you only get one attribute per instance (particle).
You might also use the geometry shader to create the particle's quad and just render a single point set, but I assume this might be slower than instancing, considering that SM4/GL3 hardware is quite likely to support instancing, too.
Context
I am doing swarm simulation using GPU programming (both OpenCL and CUDA,
but not at the same time of course) for scientific purpose.
I use OpenGL for display.
Goal
I would like to draw the same object —namely the swarming particle, can be a simple triangle in 2D— N times at different positions and with
different orientations in the most efficient way knowing that:
the object is always exactly the same
the positions and orientations are calculated on the GPU and thus stored in the GPU memory
the number of particles N can be large
Current solution
So far, to avoid sending back the data to the CPU, I store the position and
orientation arrays in a VBO and use:
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, velocity_vbo);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, 0);
glDrawArrays(GL_POINTS, 0, N);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
to draw a set of points with color-coded velocity without copying back the arrays to the CPU.
What I would like to do is something like drawing a full object instead of a simple point
using a similar way ie without copying back the VBO's to the CPU.
Basically I would like to store on the GPU the model of an object
(a Display List? a Vertex Array?) and to use the positions and orientations on the GPU
to draw the object N times without sending data back to the CPU.
Is it possible and how? Else, how should I do it?
PS: I like keeping the code clean so I would rather separate the display issues from the swarming kernel.
I believe you can do this with a geometry shader (available in OpenGL 3.2). See this tutorial for specific information.
In your case, you need to make the input type and output type of the geometry shader to GL_POINTS and GL_TRIANGLES respectively, and in your geometry shader, emit the 3 vertices of your triangle for each incoming point vertex.