420 likes | 665 Views
Primitives. Primitives. Primitives are what get rendered to make shapes. There are points, lines, line strips, triangles, triangle strips, and triangle fans. points lines triangles
E N D
Primitives • Primitives are what get rendered to make shapes. • There are points, lines, line strips, triangles, triangle strips, and triangle fans. points lines triangles line list triangle list triangle fan
Primitives • Primitives are made up of vertices; • A vertex is (typically) a position, plus some other information associated with that vertex. • ▫ Position ▫ Normal▫ Texture Coordinate(s)▫ Color ▫ Material ID▫ Whatever…
Primitives • Primitives are made up of vertices; • A vertex is (typically) a position, plus some other information associated with that vertex. • ▫ Position ▫ Normal▫ Texture Coordinate(s)▫ Color ▫ Material ID▫ Whatever… These, collectively, are the vertex ATTRIBUTES
Primitives • Primitives are made up of vertices; • A vertex is (typically) a position, plus some other information associated with that vertex. Vertex Attributes ▫ Position ▫ Normal ▫ Texture Coordinate(s) ▫ Color ▫ Material ID ▫ Whatever…
Primitives Vertex 0 Vertex Attributes ▫ Position ▫ Normal ▫ Texture Coordinate(s) ▫ Color ▫ Material ID ▫ Whatever…
Primitives Vertex 0 Vertex 2 Vertex 1
Primitives Each vertex has a set of attributes Each vertex has the SAME number of attributes Vertex 0 Vertex 2 Vertex 1
Primitives Sidebar: Winding Order Vertex 0 The winding order is how OpenGL “knows” what the front and back of the triangle are. Which side is considered the "front" side is set by the function glFrontFace. Vertex 2 Vertex 1
Primitives Sidebar: Winding Order Vertex 0 The winding order is how OpenGL “knows” what the front and back of the triangle are. Which side is considered the "front" side is set by the function glFrontFace. Vertex 2 Vertex 1 This is global state. mode may be GL_CW (clockwise = left-hand rule) or GL_CCW (counter-clockwise = right-hand rule) is front, respectively. The default is GL_CCW.
Primitives • Primitives are made up of vertices; • A vertex is (typically) a position, plus some other information associated with that vertex. • ▫ Position ▫ Normal▫ Texture Coordinate(s)▫ Color ▫ Material ID
Primitives • There is a limit to the number of attributes you can have for a vertex. An attribute can have 1,2,3 or 4 elements. • glGet(GL_MAX_VERTEX_ATTRIBS); • the maximum number of 4-component generic vertex attributes accessible to a vertex shader. The value must be at least 8 for 2.0, 16 for 3+.
Primitives V7 V5 V2 V1 V4 V7 V0 V3 Attributes: Position
Primitives V7 V5 V2 V1 8 vertices 8 positions V4 V7 V0 V3 Attributes: Position
Primitives 12 TRIANGLES P0,P1,P3 P1,P2,P3 P1,P5,P2 P5,P6,P2 P5,P6,P7 P5,P7,P4 P4,P7,P3 P4,P3,P0 P0,P1,P4 P1,P5,P4 P2,P6,P7 P2,P7,P3 P6 P5 P2 P1 8 vertices 8 positions 6 faces 2 triangles/face 12 triangles P4 P7 P0 P3 Attributes: Position = 12 triangles
Primitives 12 TRIANGLES P0,P1,P3 P1,P2,P3 P1,P5,P2 P5,P6,P2 P5,P6,P7 P5,P7,P4 P4,P7,P3 P4,P3,P0 P0,P1,P4 P1,P5,P4 P2,P6,P7 P2,P7,P3 P6 P5 P2 P1 8 vertices 8 positions P4 P7 P0 P3 Attributes: Position
Primitives 12 TRIANGLES P0,P1,P3 P1,P2,P3 P1,P5,P2 P5,P6,P2 P5,P6,P7 P5,P7,P4 P4,P7,P3 P4,P3,P0 P0,P1,P4 P1,P5,P4 P2,P6,P7 P2,P7,P3 P6 P5 P2 P1 8 vertices 8 positions 6normals P4 P7 P0 P3 Attributes: Position, Normals
Primitives 36 TRIANGLES P0-N0,P1-N0,P3-N0 … P0-N3,P3-N3,P4-N3 … P0-N4,P1-N4,P4-N4 P6 P5 P2 P1 24 vertices 8 positions 6normals P4 P7 P0 P3 Attributes: Position, Normals
Primitives VEC3 36 TRIANGLES TRIANGLE VERTEX 3 Floats P0-N0,P1-N0,P3-N0 … P0-N3,P3-N3,P4-N3 … P0-N4,P1-n4,P4-n4 3 Vertices Position - vec3 Normal – vec3 3 x 3 vertices = 48 bytes 3 floats/vec3 = 3x4 bytes/float= 12 bytes 36 triangles = 864 bytes 2 x 12 bytes = 24 bytes 1 cube w/pos,norm = 864 bytes 1 cube w/pos,norm, 2UV’s = 1440 bytes 1 cube w/pos,norm = 864 bytes 1 cube w/pos,norm = 864 bytes 1 cube w/pos,norm, 2UV’s = 1440 bytes 1 cube w/pos,norm, 3UV’s, tangent, Material ID = 2628 bytes
Primitives VEC3 36 TRIANGLES TRIANGLE VERTEX 3 Floats P0-N0,P1-N0,P3-N0 … P0-N3,P3-N3,P4-N3 … P0-N4,P1-n4,P4-n4 3 Vertices Position - vec3 Normal – vec3 3 x 3 vertices = 48 bytes 3 floats/vec3 = 3x4 bytes/float= 12 bytes 36 triangles = 864 bytes 2 x 12 bytes = 24 bytes 1 cube w/pos,norm = 864 bytes 1 cube w/pos,norm, 2UV’s = 1440 bytes 1 cube w/pos,norm, 3UV’s, tangent, Material ID = 2628 bytes
Primitives Yes, you can use lots and lots of memory rendering a primitive. This is called BANDWIDTH Bandwidth is your enemy Avoid Bandwidth at all costs Bandwidth is a performance killer Bandwidth is a battery killer It will make your app bloated and slow It will take longer to load and download No one will want to play with you if you are bloated and slow Performance Tip: Strive to use as little bandwidth as possible!
Primitives • Methods of reducing primitive bandwidth (in order): • Do not let your artists go wild • Agree on a few (very few) minimal vertex formats • Use the minimum vertex count possible(i.e. do not use high-detail models when you don’t need to) • Reuse vertices by using indexed vertices. • Use higher-order primitive. • Use Instanced rendering. • Store data on the GPU (server side) if possible. • Compress your client side data – unpack it in the shader. • Tell (hint) OpenGL the data usage (i.e. static, dynamic). • Use Level-of-Detail (LOD) primitive sets. • Use advanced shaders (compute, tessellation, geometry)YMMV
Primitives Use a higher order primitive. You can get good reuse if you use one of the STRIPS or FANS primitives. The longer the primitive, the more efficient – approaching 66% reduction overall in vertex buffer size.
Primitives Tailor vertex data storage and usage Example 1a: Vertex Arrays - nonindexed GLfloat cube[] = { 0.5f,-0.5f,-0.5f, 0.5f, 0.5f,-0.5f, 0.5f, 0.5f, 0.5f, 0.5f,-0.5f, ... -0.5f, 0.5f,-0.5f, 0.5f, 0.5f,-0.5f}; // 36 total floats glVertexAttribPointer(0, // index of the attribute 3, // number of components 1, 2, 3, or 4 GL_FLOAT, // data type of the components GL_FALSE, // normalize? 0, // stride cube); // pointer to the start of vertex attribute data glEnableVertexAttribArray(0); // enable attribute 0 // use the vertex array to draw triangles glDrawArrays(GL_TRIANGLES,0,36); glDisableVertexAttribArray(0); // disable attribute 0
Primitives Tailor vertex data storage and usage Example 1b: Vertex Arrays - indexed GLfloatcube[] = { -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f }; // 24 total floats GLushortindices[] = {0,1,2, 0,7,1, 7,5,3, 7,3,1, 4,5,6, 4,6,2, 3,4,2, 3,5,4, 2,1,3, 2,6,0, 6,7,0, 6,5,7,}; glVertexAttribPointer(0, // index of the attribute 3, // number of components 1, 2, 3, or 4 GL_FLOAT, // data type of the components GL_FALSE, // normalize? 0, // stride cube); // pointer to the start of vertex attribute data glEnableVertexAttribArray(0); // enable attribute 0 // use the index array and the vertex array to draw triangles glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices ); glDisableVertexAttribArray(0); // disable attribute 0
Primitives • Tailor vertex data storage and usage • Example 2: Vertex Buffer Objects • The problem with Vertex Arrays are that when you issue a glDrawXXXcommand the data must be copied from client memory to graphics memory. Every time you draw. You can avoid this overhead using Vertex Buffer Objects (VBO’s). • Creates buffers in GPU memory • Memory is resident on GPU • Can free up memory on client side • Can provide “hints” of usage • Enable/Disable via the currently “bound” buffer
Primitives • Tailor vertex data storage and usage • Example 2: Vertex Buffer Objects - creation • GLuintIDs[2]; • structvertStruct{ … // vertex interleaved data }; • vertStructverts[100] = {…}; • Glubyteindx[300] = {…}; • glGenBuffers(2, IDs); // one for vertex, one for index • // vertex data • glBindBuffer(GL_ARRAY_BUFFER, IDs[0]); • glBufferData(GL_ARRAY_BUFFER, 100 * sizeof(vertStruct),verts, GL_STATIC_DRAW); • // index data • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IDs[1]); • glBufferData(GL_ARRAY_BUFFER, 300* sizeof(Glubyte),indx,GL_STATIC_DRAW); • unsigned int stride = sizeof(vertStruct); • glEnableVertexAttribArray(0); • glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,stride,(void *)0); • glEnableVertexAttribArray(1); // plus any more in the vertex attribs • glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,stride,(void *)(sizeof(float)*3)); • glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (void *)0 ); • glDisableVertexAttribArray(1); • glDisableVertexAttribArray(0); • glBindBuffer(GL_ARRAY_BUFFER, 0); • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Primitives • The idiosyncratic glVertexAttribPointer command • The glVertexAttribPointercommand is one command with two distinct functions. The OpenGL-ES version still has the functionality that was deprecated in OpenGL, while it also has newer additional functionality. • Rather than have a new function that provides access to the new functionality, the glVertexAttribPointerfunction provides two separate but similar bits of functionality – depending upon the OpenGL state. • It is used to describe the vertex data format, size and offsets in both cases. • By default, it points to the vertex attribute data that sits on the CPU side that you want to use for rendering. It renders vertex arrays. • IF there is a VBO active, the arguments do NOT point to the data but you pass in the offset of the VBO array that is active. Hence the last argument will require a cast from an unsigned integer to a pointer, even though it’s an offset and not an address. • void glVertexAttribPointer(GLuintindex, • GLint size, • GLenum type, • GLboolean normalized, • GLsizei stride, • constGLvoid * pointer); • Specifies a pointer to the first generic vertex attribute in the array. If a non-zero buffer is currently bound to the GL_ARRAY_BUFFER target, pointer specifies an offset of into the array in the data store of that buffer.
Primitives Use Instanced Rendering. (OpenGL-ES 3.0) Instancing is a way of executing the same drawing commands many times with one function call. You can render the same vertex data many times with different results. You perform instanced rendering with; glDrawArraysInstanced glDrawElementsInstanced And use the glVertexAttribDivisor command to skip to sequential elements in a vertex array or you can use the shader variable GL_INSTANCE_ID and do something in the shader.
Primitives Use Instanced Rendering.Example 3a: Multiple objects non-instanced rendering Position0, Position1, Position2...PositionN Attrib 0 Normal0, Normal1, Normal2...NormalN Attrib 1 Matrix0, Matrix1, Matrix2...MatrixN for (inti = 0; i < NumInstances; ++i) { glUniformMatrix4fv(…); // send matrix[i] glDrawElements(…); // render object }
Primitives Use Instanced Rendering. (OpenGL-ES 3.0)Example 3b: Multiple objects instanced rendering Position0, Position1, Position2...PositionN Attrib 0 Normal0, Normal1, Normal2...NormalN Attrib 1 Matrix0, Matrix1, Matrix2...MatrixN Attrib 2-5 // tell it NOT to advance per vertex, // but per N instances rendered, here N=1 glVertexAttribDivisor(2, 1); glDrawElementsInstanced(…,NumInstances);
Primitives Use Indirect Rendering. (OpenGL-ES 3.1) OpenGL-ES 3.1 introduces Indirect Rendering, which allows you to fetch arguments from buffer objects. This allows you to generate arguments on the GPU and then draw from the GPU, without CPU intervention. Typical examples are particle systems or animation systems.
Primitives • Packing even MORE into your render call…
Primitives Packing vertex data by stitching strips Example 3a: using degenerate triangles 0 10 1 2 3 4 11 12 13 14 5 15 6 7 8 9 16 17 18 19 Strip 2: 10,15,11,16,12,17,13,18,14,19 Triangles: 9[10 15 11] 10[15 11 16] 11[11 16 12] … 15[13 18 14] 16[18 14 19] Strip 1: 0,5,1,6,2,7,3,8,4,9 Triangles: 1[0 5 1] 2[5 1 6] 3[1 6 2] … 7[3 8 4] 8[8 4 9] A degenerate triangle is one that has no area – which can be created by reusing two vertices – OpenGL knows not to render degenerate triangles.
Primitives Packing vertex data by stitching strips Example 3a: using degenerate triangles 0 9a 10 1 2 3 4 11 12 13 14 5 15 6 7 8 9 16 17 18 19 Triangles: D1[4 9 9a] D2[9 9a 10] Strip 2: 10,15,11,16,12,17,13,18,14,19 Triangles: 9[10 15 11] 10[15 11 16] 11[11 16 12] … 15[13 18 14] 16[18 14 19] Strip 1: 0,5,1,6,2,7,3,8,4,9 Triangles: 1[0 5 1] 2[5 1 6] 3[1 6 2] … 7[3 8 4] 8[8 4 9] A degenerate triangle is one that has no area – which can be created by reusing two vertices – OpenGL knows not to render degenerate triangles.
Primitives Packing vertex data by stitching strips Example 3a: using degenerate triangles 0 9a 10 1 2 3 4 11 12 13 14 5 10a 15 6 7 8 9 16 17 18 19 Triangles: D1[4 9 9a] D2[9 9a 10a] D3[9a 10a 10] D4[10a 10 15] Strip 2: 10,15,11,16,12,17,13,18,14,19 Triangles: 9[10 15 11] 10[15 11 16] 11[11 16 12] … 15[13 18 14] 16[18 14 19] Strip 1: 0,5,1,6,2,7,3,8,4,9 Triangles: 1[0 5 1] 2[5 1 6] 3[1 6 2] … 7[3 8 4] 8[8 4 9] A degenerate triangle is one that has no area – which can be created by reusing two vertices – OpenGL knows not to render degenerate triangles.
Primitives Packing vertex data by stitching strips Example 3a: using degenerate triangles 0 10 1 2 3 4 11 12 13 14 5 15 6 7 8 9 16 17 18 19 Degenerate Triangles: D1[4 9 9] D2[9 9 10] D3[9 10 10] D4[10 10 15] Strip 2: 10,15,11,16,12,17,13,18,14,19 Triangles: 9[10 15 11] 10[15 11 16] 11[11 16 12] … 15[13 18 14] 16[18 14 19] Strip 1: 0,5,1,6,2,7,3,8,4,9 Triangles: 1[0 5 1] 2[5 1 6] 3[1 6 2] … 7[3 8 4] 8[8 4 9] A degenerate triangle is one that has no area – which can be created by reusing two vertices – OpenGL knows not to render degenerate triangles.
Primitives Packing vertex data by stitching strips Example 3a: using degenerate triangles 0 10 1 2 3 4 11 12 13 14 5 15 6 7 8 9 16 17 18 19 Degenerate Triangles: D1[4 9 9] D2[9 9 10] D3[9 10 10] D4[10 10 15] Strip 2: 10,15,11,16,12,17,13,18,14,19 Strip 1: 0,5,1,6,2,7,3,8,4,9 Strip 1&2: 0,5,1,6,2,7,3,8,4,9,9,10,10,15,11,16,12,17,13,18,14,19 A degenerate triangle is one that has no area – which can be created by reusing two vertices – OpenGL knows not to render degenerate triangles.
Primitives Packing vertex data by stitching strips (OpenGL-ES 3.0) Example 3b: using primitive restart 0 10 1 2 3 4 11 12 13 14 5 15 6 7 8 9 16 17 18 19 Strip 1&2: 0,5,1,6,2,7,3,8,4,9,-1,10,15,11,16,12,17,13,18,14,19 In OpenGL-ES 3.0 you can set a special index value in the index array to indicate that you want the primitive to start over. This is the maximum positive value that the index size can hold. The size of the index array elements is one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT. You must 1st enable this state through the call: glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);