openGL series article directory
Official website
Name
glDrawElements — render primitives from array data
C Specification
void glDrawElements( GLenum mode,
GLsizei count,
GLenum type,
const void * indices);
Parameters
mode
Specifies what kind of primitives to render. Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY and GL_PATCHES are accepted.
count
Specifies the number of elements to be rendered.
type
Specifies the type of the values in indices. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
indices
Specifies a pointer to the location where the indices are stored.
Description
glDrawElements specifies multiple geometric primitives with very few subroutine calls. Instead of calling a GL function to pass each individual vertex, normal, texture coordinate, edge flag, or color, you can prespecify separate arrays of vertices, normals, and so on, and use them to construct a sequence of primitives with a single call to glDrawElements.
When glDrawElements is called, it uses count sequential elements from an enabled array, starting at indices to construct a sequence of geometric primitives. mode specifies what kind of primitives are constructed and how the array elements construct these primitives. If more than one array is enabled, each is used.
Vertex attributes that are modified by glDrawElements have an unspecified value after glDrawElements returns. Attributes that aren't modified maintain their previous values.
Notes
GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP_ADJACENCY and GL_TRIANGLES_ADJACENCY are available only if the GL version is 3.2 or greater.
Errors
GL_INVALID_ENUM is generated if mode is not an accepted value.
GL_INVALID_VALUE is generated if count is negative.
GL_INVALID_OPERATION is generated if a geometry shader is active and mode is incompatible with the input primitive type of the geometry shader in the currently installed program object.
GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to an enabled array or the element array and the buffer object's data store is currently mapped.
Version Support
OpenGL Version
Function / Feature Name 2.0 2.1 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3 4.4 4.5
glDrawElements ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
See Also
glDrawArrays, glDrawElementsInstanced, glDrawElementsBaseVertex, glDrawRangeElements
Copyright
Copyright © 1991-2006 Silicon Graphics, Inc. Copyright © 2010-2014 Khronos Group. This document is licensed under the SGI Free Software B License. For details, see https://khronos.org/registry/OpenGL-Refpages/LICENSES/LicenseRef-FreeB.txt.
translate
Function function: use count elements to define a geometric sequence, and the index values of these elements are saved in the indexes array.
Parameter Description:
mode: the accepted value is the same as the value accepted in glBegin(), which can be GL_POLYGON,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_LINE_STRIP, etc.
count: the number of elements of the combined geometry, usually the number of points.
Type: the data type of the indeces array. Since it is an index, it is generally an integer.
Indexes: index array
describe
Gldrawelements specifies multiple geometry primitives with few subroutine calls. Instead of calling the GL function to pass each individual vertex, normal, texture coordinates, edge flag or color, you can specify a separate array of vertices, normals, etc. in advance and use them to construct a series of primitive elements through a single call to gldraineelements.
When gldrawelements is called, it uses the count order elements in the enabled array to construct a sequence of geometry from the index. The pattern specifies which primitives to construct and how array elements construct these primitives. If multiple arrays are enabled, vertex attributes modified with each array gldraineelements have unspecified values after gldraineelements is returned. Unmodified properties retain their previous values.
be careful
GL is available only when GL version is 3.2 or later_ LINE_ STRIP_ ADJACENCY, GL_ LINES_ ADJACENCY, GL_ TRIANGLE_ STRIP_ ADJACENCY and GL_ TRIANGLES_ Adjacency is available.
error
If the mode is not an acceptable value, GL is generated_ INVALID_ ENUM .
If the count is negative, GL is generated_ INVALID_ VALUE .
If a non-zero buffer object name is bound to an enabled array or array of elements, and the data store of the buffer object is currently mapped, GL is generated_ INVALID_ Operation.
Version support
OpenGL version
Function / feature name 2.0 2.1 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3 4.4.5
trace element ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
See also
GLDrawArray,glDrawElementsInstanced,glDrawElementsBaseVertex,glDrawRangeElements
copyright
copyright © Copyright 1991-2006 Silicon Graphics, Inc © 2010-2014 Khronos Group. This document is licensed under the SGI free software B license. For more information, see https://khronos.org/registry/OpenGL-Refpages/LICENSES/LicenseRef-FreeB.txt.
example
#include "glew/glew.h" #include "glfw/glfw3.h" #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #include "Utils.h" #include "Torus.h" #include "SOIL2/SOIL2.h" #include "camera.h" #include <iostream> #include <fstream> #include <string> using namespace std; static const float pai = 3.1415926f; float toRadins(float degress) { return (degress * 2.f * pai / 360.f); } GLuint renderingProgram = 0; static const int numVAOs = 1; static const int numVBOs = 4; GLuint vao[numVAOs] = { 0 }; GLuint vbo[numVBOs] = { 0 }; static const int screen_width = 1920; static const int screen_height = 1080; int width = 0; int height = 0; float cameraX = 0.f, cameraY = 0.f, cameraZ = 0.f; float torusLocX = 0.f, torusLocY = 0.f, torusLocZ = 0.f; GLuint torusTextureId = 0; float rotAmt = 0.f; //Y-axis rotation GLuint mvLoc = 0; GLuint projLoc = 0; float aspect = 0.f; glm::mat4 mMat(1.f), vMat(1.f), pMat(1.f), mvMat(1.f); Torus myTorus(0.5f, 0.2f, 48); Camera camera(glm::vec3(0.f, 0.f, 5.f)); float deltaTime = 0.f; float lastFrame = 0.f; GLboolean keys[1024] = { GL_FALSE }; GLboolean firstMouse = GL_TRUE; float lastLocX = 0.f; float lastLocY = 0.f; void processKeyInput(GLFWwindow* window); void setupVertices(void) { vector<int> ind = myTorus.getIndices(); //Get vertex index vector<glm::vec3> vert = myTorus.getVertices(); //Get each vertex, and any vertex contains (x, y, z) vector<glm::vec2> tex = myTorus.getTexCoords(); vector<glm::vec3> norm = myTorus.getNormals(); vector<glm::vec3> sTang = myTorus.getStangents(); vector<glm::vec3> tTang = myTorus.getTtangents(); vector<float> pValues; //Vertex Position vector<float> tValues; //Texture coordinates vector<float> nValues; //Normal coordinates for (int i=0; i<myTorus.getNumVertices(); i++) { pValues.push_back(vert[i].x); pValues.push_back(vert[i].y); pValues.push_back(vert[i].z); //Note that the texture coordinates here are S and T tValues.push_back(tex[i].s); tValues.push_back(tex[i].t); nValues.push_back(norm[i].x); nValues.push_back(norm[i].y); nValues.push_back(norm[i].z); } glGenVertexArrays(numVAOs, vao); glBindVertexArray(vao[0]); glGenBuffers(numVBOs, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glBufferData(GL_ARRAY_BUFFER, pValues.size() * sizeof(float), &(pValues[0]), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glBufferData(GL_ARRAY_BUFFER, tValues.size() * sizeof(float), &(tValues[0]), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); glBufferData(GL_ARRAY_BUFFER, nValues.size() * sizeof(float), &(nValues[0]), GL_STATIC_DRAW); //Note that we use glDrawElements to draw later, so GL must be used here_ ELEMENT_ ARRAY_ BUFFER glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * sizeof(float), &(ind[0]), GL_STATIC_DRAW); } void init(GLFWwindow* window) { renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl"); cameraX = 0.f, cameraY = 0.f, cameraZ = 2.f; torusLocX = 0.f, torusLocY = 0.f, torusLocZ = -0.5f; glfwGetFramebufferSize(window, &width, &height); aspect = (float)width / (float)height; pMat = glm::perspective(glm::radians(45.f), aspect, 0.01f, 1000.f); setupVertices(); torusTextureId = Utils::loadTexture("resources/brick1.jpg"); } void key_movement_callback() { if (keys[GLFW_KEY_W]) { camera.ProcessKeyboard(FORWARD, deltaTime); } if (keys[GLFW_KEY_S]) { camera.ProcessKeyboard(BACKWARD, deltaTime); } if (keys[GLFW_KEY_A]) { camera.ProcessKeyboard(LEFT, deltaTime); } if (keys[GLFW_KEY_D]) { camera.ProcessKeyboard(RIGHT, deltaTime); } } void display(GLFWwindow* window, float currentTime) { //Note that if GL_DEPTH_BUFFER_ Write bit as GL_DEPTH_BUFFER, residual shadows appear in the rendering window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.f, 0.1f, 0.8f, 1.f); glUseProgram(renderingProgram); GLfloat currentTimeFrame = glfwGetTime(); //deltaTime = currentTime - lastFrame; //lastFrame = currentTime; mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix"); projLoc = glGetUniformLocation(renderingProgram, "proj_matrix"); key_movement_callback(); vMat = camera.GetViewMatrix(); //vMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, -cameraZ)); mMat = glm::translate(glm::mat4(1.f), glm::vec3(torusLocX, torusLocY, torusLocZ)); mMat = glm::rotate(mMat, toRadins(60.f), glm::vec3(1.f, 0.f, 0.f)); aspect = (float)screen_width / (float)screen_height; pMat = glm::perspective(camera.Zoom, aspect, 0.01f, 1000.f); //Right multiplication rule mvMat = vMat * mMat; //Change the value of a uniform matrix variable or array. The location of the uniform variable to be changed is specified by location, and the value of location should be returned by the glGetUniformLocation function // Copy the perspective matrix and MV matrix to the corresponding unified variables /*Pass the consistent variable value into the rendering pipeline through the consistent variable (uniform decorated variable) reference. location : uniform The location of the. count : The number of array elements that need to load data or the number of matrices that need to be modified. transpose : Indicates whether the matrix is a column major matrix (GL_FALSE) or a row major matrix (GL_TRUE). value : Pointer to an array of count elements. */ glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat)); //Render Vertes glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); //Specifies the data format and location of the vertex attribute array whose index value is index at render time /*Parameters index Specifies the index value of the vertex attribute to modify size Specifies the number of components per vertex attribute. Must be 1, 2, 3, or 4. The initial value is 4. (dream dimension: for example, position is composed of 3 (x, y, z) and 4 (r, g, b, a)) type Specifies the data type of each component in the array. The available symbolic constants are GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, and GL_FLOAT, the initial value is GL_FLOAT. normalized Specifies whether fixed point data values should be normalized (GL_TRUE) or directly converted to fixed point values (GL_FALSE) when accessed. stride Specifies the offset between successive vertex attributes. If it is 0, the vertex attributes will be understood as: they are closely arranged together. The initial value is 0. pointer Specifies a pointer to the first component of the first vertex attribute in the array. The initial value is 0.*/ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); //Enable or disable the general vertex attribute array, the parameter 0 index corresponds to 0 in the layout(location = 0) in the shader, and the vertex position glEnableVertexAttribArray(0); //Process texture glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); Process normals //glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); //glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); //glEnableVertexAttribArray(2); //glBindBuffer(GL_ARRAY_BUFFER, vbo[3]); //glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0); //glEnableVertexAttribArray(3); //Activate texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, torusTextureId); /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_NEAREST_MIPMAP_NEAREST); glBindTexture(GL_TEXTURE_2D, sunTextureId);*/ //Backface culling is off by default glEnable(GL_CULL_FACE | GL_DEPTH_TEST); //Open back culling and depth test glFrontFace(GL_CCW); //glDepthFunc(GL_LEQUAL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]); glDrawElements(GL_TRIANGLES, myTorus.getIndices().size(), GL_UNSIGNED_INT, 0); } void window_size_callback(GLFWwindow* window, int newWidth, int newHeight) { glViewport(0, 0, newWidth, newHeight); aspect = (float)newWidth / (float)newHeight; pMat = glm::perspective(glm::radians(45.f), aspect, 0.01f, 1000.f); } void mouse_move_callback(GLFWwindow* window, double xPos, double yPos) { if (firstMouse) { lastLocX = xPos; lastLocY = yPos; firstMouse = GL_FALSE; } double offsetLocX = xPos - lastLocX; double offsetLocY = lastLocY - yPos; lastLocX = xPos; lastLocY = yPos; camera.ProcessMouseMovement(offsetLocX, offsetLocY); } void mouse_scroll_callback(GLFWwindow* window, double xPos, double yPos) { camera.ProcessMouseScroll(yPos * 0.1f); } void processKeyInput(GLFWwindow* window) { float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, GLFW_TRUE); } if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { camera.ProcessKeyboard(FORWARD, deltaTime); } if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { camera.ProcessKeyboard(BACKWARD, deltaTime); } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_KEY_A) { camera.ProcessKeyboard(LEFT, deltaTime); } if (glfwGetKey(window, GLFW_KEY_D)) { camera.ProcessKeyboard(RIGHT, deltaTime); } } void press_key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS)) { glfwSetWindowShouldClose(window, GL_TRUE); } if (action == GLFW_PRESS) { keys[key] = GL_TRUE; } else if (action == GLFW_RELEASE) { //glfwSetWindowShouldClose(window, GL_FALSE); keys[key] = GL_FALSE; } } int main(int argc, char** argv) { int glfwState = glfwInit(); if (GLFW_FALSE == glfwState) { cout << "GLFW initialize failed,invoke glfwInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl; glfwTerminate(); exit(EXIT_FAILURE); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); GLFWwindow* window = glfwCreateWindow(screen_width, screen_height, "Draw torus", nullptr, nullptr); if (!window) { cout << "GLFW create window failed,invoke glfwCreateWindow()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl; glfwTerminate(); exit(EXIT_FAILURE); } glfwMakeContextCurrent(window); glfwSetKeyCallback(window, press_key_callback); glfwSetWindowSizeCallback(window, window_size_callback); glfwSetCursorPosCallback(window, mouse_move_callback); glfwSetScrollCallback(window, mouse_scroll_callback); int glewState = glewInit(); if (GLEW_OK != glewState) { cout << "GLEW initialize failed,invoke glewInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl; glfwTerminate(); exit(EXIT_FAILURE); } glfwSwapInterval(1); init(window); while (!glfwWindowShouldClose(window)) { display(window, (float)glfwGetTime()); glfwSwapBuffers(window); glfwPollEvents(); } glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); return 0; }