Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 days ago.
Improve this question
I've been trying to implement a particle simulation engine which computes forces between particles on GPU using CUDA and visualizes it using openGL. I've been stuck for some time on the part where I want to update my vertex buffer without copying it back to CPU. The problem seems to be in the way I'm binding/ passing the vertex buffer.
Here is the fragment of code that is responsible for creating VAO and VBO and drawing it to the screen:
// pointer to array on gpu
float* d_particlePositions;
// Creating a vertex array object
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Creating a vertex buffer object for N points with 3 floats
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 3 * N * sizeof(float), NULL, GL_DYNAMIC_COPY);
cudaGLRegisterBufferObject(vertexBuffer);
// rendering loop
while(running){
cudaGLMapBufferObject((void **) &d_particlePositions, vertexBuffer);
// call some kernel functions like
update<<<x,y>>>(d_particlePositions, ...);
cudaGLUnmapBufferObject(vertexBuffer);
// bind VAO, VBO and draw to screen
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, N);
}
I know that my openGL setup is right because i got it working, but in case when every cycle I had to copy it back to CPU and create a new VBO. If you have some resources that can help me solve this I' highly appreciate it.
Related
When I first add some vertices to the buffer, these are the relevant functions I'm calling
// Create and bind the object's Vertex Array Object:
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Create and load vertex data into a Vertex Buffer Object:
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices[0], GL_STATIC_DRAW);
// Tells OpenGL that there is vertex data in this buffer object and what form that vertex data takes:
// Obtain attribute handles:
_posAttrib = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(_posAttrib);
glVertexAttribPointer(_posAttrib, // attribute handle
4, // number of scalars per vertex
GL_FLOAT, // scalar type
GL_FALSE,
0,
0);
// Unbind vertex array:
glBindVertexArray(0);
But later on in my program, I want to add some more vertices.
I do this by the following (within a separate function:
add_vertices(x,y); //adds the necessary vertices to the vector.
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, (TRIANGLE_AMOUNT+1)*4*_number_of_circles * sizeof(float), &vertices[0], GL_STATIC_DRAW);
Assuming the funky size in the 2nd argument of glBufferData is fine, am I missing anything? Are there any other OpenGL functions that need calling?
I'm not getting any errors, but when I'm trying to draw the extra shapes with the new vertices by looping over glDrawArrays with different subsets of the vertices, nothing happens. Only the first shape gets drawn.
I hope that this is semi-coherent...let me know if there's any info I haven't provided.
Cheers.
In OpenGL, changing the buffers and exchanging the buffers data are two different things which require different actions to be taken afterwards:
Exchanging the data
In this case a previously generated vbo is required. To upload new data, it is only required to bind the buffer and to buffer new data:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, (TRIANGLE_AMOUNT+1)*4*_number_of_circles * sizeof(float),
&vertices[0], GL_STATIC_DRAW);
Creating a new buffer
In this case a new buffer is generated by glGenerateBuffers and (in addition to uploading the data) all VAO bindings have to be updated.
Sidenote: In the code shown above, you create a new buffer without deleting the previous buffer.
I'm currently learning OpenGL in my free time and lately I have been facing an "error" I don't understand.
The thing is, I have no errors, only nothing appear on my screen. I'm using OpenGL with SFML.
Here is my code. Here is my method:
void CreateObjet(GLuint& vao, GLuint& vbo, GLuint& ebo, GLuint& textureLocation)
//I create my arrays here.. Don't worry they are fine.
CreateTexture(textureLocation);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glGenVertexArrays (1, &vao);
glBindVertexArray (vao); //On travaille dans le VAO
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBufferData (GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glVertexAttribPointer (2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6* sizeof(GLfloat)));
glEnableVertexAttribArray(2);
//EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indiceFinal), indiceFinal, GL_STATIC_DRAW);
glBindVertexArray(0);
I know my problem is not with my shaders because I receive no errors in my console with GlshaderRiv().
I would like to know if I'm doing the order properly.
I Create a VBO and a EBO
I Create a VAO
I bind the current VAO to modify it
I bind the current VBO inside the VAO
I bind my first array (Vertex Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my second array (Color Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my third array (Texture Position vector2f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind a EBO within the VAO
I bind the EBO with my element position (Vector 3u).
I unbind the VAO from the memory because my drawing loop is quite later in the code and so, I don't want to use memory space for nothing. Don't worry, Before I draw I put glBindVertexArray(&vao);
That definitely does not look right. You're writing the values for all attributes to the same buffer, with each one overwriting the previous one:
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
...
When you make the second glBufferData() call, it will overwrite the points data that you previously stored in the buffer with the colors data.
The misunderstanding is probably about what glVertexAttribPointer() does. It specifies which buffer the given attribute is sourced from, as well as the data layout (component count, type, etc). But it does not create a copy of the buffer data, or anything like that. The attribute data you want to use must still be stored in the buffer at the time of the draw call.
To fix this, you either have to use a different buffer for each attribute, or arrange the attribute data so that the values for all 3 attributes can be stored in the same buffer. The arguments of your glVertexAttribPointer() calls actually suggest that you were intending to store all attribute values interleaved in the same buffer. To get this working, you have to arrange the attribute values accordingly, and then store them in the buffer with a single glBufferData() call.
The memory arrangement you will need for this will have all the attribute values for the first vertex in sequence, followed by the values for the second vertex, etc. With pi the position of vertex i, ci the color, and ti the texture coordinates, the correct memory layout is:
p0x p0y p0z c0r c0g c0b t0s t0t
p1x p1y p1z c1r c1g c1b t1s t1t
p2x p2y p2z c2r c2g c2b t2s t2t
...
Right now it seems to me that my interleaved VBO is strictly ' read-only ' but I want to update it every frame (preferrably from GLSL).
I have a planet that moves around in an orbit, the code below is for rendering points of the orbit.
Problem outline:
I want each point on that orbit to have its own "lifetime", logic:
when the planet passes each consecutive point? update lifetime to 1.0 and reduce with time!
This will be used to create a fading orbitpath of each moving object. Right now Im just looking for ways to manipulate the vbo...
How can I read AND write within GLSL to and from a VBO ? Can anyone post example please?
Update: I modified the code above to work with transform feedback (suggested by user Andon M. Coleman) but I think I might be doing something wrong (I get glError):
Setup:
// Initialize and upload to graphics card
glGenVertexArrays(1, &_vaoID);
glGenBuffers(1, &_vBufferID);
glGenBuffers(1, &_iBufferID);
glGenBuffers(1, &_tboID);
// First VAO setup
glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
glBufferData(GL_ARRAY_BUFFER, _vsize * sizeof(Vertex), _varray, GL_DYNAMIC_DRAW);
// TRANSFORM FEEDBACK
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, _tboID); // Specify buffer
// Allocate space without specifying data
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
_vsize*sizeof(Vertex), NULL, GL_DYNAMIC_COPY);
// Tell OGL which object to store the results of transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _vBufferID); //correct?
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, location)));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, velocity)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _isize * sizeof(int), _iarray, GL_STREAM_DRAW);
render method():
//disable fragment, so that we do a first run with feedback
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _tboID);
glBeginTransformFeedback(_mode);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindVertexArray(0);
glDisable(GL_RASTERIZER_DISCARD);
// then i attempt to do the actual draw
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
And - right before linking:
const GLchar* feedbackVaryings[] = { "point_position" };
glTransformFeedbackVaryings(_ephemerisProgram->getProgramID(), 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
you can not change the content of your VBO from the rendering pipline of Opengl, but you can use tricks to update them depending on the time, also if you are using Opengl 4.4 you can use ComputeShaders but it's a little bit complicated to explain it in here, hust google for it, good luck.
How can I read AND write within GLSL to and from a VBO?
You can't. VBOs are strictly readonly from the normal rendering shaders. Modification is not possible at all (because that would open an infathomable deep barrel of worms) but using transformation feedback the results of the shader stages can be written into a buffer.
Or you use compute shaders.
Problem outline: I want each point on that orbit to have its own "lifetime", logic: When the planet passes each consecutive point? update lifetime to 1.0 and reduce with time!
Sound like a task for a compute shader. But honestly I don't think there's much to gain from processing this on a GPU.
This question already has answers here:
What is the proper way to modify OpenGL vertex buffer?
(3 answers)
Closed 2 years ago.
Currently I'm writing a program that simulates water. Here are the steps that I do:
Create water surface - plane.
Create VAO
Create vertex buffer object in which I store normals and vertices.
Bind pointers to this VBO.
Create index buffer object.
Then I render this plane using glDrawElements and then I invoke an update() function which changes positions of vertices of water surface. After that I invoke glBufferSubData function to update vertices positions.
When I do that - nothing happens as if the buffer isn't changed.
Here's the code snippet:
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Oscillator) * nOscillators, oscillators, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Oscillator), 0);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Oscillator), (const GLvoid*)12);
glEnableVertexAttribArray(0); // Vertex position
glEnableVertexAttribArray(2); // normals position
glGenBuffers(1, &indicesBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * nIndices, indices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBindVertexArray(0);
Then render:
glBindVertexArray(vaoHandle);
glDrawElements(GL_TRIANGLES, nIndices, GL_UNSIGNED_INT, 0);
update(time);
And update function:
//some calculations
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Oscillator) * nOscillators, oscillators);
Oscillator - it's a structure that has: 8 floats respectively - x, y, z (vertex position), nx, ny, nz (normals), upSpeed, newY
oscillators - this is an array of Oscillator structures.
What I do wrong?
Before updating the data you have to bind the correct buffer. E.g:
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Since you are updating the full buffer at once I would suggest to use glMapBuffer to update it
void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
//[...] update the buffer with new values
bool done = glUnmapBuffer(GL_ARRAY_BUFFER);
And remember to wait (or force) a glFlush() before modifying the data you are goin to copy to the gl buffer.
I've been trying to convert some of my code to modern OpenGL. I've gotten it to the point where I don't get any OpenGL errors, but nothing shows up when I try to draw an object. Here's my code (minus context creation, and error checking):
//Compile shaders and create/link program
//I very highly doubt the problem's here (all my tests say it worked fine),
//so I'm leaving this out for now, but I'll dig it out of my classes if
//there's no obvious problem with the VBO code.
//Create VAO, VBO
unsigned vaoId, vboId;
int positionAttributeLocation;
float vertices[] = {...vertex data here...};
unsigned indices[] = {...index data here...};
positionAttributeLocation = glGetAttribLocation(programId, "position");
glGenVertexArrays(1, &vaoId);
glGenBuffers(1, &vboId);
glBindVertexArray(vaoId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(positionAttributeLocation, 3, GL_FLOAT, GL_FALSE, 0, null);
glEnableVertexAttribArray(positionAttributeLocation);
//Create index buffer
unsigned indexId;
glGenBuffers(1, &indexId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glUseProgram(programId);
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(unsigned int), GL_UNSIGNED_INT, null);
Not quite SSCCE, but I think that's all the code that could possibly be causing an issue and it's pretty much self-contained.
Try glUseProgram() before your glGetAttribLocation()/glEnableVertexAttribArray() calls.
I figured it out. With some of my refactoring, I forgot to set my width and height variables properly, creating a 0 by 0 viewport. Oops...
Your problem more than likely lies with your cg program and modelview space.
Add cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); to your program just before gldrawarrays, and in your cg file add OUT.HPos = mul(ModelViewProj, IN.position);.
Also add modelViewMatrix as a cgparameter in you initcg section.
I worked this out from the basic opengl samples in the cgtoolkit, and my render function is very similar to yours and now works after having the same problem.