Plotting a 3D surface from x,y,z data

Hi,
Ok, I think I will defer this one for a while, but thanks, I will get to this.
Another question:

For my test case, I have x,y,and z axis and grids for my plots. At the moment I have just a pyramid plotted in these axis. I can rotate everything and it works well.
I also have a rectangle around the whole thing that is stationary. It was made with lines. Now when you rotate the scene with the pyramid, I would like it so that when the scene is rotated and goes beyond the border of the rectangle, I do not want to show those points. How would I do this? One way I suppose is to change the rectangle to a filled object that has a hole. Is that what I need to do?

If you want to restrict rasterisation to a screen-aligned rectangle, use glEnable(GL_SCISSOR_TEST) and glScissor().

Another option is changing the viewport, which may improve performance (primitives which are entirely outside of the viewport will be discarded entirely prior to rasterisation). However, wide lines or points can extend outside of the viewport rectangle.

Got it. Thanks!

Ok, thanks to all the people who pointed me in the right direction! This is the current status of the project. At the moment everything is done except plotting of the data…there is just a pyramid in it’s place. I will list the steps below as a reality check to make sure things are going correctly:

  1. Initialize ( setup freeglut, window, keyboard, mouse callbacks etc…)
  2. Create a vertex shader and fragment shader for the pyramid.
  3. Create vertices and indexes for the glDrawElements for the pyramid.
  4. Create a vertex shader and fragment shader for the axis and grids.
  5. Create vertices and indexes for the axis and grids.
  6. Create a vertex shader and fragment shader for Text
  7. Create vertices for the characters of the text
  8. Use the various programs for the objects, binding buffers, and then glDrawElements for all.
  9. dispose of all objects on exit.

So I presume this is all done the right way? I can see that a typical openGL app might have many, many VAOs and shaders.
Thanks!

of course you can do it that way, but it is more efficient to have 1 program + 1 vertexarray + 1 vertexbuffer + 1 elementbuffer for each “vertex layout”, that means you can use the same VAO + VBO + IBO (elementbuffer) for all of them, the pyramid + the grid (except text)

consider glDrawArrays(…, offset, count):
if you put 36 vertices into the VBO for a cube, and then 300 vertices for a sphere, then:
cube:
– offset = 0
– count = 36
sphere:
– offset = 36
– count = 300

both cube and sphere have the same program / vertexshader / fragmentshader / VAO / VBO

https://www.khronos.org/opengl/wiki/Vertex_Specification_Best_Practices

Hi
Of course. Makes sense and a good link. A question about some of this: There are several objects that never change. The axis for example. Do you need to make a distinction between these and objects that will change continuously like the 3d surface that I am plotting?
Currently, it takes less than a millisecond to do everything.

you dont need to, you can …
but in your case i wouldnt make a distinction for those few bytes

updating a buffers content can be done very fast using:


glBindBuffer(GL_ARRAY_BUFFER, mybuffer);
void* bufferdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);

// .. use that pointer for memory access:
std::memcpy(bufferdata, ..., ...);

glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);

just as an alternative to glBufferSubData(…)

Also, if you use glMapBufferRange() there are several flags which may allow the implementation to optimise the operation.

If you use glBufferSubData() to overwrite regions which will be used by pending commands, it has to either block until the implementation has finished using the existing data, or make a copy of the new data, or make a copy of the old data then update part of it. Whereas glBufferData() can simply allocate a new block of memory for the new data and “orphan” the existing memory, deleting it once the last command which uses it completes.

On the other hand, glMapBuffer() may have to copy the original data to system memory in case you only overwrite some parts of it (whether it will actually do so depends upon whether it maps video memory directly or uses a shadow copy). Whereas glMapBufferRange() can be instructed (via GL_MAP_INVALIDATE_BUFFER_BIT) that this isn’t necessary (because either you’re going to overwrite everything or any portions which aren’t overwritten won’t be used).

Hi,
Ok, I’m going to need to look at all of this more carefully.
In my software I need to update the text which is used for the scales of the axis. When I first tried this, I would get a system access violation when existing the software or if I updated the text a couple of times. Turns out the library I use for text will only dispose of the VBO’s when the program exists. So if I update the text it keeps creating new VBO’s for the text but does not get rid of the old ones.
So, I now take care of this in my software but it seems that this is very inefficient since I have to dispose of many VBO’s, one per string before I can update them. I don’t thing that this is an issue for the text but when I make my 3d plot, I do need to update this once every 100ms or so. I don’t want to be disposing of VBO’s, index buffers, etc.
So I will look at the last two messages…

Ok, this is not so easy to decipher.
I initially (outside the render callback) setup a pyramid… here is the code…


            program = new ShaderProgram(VertexShader, FragmentShader)

            // set the view and projection matrix for pyramid
            program.Use();
            program["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
            program["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 10), Vector3.Zero, new Vector3(0, 1, 0)));


            // create a pyramid with vertices and colors
            pyramid = new VBO<Vector3>(new Vector3[] {
                new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),        // front face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),        // right face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),      // back face
                new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) });   // left face


            pyramidColor = new VBO<Vector3>(new Vector3[] {
                new Vector3(0.5f, 0, 0), new Vector3(0, 0.5f, 0), new Vector3(0, 0, 0.5f),
                new Vector3(0.5f, 0, 0), new Vector3(0, 0, 0.5f), new Vector3(0, 0.5f, 0),
                new Vector3(0.5f, 0, 0), new Vector3(0, 0.5f, 0), new Vector3(0, 0, 0.5f),
                new Vector3(0.5f, 0, 0), new Vector3(0, 0, 0.5f), new Vector3(0, 0.5f, 0) });


            pyramidTriangles = new VBO<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, BufferTarget.ElementArrayBuffer);

I then enter the main loop of Glut. On the render callback I have:


            // use our vertex shader program
            Gl.UseProgram(program);
           
            // bind the vertex positions, colors and elements of the pyramid
            program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));              
            Gl.BindBufferToShaderAttribute(pyramid, program, "vertexPosition");
            Gl.BindBufferToShaderAttribute(pyramidColor, program, "vertexColor");
            Gl.BindBuffer(pyramidTriangles);
            Gl.DrawElements(BeginMode.Triangles, pyramidTriangles.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

And this all works file. I then thought to add an update to the OnRender callback which just updates the pyramid vertices (just the very first X in this case as a test with this:


            Gl.UseProgram(program);

            pyramid = new VBO<Vector3>(new Vector3[] {
                new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),        // front face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),        // right face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),      // back face
                new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) });   // left face

            
            // bind the vertex positions, colors and elements of the pyramid
            program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));              
            Gl.BindBufferToShaderAttribute(pyramid, program, "vertexPosition");
            Gl.BindBufferToShaderAttribute(pyramidColor, program, "vertexColor");
            Gl.BindBuffer(pyramidTriangles);
            Gl.DrawElements(BeginMode.Triangles, pyramidTriangles.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

This works. However, when I leave the program I again get a memory access violation. Would this mean I need to dispose of the pyramid vertices each time? Or am I updating the pyramid VAO incorrectly?
Thanks

Well I figured it out!
In the OnRender callback you need to do a the following:

            // use our vertex shader program
            Gl.UseProgram(program);

            // bind the vertex positions, colors and elements of the pyramid
            program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));
            
            pyramid.BufferSubData(new Vector3[] {
                new Vector3(0.0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),        // front face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),        // right face
                new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),      // back face
                new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) });
            
            Gl.BindBufferToShaderAttribute(pyramid, program, "vertexPosition");
            Gl.BindBufferToShaderAttribute(pyramidColor, program, "vertexColor");
            Gl.BindBuffer(pyramidTriangles);

The command needed was pyramid.BufferSubData …
Again, the differences between c++ and C# made this more difficult than need be.

Of course this opens a whole new can of worms…
How in the world do I update or create all those vectors in a loop???

[QUOTE=tomb18;1285358]Of course this opens a whole new can of worms…
How in the world do I update or create all those vectors in a loop???[/QUOTE]

what do you mean exactly by that ?
if you want to draw a pyramid, all vertices are “static”, they dont have to be updated, instead you modify the Model-To-World matrix to move/rotate/resize the appearance of the pyramid in your scene

if you have a “signal”, lets say array<vec3, 100> and you want to replace 100 existing vec3’s in your buffer:
glBufferSubData(…) has parameter offset, count, you can control with them where and how much data to copy / replace

or as mentioned before: glMapBuffer() / glMapBufferRange()

maybe you dont want to update a signal each frame, use a timer function to control the update frequency

Hi,
This is my lack of experience in dealing with objects like vectors.
All figured out now!