العديد من الكواد، وليس الكثير من الإطارات في الثانية على الرغم من VBO

StackOverflow https://stackoverflow.com/questions/6330851

سؤال

لقد حصلت على بعض الوقت وقرأت عن VBO وهذا ما حصلت عليه:

http://img64.imageshack.us/img64/5733/fps8.jpg

حسنًا، إنه أفضل بكثير من ذي قبل.تم تجميعها في الإصدار.أستخدم VBO (ربما، إذا كان كل شيء على ما يرام) وglDrawArrays للرسم.

وهنا رمز الرسم.من فضلك أعطني النصيحة حول كيفية تحسينه.أردت مع التضاريس ...اه بضعة آلاف من الإطارات في الثانية، هل هذا حقيقي؟

void DrawVBO (void)
{
    int i;

    CVert*      m_pVertices; 
    CTexCoord*  m_pTexCoords;

    unsigned int    m_nTextureId;

    m_pVertices = NULL;
    m_pTexCoords = NULL;
    m_nVertexCount = 0;
    m_nVBOVertices = m_nVBOTexCoords = m_nTextureId = 0;


    if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
    {
        // Pobierz wskaźniki na funkcje OpenGL 
        glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
        glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
        glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
        glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) 
        wglGetProcAddress("glDeleteBuffersARB"); 
    }

    todrawquads=0;
    nIndex=0;


// my function counting how many quads I will draw


    for (i=0;i<MAX_CHUNKS_LOADED;i++)
    {
        if (chunks_loaded[i].created==1)
        {
            countquads(i);
        }
    }

    m_nVertexCount=4*todrawquads;

    m_pVertices = new CVec[m_nVertexCount];
    m_pTexCoords = new CTexCoord[m_nVertexCount];

// another my function adding every quad which i'm going to draw (its verticles) to array

    for (i=0;i<MAX_CHUNKS_LOADED;i++)
    {
        if (chunks_loaded[i].created==1)
        {
            addchunktodraw(i,m_pVertices,m_pTexCoords);
        }
    }


    glClearColor (1,1,1, 0.0);
    glColor3f(1,1,1);

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
    glLoadIdentity ();                                          // Reset The Modelview Matrix

    fps++;

    // Camera settings.

    //gluLookAt (zom, zom, zom, 0.0, 0.0, 0.0, 0, 0, 1);

    gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
    glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
    glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
    glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

    //m_nTextureId = t_terrain;

    // Generate And Bind The Vertex Buffer
    glGenBuffersARB( 1, &m_nVBOVertices );                          // Get A Valid Name
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );         // Bind The Buffer
    // Load The Data
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB );

    // Generate And Bind The Texture Coordinate Buffer
    glGenBuffersARB( 1, &m_nVBOTexCoords );                         // Get A Valid Name
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );        // Bind The Buffer
    // Load The Data
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB );

    // Enable Pointers
    glEnableClientState( GL_VERTEX_ARRAY );                     // Enable Vertex Arrays
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );              // Enable Texture Coord Arrays

    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
    glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );       // Set The Vertex Pointer To The Vertex Buffer
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
    glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );     // Set The TexCoord Pointer To The TexCoord Buffe

    glDrawArrays( GL_QUADS, 0, m_nVertexCount); // Draw All Of The Triangles At Once

    glDisableClientState( GL_VERTEX_ARRAY );                    // Disable Vertex Arrays
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );             // Disable Texture Coord Arrays

    liniergb();

    glutSwapBuffers();

    delete [] m_pVertices; m_pVertices = NULL;
    delete [] m_pTexCoords; m_pTexCoords = NULL;
}

إذن ماذا يمكنني أن أفعل به؟(الرمز أعلاه هو وظيفة السحب الرئيسية)

يحرر

لقد قمت بنقل هذا :

if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
{
    // Pobierz wskaźniki na funkcje OpenGL 
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
    glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
    glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) 
    wglGetProcAddress("glDeleteBuffersARB"); 
}

إلى وظيفتي الرئيسية.ربما لا يوجد تحسن.

تحرير2

الآن، أستطيع أيضًا أن أرى أنه يأكل الذاكرة.كل بضع ثوانٍ، يزداد استخدام ذاكرة البرنامج أكثر فأكثر...ما هو الخطأ ؟ما الذي لا أحذفه؟

تحرير3

حسنًا، شكرًا جزيلاً.لقد قمت بنقل بعض التعليمات البرمجية خارج وظيفة السحب و ...المزيد من الإطارات في الثانية!ًشكراً جزيلا !

http://img197.imageshack.us/img197/5193/fpsfinal.jpg

إنها خريطة بحجم 640 × 640 كتلة (أكبر 40 مرة) مع 650000 كواد (حوالي 70 مرة أكثر) ولا تزال ~ 170 إطارًا في الثانية.عظيم !ولا تسرب الذاكرة.شكرًا لك مرة أخرى !

هل كانت مفيدة؟

المحلول

يجب أن تحتوي وظيفة DrawVBO الخاصة بك على ما يلي فقط:

glClearColor (1,1,1, 0.0);
glColor3f(1,1,1);

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
glLoadIdentity ();                                          // Reset The Modelview Matrix

fps++;

// Camera settings.

//gluLookAt (zom, zom, zom, 0.0, 0.0, 0.0, 0, 0, 1);

gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

// Enable Pointers
glEnableClientState( GL_VERTEX_ARRAY );                     // Enable Vertex Arrays
glEnableClientState( GL_TEXTURE_COORD_ARRAY );              // Enable Texture Coord Arrays

glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );       // Set The Vertex Pointer To The Vertex Buffer
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );     // Set The TexCoord Pointer To The TexCoord Buffe

glDrawArrays( GL_QUADS, 0, m_nVertexCount); // Draw All Of The Triangles At Once

glDisableClientState( GL_VERTEX_ARRAY );                    // Disable Vertex Arrays
glDisableClientState( GL_TEXTURE_COORD_ARRAY );             // Disable Texture Coord Arrays

liniergb();

glutSwapBuffers();

تحتاج إلى نقل الباقي إلى وظيفة منفصلة يتم استدعاؤها مرة واحدة فقط عند بدء التشغيل (أو عندما تتغير التضاريس).

نصائح أخرى

هل تقوم بإعادة تحميل كافة المخازن المؤقتة الخاصة بك وتحريرها مرة أخرى في كل إطار على حدة؟توقف عن فعل ذلك وسيرتفع معدل الإطارات لديك.

لاحظ أن كودك الحالي سوف ينفد في النهاية من معرفات VBO، نظرًا لأنك لا تحذف مطلقًا معرفات VBO التي تقوم بإنشائها.

ربط وظائف التمديد قطعاً لا يلزم القيام بكل إطار أيضًا.

تبرز بعض الأشياء:

في وظيفة الرسم، تقوم بتخصيص الذاكرة لبياناتك الهندسية

    m_pVertices = new CVec[m_nVertexCount];
    m_pTexCoords = new CTexCoord[m_nVertexCount];

يعد تخصيص الذاكرة عملية مكلفة للغاية، وهي واحدة من تلك الأشياء التي يجب القيام بها مرة واحدة فقط.ليس المقصود من OpenGL أن يتم "تهيئته" - لكن هياكل البيانات التي ستمررها إليها هي!

هنا تقوم بنسخ المخازن المؤقتة المخصصة حديثًا إلى OpenGL، مرارًا وتكرارًا مع كل إطار.وهذا هو بالضبط عكس ما يجب القيام به.

// Generate And Bind The Vertex Buffer
glGenBuffersARB( 1, &m_nVBOVertices );                          // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );         // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB );

// Generate And Bind The Texture Coordinate Buffer
glGenBuffersARB( 1, &m_nVBOTexCoords );                         // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );        // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB );

الفكرة الكاملة لـ VBOs هي تحميل البيانات مرة واحدة فقط، ونسخها إلى OpenGL ثم عدم إعادة تخصيصها مرة أخرى.لاحظ أن هذه ليست تهيئة OpenGL، إنها تهيئة بيانات، وهو أمر معقول تمامًا.أرى أنك قمت بتسمية المتغيرات الخاصة بك m_pVertices و m_pTexCoords تشير إلى أن هذه هي متغيرات أعضاء الفئة.ثم الحل بسيط:انقل رمز التهيئة بالكامل إلى بعض وظائف المُحمل.أيضًا بدلاً من صفائف C++ العارية أقترح بشدة استخدام std::vector.

لذلك دعونا نصلح هذا:

// Load Extensions only once. Well, once per context actually, however
// why don't you just use an extension wrapper and forget about those
// gritty details? Google GLEW or GLee
void init_extensions()
{
    if( IsExtensionSupported( "GL_ARB_vertex_buffer_object" ) )
    {
    // Pobierz wska\u017aniki na funkcje OpenGL 
    glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
    glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
    glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
    glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB"); 
    }
}

class Block0r
{
protected:
    GLuint m_nTextureId;
    GLuint m_nVBOVertices;
    GLuint m_nVBOTexCoords;
    GLuint m_nVertexCount;

    // Call this one time to load the data    
    void LoadVBO()
    {
        std::vector<CVert> vertices;
        std::vector<CTexCoord> texCoords;
        // my function counting how many quads I will draw

        todrawquads = 0;

        for(int i=0; i < MAX_CHUNKS_LOADED; i++) {
            if( chunks_loaded[i].created == 1 ) {
                countquads(i);
            }
        }

        m_nVertexCount = 4*todrawquads;

        vertices.resize(vertexcount);
        texcoords.resize(vertexcount);


        for (i=0;i<MAX_CHUNKS_LOADED;i++) {
            if (chunks_loaded[i].created==1) {
                addchunktodraw(i, &vertices[0], &texcoords[0]);
            }
        }

        glGenBuffersARB( 1, &m_nVBOVertices );
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
            glBufferDataARB( GL_ARRAY_BUFFER_ARB, vertices.size()*sizeof(CVert), &vertices[0], GL_STATIC_DRAW_ARB );

        glGenBuffersARB( 1, &m_nVBOTexCoords );
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
        glBufferDataARB( GL_ARRAY_BUFFER_ARB, texCoords.size()*sizeof(CTexCoord), &texCoords[0], GL_STATIC_DRAW_ARB );
    }

    void DrawVBO()
    {
        glClearColor (1,1,1, 0.0);
        glColor3f(1,1,1);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_PROJECTION);
            setup_projection(); // this should really be done in the drawing handler

        glMatrixMode(GL_MODELVIEW); // don't asssume a certain matrix being active!
        glLoadIdentity();

        fps++;

        gluLookAt (zoom, zoom, zoom, 0.0, 0.0, 0.0, 0, 0, 1);
        glRotatef((rot_x / 180 * 3.141592654f),1,0,0);  
        glRotatef((rot_y / 180 * 3.141592654f),0,1,0);
        glRotatef((rot_z / 180 * 3.141592654f),0,0,1);

        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_TEXTURE_COORD_ARRAY );

        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
        glVertexPointer( 3, GL_FLOAT, 0, (GLvoid *) 0 );

        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
        glTexCoordPointer( 2, GL_FLOAT, 0, (GLvoid *) 0 );

        glDrawArrays( GL_QUADS, 0, m_nVertexCount);
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_TEXTURE_COORD_ARRAY );
        liniergb();

        glutSwapBuffers();
    }
}

في ملحوظة جانبية:تعليقات مثل // Generate And Bind The Vertex Buffer أو // Set The Vertex Pointer To The Vertex Buffer ليست مفيدة للغاية.تخبرنا هذه التعليقات بشكل متكرر بما يمكن للمرء قراءته من الكود على أي حال.يجب إضافة التعليقات إلى التعليمات البرمجية، والتي لا يمكن فهم الأعمال الداخلية عليها على الفور، أو إذا كان عليك القيام بنوع من الاختراق لإصلاح شيء ما، وهذا الاختراق من شأنه أن يحير شخصًا آخر، أو نفسك في غضون بضعة أشهر.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top