I'm trying to modernize my OpenGL code a little bit by bringing it to OpenGL 2.0 time, but all I get is a black screen... perhaps someone spots a mistake in my code (not that much of code).
Here is a snip of the relevant bits of my old, fully working code.
// Send color data into GPU memory
glEnableClientState(GL_COLOR_ARRAY);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorsHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colors, GL15.GL_DYNAMIC_DRAW);
glColorPointer(4, GL_FLOAT, 0, 0);
// Send vertex data into GPU memory
glEnableClientState(GL_VERTEX_ARRAY);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, verticesHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, GL15.GL_DYNAMIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, 0);
// Send texcoords data into GPU memory
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, texcoordsHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, GL15.GL_DYNAMIC_DRAW);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
for (Batch batch : batches) batch.render();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
... batch calls glDrawArrays (amongst doing some opengl state changes) ...
glDrawArrays(GL_QUADS, spriteOffset * 4, spriteCount * 4);
And here is the new code:
// Send color data into GPU memory
GL20.glEnableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorsHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colors, GL15.GL_DYNAMIC_DRAW);
GL20.glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
// Send vertex data into GPU memory
GL20.glEnableVertexAttribArray(1);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, verticesHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_DYNAMIC_DRAW);
GL20.glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
// Send texcoords data into GPU memory
GL20.glEnableVertexAttribArray(2);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, texcoordsHandle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, texcoords,GL15.GL_DYNAMIC_DRAW);
GL20.glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0);
for (Batch batch : batches) batch.render();
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL20.glDisableVertexAttribArray(2);
Like I said the first bit of code works perfectly, but the second does not draw anything at all. Those are the only lines of code I changed in my renderer, and they look correct to me. But obviously there is a problem somewhere... What could possibly cause the absence of rendering?
If those are really the only lines you've changed, then I guess you haven't implemented any shaders?
In OpenGLES 2.0 there is no fixed function pipeline, so you need to write vertex/fragment shaders, compile them, link program objects, etc.
I'm sure you can find many tutorials for this if you search.
Related
In the example below I have 2 meshes that use the same shader and I want to send different values
to each mesh the code below works but it seems unnecessary to send the data to the GPU every frame. Is there a way to send non-shader specific data to the GPU that can be used by the shader code and can by bound before draw calls?
I could just make a new shaders for every mesh I want to draw but this just seems like waste of memory.
glUseProgram(ShaderID);
glBindBuffer(GL_ARRAY_BUFFER, mesh1->VBO);
glBindVertexArray(mesh1->VAO);
glUniformMatrix4fv(MVP_ID, 1, GL_FALSE, (const GLfloat*)mvp1);
glUniform1fv(DataUniformID, 5, data1);
glDrawArrays(GL_TRIANGLES, 0, mesh1->size);
glBindBuffer(GL_ARRAY_BUFFER, mesh2->VBO);
glBindVertexArray(mesh2->VAO);
glUniformMatrix4fv(MVP_ID, 1, GL_FALSE, (const GLfloat*)mvp2);
glUniform1fv(DataUniformID, 5, data2);
glDrawArrays(GL_TRIANGLES, 0, mesh2->size);
I'm using a Widget inheriting QGLWidget to show an OpenGL viewport inside my Qt application.
The Widget does nothing more than creating three CRenderVectors and drawing them all the time.
A CRenderVector is simply a group of a QVector3D, a QOpenGLVertexArrayObject and three QOpenGLBuffers for vertices, indices and colors.
The vertex buffer objects get created with
const GLFloat color[] = {1, 0, 0, 1, 0, 0};
color_buffer.create();
color_buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
color_buffer.bind();
color_buffer.allocate(color, sizeof(color);
color_buffer.release();
respectively, using 0, 0, 0 and vec().{x,y,z}() for the vertex_buffer.
The vertex array object gets created via
vertex_array.create();
vertex_array.bind();
vertex_buffer.bind();
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, (void*)0);
index_buffer.bind();
color_buffer.bind();
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, (void*)0);
vertex_array.release();
Drawing of a vector looks like
vertex_array.bind();
glDrawElements(GL_LINES, elements, GL_UNSIGNED_INT, (void*)0);
vertex_array.release();
The problem is, that I can't see anything in the viewport except the clearing color although I think I'm using everything like shown in the official Qt documentation. Where did I misunderstand Qt or OpenGL documentations?
The stripped project for QtCreator can be downloaded at mediafire.
I have generally learned OpenGL Interoperability with CUDA, but my problem is like this:
I have a lot of arrays, some for vertex, some for norm and some for alpha value alone, and some pointers to these arrays on device memory (something like dev_ver, dev_norm) which are used in kernel. I have already mapped the resource and now I want to use these data in shaders to make some effects. My rendering code is like this:
glUseProgram (programID);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_0);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_0, GL_DYNAMIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_1);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_1, GL_DYNAMIC_DRAW);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray (0);
glEnableVertexAttribArray (1);
glEnableVertexAttribArray (2);
glDrawArrays (GL_TRIANGLES, 0, _max_);
glDisableVertexAttribArray (0);
glDisableVertexAttribArray (1);
glDisableVertexAttribArray (2);
However, now I have no _data_on_cpu_, is it still possible to do the same thing ? The sample in cuda 6.0 is something like this:
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalVbo);
glNormalPointer(GL_FLOAT, sizeof(float)*4, 0);
glEnableClientState(GL_NORMAL_ARRAY);
glColor3f(1.0, 0.0, 0.0);
glDrawArrays(GL_TRIANGLES, 0, totalVerts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
I don't exactly understand how this could work and what to do in my case.
By the way, the method I have used is to cudaMemcpy the dev_ to host and do the render like usual, but this is obviously not efficient, because when I do rendering I again send the data back to GPU by OpenGL (if I'm right).
It's not really clear what your asking for, you mention CUDA yet none of the code you have posted is CUDA specific. I'm guessing vertexbuffer_2 contains additional per vertex information you want to access in the shader?
OpenGL calls are as efficient as you will get it, they aren't actually copying any data back from device to host. They are simply sending the addresses to the device, telling it where to get the data from and how much data to use to render.
You only need to fill the vertex and normal information at the start of your program, there isn't much reason to be changing this information during execution. You can then change data stored in texture buffers to pass additional per entity data to shaders to change model position, rotation, colour etc.
When you write your shader you must include in it;
attribute in vec3 v_data; (or similar)
When you init your shader you must then;
GLuint vs_v_data = glGetAttribLocation(p_shaderProgram, "v_data");
Then instead of your;
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
You use;
glEnableVertexAttribArray (vs_v_data);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (vs_v_data, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
This should let you access a float3 inside your vshaders called v_data that has whatevers stored in vertexBuffer_2, presumably secondary vertex information to lerp between for animation.
A simple shader for this that simply repositions vertices based on an input tick
#version 120
attribute in float tick;
attribute in vec3 v_data;
void main()
{
gl_Vertex.xyz = mix(gl_Vertex.xyz, v_data, tick);
}
If you want per entity data instead of/in addition to per vertex data, you should be doing that via texture buffers.
If your trying to access vertex buffer obj data inside kernels you need to use a bunch of functions;
cudaGraphicsGLRegisterBuffer() This will give you a resource pointer to the buffer, execute this once after you initially setup the vbo.
cudaGraphicsMapResources() This will map the buffer (you can use it in CUDA but not gl)
cudaGraphicsResourceGetMappedPointer() This will give you a device pointer to the buffer, pass this to the the kernel.
cudaGraphicsUnmapResources() This will unmap the buffer (you can use it in gl, but not CUDA)
I hope this is the right lanuage to describe what I have done! I've created a WGL OpenGL context that supports FSAA. I have managed to render using shaders and VBOs through using
glBindBuffer(GL_ARRAY_BUFFER, my_gl_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data[0][0])*9, g_vertex_buffer_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, my_gl_vertexbuffer);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glBindBuffer(GL_ARRAY_BUFFER, my_gl_colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data[0][0])*9, g_color_buffer_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, my_gl_colorbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
and I get an output, without lighting because I have no lighting calculations in my shader cause I have 3 lights lighting the scene.
So it was suggested that I could use
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, g_vertex_buffer_data);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0,g_color_buffer_data);
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
which sort of works in a simple OpenGL context [that does not support FSAA]. In an FSAA WGL context [without any shaders loaded so I can use the fixed pipeline] all I get is the background colour that I cleared the screen to - it does not seem to render anything. Are glVertexPointer etc commands not supported in a FSAA WGL context? Or is it a case that with WGL context I have to use shaders?
You cannot use glVertexPointer (...), glColorPointer (...), etc... in a forward-compatible context.
Your problem has nothing to do with MSAA (though using 64x raises eyebrows), rather you have told GL to eliminate everything deprecated. A forward-compatible context is one step beyond core in terms of restrictivity. There are things that are deprecated but not removed in core, like wide lines... forward-compatible removes anything deprecated that is still valid in core.
Nevertheless, glColorPointer (...) is both, deprecated and removed from core. You must remove the forward-compatible bit from your context flags to use it.
I read this tutorial arc synthesis, vertex attributes, chapter 2 playing with colors and decided to play around with the code. To sum up, this tutorial explain how to pass vertices colors and coordinates to vertex and fragment shaders to put some color on a triangle.
Here is a code of the display function (from the tutorial with some changes) that works as expected :
void display()
{
// cleaning screen
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
//using expected program and binding to expected buffer
glUseProgram(theProgram);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//setting data to attrib 0
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
//glDisableVertexAttribArray(0); // if uncommenting this out, it does not work anymore
//setting data to attrib 1
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);
//cleaning and rendering
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
glfwSwapBuffers();
}
Now if uncommenting the line
//glDisableVertexAttribArray(0);
before setting data to attribute 1 this does not work anymore. Why is that ? Plus, I don't get it why attribute 0 can be set without 1 enabled and not the contrary. By the way, what is the usefulness of enabling/disabling vertices attributes ? I mean you (at least I) will probably end up enabling all vertices attributes so why they are off by default ?
It's at the glDrawArrays call that currently enabled attributes are read and passed to the renderer. If you disable them before that then they won't get passed from your buffer.
There can be a lot of potential attributes available (up to glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result); at least 16) and most applications don't need that many.
The position attribute in the shader is set to index 0 and if it doesn't get assigned then the shader gets all points with the same location (typically 0,0,0,1). Whereas index 1 is the color data and if that is missing it's not a big deal.