Effectively draws a large number of polygons with OpenGL?

I am currently using opengl to draw several thousand polygons, and it works very slowly. To draw 8000 polygons, 100 ΞΌs is required.

Here is the information about my setup:

  • I have every object in my three-dimensional field defined as a collection of 2d polygonal planes, so the square will consist of 6, 4-vertex planes. Therefore, I have access to each individual aircraft.
  • I cannot guarantee that each polygon will have the same number of vertices
  • I am currently drawing the following:

    for(allPlanes){ glBegin(GL_POLYGON); for(allPointsInThePlane){ glVertex(pointX,pointY,pointZ); } glEnd(); } 

This is much slower than I expected and instead considered using glDrawElements () and breaking the planes of the polygons into triangles and using triangles or stripes to draw them.

I'm just looking for some tips on the most efficient way to do this or any criticism regarding how I approach the drawing.

+4
source share
3 answers

"Triangulate" and move the triangles to a larger VA / VBO .

EDIT : GLUtesselator shell:

 struct TessContext { ~TessContext() { for( size_t i = 0; i < combined.size(); ++i ) { delete[] combined[i]; } } vector< Eigen::Vector2d > pts; vector< GLdouble* > combined; }; #define APIENTRY __stdcall void APIENTRY tess_begin( GLenum type ) {} void APIENTRY tess_edgeFlag( GLboolean flag ) {} void APIENTRY tess_end() {} void APIENTRY tess_vertex( void *data, TessContext* ctx ) { GLdouble* coord = (GLdouble*)data; ctx->pts.push_back( Eigen::Vector2d( coord[0], coord[1] ) ); } void APIENTRY tess_combine( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData, TessContext* ctx ) { GLdouble* newVert = new GLdouble[3]; ctx->combined.push_back( newVert ); newVert[0] = coords[0]; newVert[1] = coords[1]; newVert[2] = coords[2]; *outData = newVert; } template< typename Vec > vector< Vec > Triangulate ( const vector< Vec >& aSimplePolygon ) { vector< GLdouble > coords; for( size_t i = 0; i < aSimplePolygon.size(); ++i ) { coords.push_back( aSimplePolygon[i].x() ); coords.push_back( aSimplePolygon[i].y() ); coords.push_back( 0 ); } GLUtesselator* tess = gluNewTess(); //gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD ); //gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO ); gluTessCallback( tess, GLU_TESS_BEGIN, (GLvoid (APIENTRY *)()) tess_begin ); gluTessCallback( tess, GLU_TESS_EDGE_FLAG, (GLvoid (APIENTRY *)()) tess_edgeFlag ); gluTessCallback( tess, GLU_TESS_VERTEX_DATA, (GLvoid (APIENTRY *)()) tess_vertex ); gluTessCallback( tess, GLU_TESS_END, (GLvoid (APIENTRY *)()) tess_end ); gluTessCallback( tess, GLU_TESS_COMBINE_DATA, (GLvoid (APIENTRY *)()) tess_combine ); gluTessNormal( tess, 0.0, 0.0, 1.0 ); TessContext ctx; gluTessBeginPolygon( tess, &ctx ); gluTessBeginContour( tess ); for( size_t i = 0; i < aSimplePolygon.size(); ++i ) { gluTessVertex( tess, &coords[i*3], &coords[i*3] ); } gluTessEndContour( tess ); gluTessEndPolygon( tess ); gluDeleteTess(tess); vector< Vec > ret( ctx.pts.size() ); for( size_t i = 0; i < ret.size(); ++i ) { ret[i].x() = ctx.pts[i].x(); ret[i].y() = ctx.pts[i].y(); } return ret; } 

Uses Eigen , but not for anything interesting.

+9
source

glDrawArrays () or glDrawElements () (or glDrawRangeElements () ) are the preferred method, as well as the only one not obsolete. Immediate mode (your example) is the slowest and least preferred method, useful mainly for OpenGL tutorials and (in my own experience) debugging. There are also display lists , "macros" for OpenGL, which are just one step higher, using the direct mode for drawing, and vertex buffer objects (VBOs) .

Anyone other than direct mode should be fast enough for your needs.

+6
source

Yes, using Triangulation (which is a special case of tessellation) to calculate the points and then drawing them is preferred (you used the immediate mode, which is deprecated)

The current graphic architecture uses shaders

Therefore, instead of sending a small set of vertices each time between the processor and the GPU, you should

  • Process all vertices at once, save them in the data structure and send them to gpu

  • Draw it right away (using the glDraw * () functions),

It’s faster because

  • The entire array is calculated only once and stored in the data structure so that it can be reused

  • Then the data is transferred completely to the GPU memory, where further operations can be performed without any additional bottleneck in the data transfer and associated service data (using programmable shaders)

+2
source

Source: https://habr.com/ru/post/1402964/


All Articles