12,761,826 members (43,565 online)
Technical Blog
alternative version

#### Stats

2.1K views
2 bookmarked
Posted 4 Feb 2017

# OpenGL 4 with OpenTK in C# Part 8: Drawing Multiple Objects

, 5 Feb 2017 CPOL
 Rate this:
How to reuse the Vertex Array and Buffers to draw the same model multiple times

In this post, we will look at how to reuse the Vertex Array and Buffers to draw the same model multiple times.

This is part 8 of my series on OpenGL4 with OpenTK.

For other posts in this series:

As stated in the previous post, I am in no way an expert in OpenGL. I write these posts as a way to learn and if someone else finds these posts useful, then all the better. :)

If you think that the progress is slow, then know that I am a slow learner. :P

This part will build upon the game window and shaders from part 6.

## Projection Matrix

As a starter, in the previous post, the cube looked a little odd. It had no real perspective and when the window was rescaled, it didn't behave as it should have, i.e., it got out of shape.

To solve this, we shall add a Projection Matrix to our solution.

In our vertex shader, we will add another uniform matrix in addition to the `modelView` matrix we already have as follows:

```#version 450 core

layout (location = 0) in vec4 position;
layout(location = 1) in vec4 color;

out vec4 vs_color;

layout(location = 20) uniform  mat4 projection;
layout (location = 21) uniform  mat4 modelView;

void main(void)
{
gl_Position = projection * modelView * position;
vs_color = color;
}```

Be sure to get the order of multiplications correct or else things will look very very strange.

In our `GameWindow`, let's add the following method to create this projection matrix.

```private void CreateProjection()
{

var aspectRatio = (float)Width/Height;
_projectionMatrix = Matrix4.CreatePerspectiveFieldOfView(
60*((float) Math.PI/180f), // field of view angle, in radians
aspectRatio,                // current window aspect ratio
0.1f,                       // near plane
4000f);                     // far plane
}```

Basically, we tell OpenTKs Matrix4 to create this matrix for us. And we want to supply the angle of the field of view together with the window aspect ratio and the near and far clipping planes.

Changing the angle is a cheap man's zoom of sorts, the aspect ratio helps keep things in shape even if we drag the window to strange sizes and the near and far clipping determine how close or far away an object can be and still be drawn on screen.

We want to call the `CreateProjection` from both the `OnLoad` and `OnResize` event handlers.

Then, in our `OnRenderFrame`, add a call to:

`GL.UniformMatrix4(20, false, ref _projectionMatrix);`

And we should be set.

## Drawing Multiple Objects

So, now that we have gone through the projection matrix, that should probably have been covered in an earlier post, but I did not know it at the time of writing. We can finally start with the topic of this post: Drawing multiple objects on screen.

Let's initialize a few different `RenderObjects` in our `OnLoad` method. As the only model we have at the moment is a cube, let's create some different colored ones so that we know the difference.

In reality, these would probably be different models that look differently all together. But for now, let's take what we have.

```protected override void OnLoad(EventArgs e)
{
VSync = VSyncMode.Off;
CreateProjection();

CursorVisible = true;

_program = CreateProgram();
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
GL.PatchParameter(PatchParameterInt.PatchVertices, 3);
GL.Enable(EnableCap.DepthTest);
Closed += OnClosed;
}```

So, now, we have 4 different `RenderObjects` created, each containing Vertex Arrays and Buffers. The next step is to draw them on the screen. But we don't want to just draw one of each, let's draw a bunch.

```protected override void OnRenderFrame(FrameEventArgs e)
{
_time += e.Time;
Title = \$"{_title}: (Vsync: {VSync}) FPS: {1f / e.Time:0}, z:{_z}";
GL.ClearColor(_backColor);

GL.UseProgram(_program);
GL.UniformMatrix4(20, false, ref _projectionMatrix);
float c = 0f;
foreach (var renderObject in _renderObjects)
{
renderObject.Bind();
for (int i = 0; i < 5; i++)
{
var k = i + (float)(_time * (0.05f + (0.1 * c)));
var t2 = Matrix4.CreateTranslation(
(float)(Math.Sin(k * 5f) * (c + 0.5f)),
(float)(Math.Cos(k * 5f) * (c + 0.5f)),
_z);
var r1 = Matrix4.CreateRotationX(k * 13.0f + i);
var r2 = Matrix4.CreateRotationY(k * 13.0f + i);
var r3 = Matrix4.CreateRotationZ(k * 3.0f + i);
var modelView = r1 * r2 * r3 * t2;
GL.UniformMatrix4(21, false, ref modelView);
renderObject.Render();
}
c += 0.3f;
}
GL.PointSize(10);
SwapBuffers();
}```

The projection matrix will stay the same during the whole frame, so we need only to set it once before the render loop.

Then for each model that we loaded (different colored cube in our case), let's apply some transforms and rotations, each object gets a unique model view matrix that we set.

Note that the same `RenderObject` is bound once but rendered multiple times, just with different translations.

In the `RenderObject`, we need to split the old `Render` method into a `Render` and `Bind` method for this to work.

```public void Bind()
{
GL.BindVertexArray(_vertexArray);
}
public void Render()
{
GL.DrawArrays(PrimitiveType.Triangles, 0, _verticeCount);
}```

The end results should be like this:

Full video: https://youtu.be/4st0qiSAGtU

Hope this helps someone out there. :)

No cat video today either, it seems to be an every other post thing currently.

Until next time: Work to Live, Don't Live to Work

## Share

 Architect Sweden
http://dreamstatecoding.blogspot.com