In order to avoid pushing the same data multiple times, we can exploit the instanced rendering functions. We will now see how we can omit the multiple `glDrawElements`

calls in the previous recipe with a single `glDrawElementsInstanced`

call.

Before doing this, we assume that the reader knows how to use the geometry shader in the OpenGL 3.3 core profile. The code for this recipe is in the `Chapter1\SubdivisionGeometryShader_Instanced`

directory.

Converting the previous recipe to use instanced rendering requires the following steps:

Change the vertex shader to handle the instance modeling matrix and output world space positions (

`shaders/shader.vert`

).`#version 330 core layout(location=0) in vec3 vVertex; uniform mat4 M[4]; void main() {`

**gl_Position = M[gl_InstanceID]*vec4(vVertex, 1);**}Change the geometry shader to replace the

`MVP`

matrix with the`PV`

matrix (`shaders/shader.geom`

).#version 330 core layout (triangles) in; layout (triangle_strip, max_vertices=256) out; uniform int sub_divisions;

**uniform mat4 PV;**void main() { vec4 v0 = gl_in[0].gl_Position; vec4 v1 = gl_in[1].gl_Position; vec4 v2 = gl_in[2].gl_Position; float dx = abs(v0.x-v2.x)/sub_divisions; float dz = abs(v0.z-v1.z)/sub_divisions; float x=v0.x; float z=v0.z; for(int j=0;j<sub_divisions*sub_divisions;j++) {**gl_Position = PV * vec4(x,0,z,1); EmitVertex();****gl_Position = PV * vec4(x,0,z+dz,1); EmitVertex();****gl_Position = PV * vec4(x+dx,0,z,1); EmitVertex();****gl_Position = PV * vec4(x+dx,0,z+dz,1); EmitVertex();**EndPrimitive(); x+=dx; if((j+1) %sub_divisions == 0) { x=v0.x; z+=dz; } } }Initialize the per-instance model matrices (

`M`

).void OnInit() { //set the instance modeling matrix

**M[0] = glm::translate(glm::mat4(1), glm::vec3(-5,0,-5));****M[1] = glm::translate(M[0], glm::vec3(10,0,0));****M[2] = glm::translate(M[1], glm::vec3(0,0,10));****M[3] = glm::translate(M[2], glm::vec3(-10,0,0));**.. shader.Use(); shader.AddAttribute("vVertex");**shader.AddUniform("PV");****shader.AddUniform("M");**shader.AddUniform("sub_divisions"); glUniform1i(shader("sub_divisions"), sub_divisions);**glUniformMatrix4fv(shader("M"), 4, GL_FALSE, glm::value_ptr(M[0]));**shader.UnUse();Render instances using the

`glDrawElementInstanced`

call.void OnRender() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glm::mat4 T =glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, dist)); glm::mat4 Rx=glm::rotate(T,rX,glm::vec3(1.0f, 0.0f, 0.0f)); glm::mat4 V =glm::rotate(Rx,rY,glm::vec3(0.0f, 1.0f,0.0f));

**glm::mat4 PV = P*V;**shader.Use();**glUniformMatrix4fv(shader("PV"),1,GL_FALSE,glm::value_ptr(PV));**glUniform1i(shader("sub_divisions"), sub_divisions);**glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0, 4);**shader.UnUse(); glutSwapBuffers(); }

First, we need to store the model matrix for each instance separately. Since we have four instances, we store a uniform array of four elements (`M[4]`

). Second, we multiply the per-vertex position (`vVertex`

) with the model matrix for the current instance (`M[gl_InstanceID]`

).

### Tip

Note that the `gl_InstanceID`

built-in attribute will be filled with the index of each instance automatically at the time of the `glDrawElementsInstanced`

call. Also note that this built-in attribute is only accessible in the vertex shader.

The `MVP`

matrix is omitted from the geometry shader since now the input vertex positions are in world space. So we only need to multiply them with the combined view projection (`PV`

) matrix. On the application side, the `MV`

matrix is removed. Instead, we store the model matrix array for all four instances (`glm::mat4 M[4]`

). The values of these matrices are initialized in the `OnInit()`

function as follows:

M[0] = glm::translate(glm::mat4(1), glm::vec3(-5,0,-5)); M[1] = glm::translate(M[0], glm::vec3(10,0,0)); M[2] = glm::translate(M[1], glm::vec3(0,0,10)); M[3] = glm::translate(M[2], glm::vec3(-10,0,0));

The rendering function, `OnRender()`

, creates the combined view projection matrix (`PV`

) and then calls `glDrawElementsInsntanced`

. The first four parameters are similar to the `glDrawElements`

function. The final parameter is the total number of instances desired. Instanced rendering is an efficient mechanism for rendering identical geometry whereby the `GL_ARRAY_BUFFER`

and `GL_ELEMENT_ARRAY_BUFFER`

bindings are shared between instances allowing the GPU to do efficient resource access and sharing.

void OnRender() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glm::mat4 T = glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, 0.0f, dist)); glm::mat4 Rx = glm::rotate(T, rX, glm::vec3(1.0f, 0.0f, 0.0f)); glm::mat4 V = glm::rotate(Rx, rY, glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 PV = P*V; shader.Use();glUniformMatrix4fv(shader("PV"),1,GL_FALSE,glm::value_ptr(PV));glUniform1i(shader("sub_divisions"), sub_divisions);glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,0, 4);shader.UnUse(); glutSwapBuffers(); }

There is always a limit on the maximum number of matrices one can output from the vertex shader and this has some performance implications as well. Some performance improvements can be obtained by replacing the matrix storage with translation and scaling vectors, and an orientation quaternion which can then be converted on the fly into a matrix in the shader.

The official OpenGL wiki can be found at http://www.opengl.org/wiki/Built-in_Variable_%28GLSL%29.

An instance rendering tutorial from OGLDev can be found at http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html.