 An example, 10.1, instancing quads. What we see here are a bunch of quads that are being rendered. And the most obvious way to do this, given what we've seen so far, is we could either create a vertex buffer that has all the geometry information for each one of these 100 quads, or the vertex buffer would have just a single quad, and we'd simply call draw arrays 100 times, each time setting different uniforms for a position of the quad and also for its scale. Either solution would get what we see here, but the problem is not a solution is very efficient. In the first case, constructing a vertex buffer with 100 different quads, well, that's a lot of redundant data taking up memory and having to be transferred from system memory to GPU memory. So that's not ideal. And the other solution, making 100 draw calls, that's not efficient either because draw calls tend to have significant overhead. So the best solution here is to use what's called instancing. Looking at the code, our vertex buffer is only going to have the quad defined once, six positions and six colors, but then when we render, we'll be calling draw arrays instanced. And in this call, we're drawing triangles starting at an offset of zero within our vertex buffer. We'll render six vertices from the buffer, but we're drawing this 100 times. We're drawing 100 instances. Each instance we want to draw in a different position, so that also has to be passed in through the vertex array object. And these positions, these offsets are specified in what we might call an instance buffer object, which is just an array buffer, like we've seen many times before. The data at stores is coming from this translations array, which is a bunch of two values, bunch of X and Y offset values that we've set up in this loop. And then when we add this vertex buffer object into the vertex array object, we do one new special thing in the configuration. We call vertex attrib divisor, where the first value two here, that's just the index into the vertex array object, just like here and here in these calls. But then the second value, this one here, if the value here were zero, then this attribute would be read from the buffer advancing to the next one per vertex like normal. And this is the default. So if you don't call vertex attrib divisor, it's like calling it and providing the value zero here. But with the argument one, like we have here, now the attribute is advancing once per instance, not per vertex. And so in our draw arrays instance called those same six vertices are being rendered 100 times. But for the first six vertices, it'll be the same first translation value of this attribute. In the second instance, it'll be the second translation value from this attribute. For the third instance, it'll be the third attribute value and so forth. So effectively in the vertex shader, it's going to get a different translation value for different instances. We could also make this argument two, in which case the value would advance for every two instances or three, in which case it would advance for every three instances and so forth. Sometimes that's useful, but in our case, we want a different translation for every single instance. So looking at the shaders, our fragment shader is nothing new. But then in the vertex shader, while we're getting the coordinate positions, the color value, and also this offset, this is the translation per instance. And this is the value that's going to be the same for the six vertices of each instance. The position and color values will be different for each of the six vertices. But to render 100 instances, this vertex shader will run 600 times. And so each different position and color value is actually going to show up in 100 different calls of this vertex shader. We're setting here the output color to just the input color. The output position is the input position but modified by the offset. But first we're going to scale down the positions so the different instances are rendered at different sizes. And we can do this using the special variable glInstanceId, which for the first instance will be zero. For the second it'll be one, for the third it'll be two, etc. All the way up to 99 for our hundredth and last instance. So for our first instance, our position is going to be multiplied by 1 over 100, effectively shrinking our first quad way down. For the second instance, it'll be two over 100 and the third instance will be three over 100. So the quads for each instance are getting bigger and bigger until eventually in the last case, it's 100 over 100, which is one, so it's not scaled down at all. And that's the only instance here that'll be rendered at full size. And that's how we get this output. The first instance is in the bottom left, then the second, the third, the fourth, the fifth, the sixth. And then all the way up until the top right, that is the last and final instance. Now of course, drawing just 100 quads is not really going to tax any modern hardware. But looking at this Asteroids example, here we're not doing instance rendering. And this is a lot of Asteroids, sure, but what if we could have a lot more than this? If we make too many draw calls in a single frame, then it's going to get bogged down pretty quick. I won't walk through this code in detail, because it's all stuff we've seen before basically. But first we're drawing the planet, and then we're drawing the meteorites. And each time we do, we're setting a different model transform matrix from this array that we've constructed in this loop up here. First, we pick a random point on the circle on the orbit of the Asteroids, and then we randomly displace them a little bit off the orbit so that they're not exactly on the same orbit. And then we add in a little random amount of scaling and some random rotation. And so we end up with an array of a bunch of different transform matrices for all the Asteroids. When we then render, we're making a separate draw call each time. And in this case, the number of draw calls is amount, what is this? This is a thousand up here. Let's increase this a bit, and we'll start seeing the performance degrade. I'm going to rebuild here, and oh yeah, this is bad. Even on my system, which is very powerful, apparently 10,000 separate draw calls per frame is not a good idea. I'm getting a single digit frame number here. Now if we take this example and instead use instance rendering, like here in Asteroids Instanced, we're going to get much better results. This is 100,000 Asteroids, and on my system they're rendering perfectly smoothly. I'm running the, I don't know what the frame rate is exactly, but it's still quite high. So this is obviously a lot better than making a separate draw call each time. Now in fact, what if I were to increase this up to, it's currently 100,000. Let's make it 250, I think 300,000 will start straining too much, but let's go up. And now I'm starting to see some degradation in the frame rate. It doesn't feel nearly as smooth. Still pretty high, not very consistent, but it's reasonably high. And that's a lot of Asteroids, probably more than you would ever really want to render. The difference in this version is that we are using instance rendering. We're calling draw elements instanced. Draw elements, remember, uses indexes for the vertices. And this variant, the instance variant of course does instance rendering. So now in our VAO here, all the Asteroid transforms are stored in the buffer, and that's done up here. And kind of the odd thing is that we actually need four separate vertex of trips because it turns out that in a trip size cannot be greater than four floats and a four by four matrix is made up of 16 floats. So we have to use four separate vertex of trips and note the divisor here. They'll have a divisor of one because we want every separate instance to have its own transform. And so with this properly configured in the vertex shader for rendering our Asteroids, the model transfer matrix will come in here to a instance matrix and this will be different for every instance, not every vertex.