lid6j86's picture

Best method of displaying

So originally i meant to post this question in an existing forum, but I decided to make a new post about it.

I've seen several methods of posting to the screen (which is great because it means openGL is diverse), but it's gotten me wondering what the best method is?

I've been using GL.Begin and GL.End to this point but it seems like it is depreciated, discouraged, and slower than the other methods.

In another example I saw something about VBO and calling a Vector3 array and putting the points in like that (not 100% sure what i was seeing, but it was along those lines). I still don't fully understand the code below but that's because I just don't understand the functions themselves and what role they play.

int vbo;
 
		void CreateVertexBuffer()
		{
			Vector3[] vertices = new Vector3[3];
			vertices[0] = new Vector3(-1f, -1f, 0f);
			vertices[1] = new Vector3( 1f, -1f, 0f);
			vertices[2] = new Vector3( 0f,  1f, 0f);
 
			GL.GenBuffers(1, out vbo);
			GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
			GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
			                       new IntPtr(vertices.Length * Vector3.SizeInBytes),
			                       vertices, BufferUsageHint.StaticDraw);
		}
 
		protected override void OnLoad(EventArgs e)
		{
			GL.ClearColor(Color.Brown);
			CreateVertexBuffer();
		}
 
		protected override void OnRenderFrame(FrameEventArgs e)
		{
			GL.Clear(ClearBufferMask.ColorBufferBit);
 
			GL.EnableVertexAttribArray(0);
			GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
			GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
 
			GL.DrawArrays(BeginMode.Triangles, 0, 3);
 
			GL.DisableVertexAttribArray(0);
 
			SwapBuffers();
		}

I've also seen in several OpenGL examples a single array declared.

float vVerts[] = { -0.5f, 0.0f, 0.0f,
                               0.5f, 0.0f, 0.0f,
                               0.0f, 0.5f, 0.0f};

this version uses something called batches (which once again, I have no idea what that is in relation to OpenGL or if its still used) to load it into opengl and then display it onto the screen.

so I guess I'm asking, for C# and OpenTK purposes, what is the best method, and how does that best method work?

(by the way, I appreciate all of the patience with my several posts and questions, you all have helped tremendously)


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mOfl's picture

The best/recommended/modern way to display geometric information is with Vertex Array Objects (VAO) and Vertex Buffer Objects (VBO). Please be aware that Vertex Array Objects are a completely different thing than Vertex Attribute Arrays (often only called Vertex Arrays)! A Vertex Array Object is just a state object, meaning that you create it, bind it, then create and bind all of your desired VBOs and your Element (Index) Buffer, then unbind your VAO again. From then on, each time you want to draw your geometry, you only have to bind the VAO and call the draw command. I can't provide you complete code right now because I work with the shader language Cg in my framework and attribute binding is done slightly different then, but I hope this helps:

// Loading
 
// vertex array object
GL.GenVertexArrays(1, out this.vertexArray);
GL.BindVertexArray(this.vertexArray);
 
// vertex buffer
GL.GenBuffers(1, out this.vertexBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, this.vertexBuffer);
GL.BufferData<Vector4>(
    BufferTarget.ArrayBuffer,
    new IntPtr(this.vertices.Length * Vector4.SizeInBytes),
    this.vertices,
    BufferUsageHint.StaticDraw);
 
// replace this call with your own attribute binding, e.g.:
// int positionIndex = GL.GetAttribLocation(shaderHandle, "inPosition");
// GL.EnableVertexAttribArray(positionIndex);
// GL.BindBuffer(BufferTarget.ArrayBuffer, this.vertexBuffer);
// GL.VertexAttribPointer(positionIndex, 4, VertexAttribPointerType.Float, true, Vector4.SizeInBytes, 0);
this.material.Shader.SetPointer4f(ShaderType.VertexShader, "inPosition", true);
 
// normal buffer
GL.GenBuffers(1, out this.normalBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, this.normalBuffer);
GL.BufferData<Vector3>(
    BufferTarget.ArrayBuffer,
    new IntPtr(this.vertices.Length * Vector3.SizeInBytes),
    this.normals,
    BufferUsageHint.StaticDraw);
 
// replace this one, too
this.material.Shader.SetPointer3f(ShaderType.VertexShader, "inNormal", true);
 
// color buffer
GL.GenBuffers(1, out this.colorBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, this.colorBuffer);
GL.BufferData<Vector4>(
    BufferTarget.ArrayBuffer,
    new IntPtr(this.vertices.Length * Vector4.SizeInBytes),
    this.colors,
    BufferUsageHint.StaticDraw);
 
// replace this one, too
this.material.Shader.SetPointer4f(ShaderType.VertexShader, "inColor", true);
 
// index buffer
GL.GenBuffers(1, out this.elementBuffer);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, this.elementBuffer);
GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * this.indices.Length), this.indices, BufferUsageHint.StaticDraw);
 
// unbind the vertex array object
GL.BindVertexArray(0);

This is everything you need for your buffer setup. Drawing then is very easy:

// Drawing
 
GL.BindVertexArray(this.vertexArray);
 
// bind your shader here
 
GL.DrawElements(BeginMode.Triangles, this.indices.Length, DrawElementsType.UnsignedInt, IntPtr.Zero);
 
GL.BindVertexArray(0);

I really recommend you to use VAOs, as everything else is deprecated already. Using VBOs without a VAO is possible and not much slower (all you have to do is bind every buffer on its own during rendering instead of just binding the VAO), but an illegal operation in Core Profiles.

But: VAO+VBO is not usually the fastest way to draw your geometry. If your geometry is completely static, Display Lists tend to be as fast as or even faster than the buffers. I've read the slides of a conference talk from some NVIDIA guy a year ago where he stated that although there are these profile compatibility issues, he recommends professional game developers to rely on Display Lists. But please note that this is really only true for professional game developers where every single call on outdated hardware really matters. If the maximum performance was your main goal, you would not be using managed code and OpenTK in the first place ;)