Performance Problem

Hello,
i am working on a little CAD-system. my scene has only one object at this time. this object is a geosphere with 5120 triangles and 2562 vertices for testing the performance.

the vertices and mesh-description for the geosphere are precalculated, so that they would not be calculated while rendering. access-members for complex classes in my structure like cobject, cvertex, cmeshface, will always return references for faster access.

i am using visual c++ in release-mode and no vertical synchronization for my gfx-card and monitor.

when i render in imidiate mode, i get only 7 fps. using a displaylist for the geosphere speeds up rendering to 50 fps. i think this is not very fast, because popular games render more triangles in less times.

here is the render-method :

void C3DViewGL::RenderScene()
{
CExp3DDoc *pDoc = (CExp3DDoc *) GetDocument();
if (!pDoc) return;

CScene *pScene = pDoc->GetScene();
if (!pScene) return;    

wglMakeCurrent(m_hDC,m_hRC);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

RenderGrid();

glRotatef(m_rotAngleX,1.0,0.0,0.0);
glRotatef(m_rotAngleY,0.0,1.0,0.0);
glRotatef(m_rotAngleZ,0.0,0.0,1.0);
glTranslatef(m_trans[1],m_trans[2],m_trans[3]);    

glBegin(GL_TRIANGLES);    
for (long i=0; i < pScene->Get3DObjectCount(); i++)
{        
    C3DObject *pObject = pScene->Get3DObjectAt(i);
    if (pObject) 
    {
        if (pObject->GetMemObj())            
            //Execute displaylist
            pObject->GetMemObj()->Execute();
            
        else 
            //Render in imidiate-mode
            RenderObject(pObject);
    }
}    
glEnd();

RenderCoorSys();

SwapBuffers(m_hDC);
glPopMatrix();

}

void C3DViewGL::RenderObject(C3DObject *pObject)
{
CScene *pScene = pObject->GetScene();
if (!pScene) return;

if (pScene->GetColorMode() == CM_OBJECT)
    glColor3f(pObject->GetRed()/255.0, pObject->GetGreen()/255.0, pObject->GetBlue()/255.0);
for (long j=0; j < pObject->GetMeshFaceCount(); j++)
{
    CMeshFace *pMesh = pObject->GetMeshFaceAt(j);
    if (pMesh)
    {
        CVertex *pA, *pB, *pC;                    
        pA = pObject->GetVertexAt(pMesh->GetIndexA());
        pB = pObject->GetVertexAt(pMesh->GetIndexB());
        pC = pObject->GetVertexAt(pMesh->GetIndexC());
        if (pA && pB && pC)
        {                        
            if (pScene->GetShadingModel() == SM_FLAT)
                glNormal3f(pMesh->GetNormal()[1], pMesh->GetNormal()[2], pMesh->GetNormal()[3]);

            if (pScene->GetShadingModel() == SM_SMOOTH)
                glNormal3f(pA->GetNormal()[1], pA->GetNormal()[2], pA->GetNormal()[3]);
            if (pScene->GetColorMode() == CM_VERTEX)
                glColor3f(pA->GetRed()/255.0, pA->GetGreen()/255.0, pA->GetBlue()/255.0);
            glVertex3f(pA->GetVertex()[1], pA->GetVertex()[2], pA->GetVertex()[3]);

            if (pScene->GetShadingModel() == SM_SMOOTH)
                glNormal3f(pB->GetNormal()[1], pB->GetNormal()[2], pB->GetNormal()[3]);
            if (pScene->GetColorMode() == CM_VERTEX)
                glColor3f(pB->GetRed()/255.0, pB->GetGreen()/255.0, pB->GetBlue()/255.0);
            glVertex3f(pB->GetVertex()[1], pB->GetVertex()[2], pB->GetVertex()[3]);

            if (pScene->GetShadingModel() == SM_SMOOTH)
                glNormal3f(pC->GetNormal()[1], pC->GetNormal()[2], pC->GetNormal()[3]);
            if (pScene->GetColorMode() == CM_VERTEX)
                glColor3f(pC->GetRed()/255.0, pC->GetGreen()/255.0, pC->GetBlue()/255.0);
            glVertex3f(pC->GetVertex()[1], pC->GetVertex()[2], pC->GetVertex()[3]);
        }
    }
} 

}

maybe someone can give me a hint to speed this up !

best regards

tabor25

You’re doing a bunch of conditional logic and unneccesary checks in the rendering function which slows you way down. That’s why it speeds up so much when using a display list. Read this document on performance in OpenGL. To get better performance, abstract at a higher level, having a class called CVertex and sending this class one instance at a time to OpenGL is going to kill performance. You’re also doing lots of logic per CMeshFace which seems to be a triangle. don’t do that, it’s slow. Batch stuff up in larger groups, abstract at a higher level/larger granularity and hoist your logic out of the loops. Use vertex arrays and index arrays and render the large batches with glDrawRangeElements and you’l see a large speed improvement. If you wan’t more information on performance try searching these boards or looking here .

[This message has been edited by harsman (edited 03-05-2002).]

Also, try to unnest if/else constructs out of for-loops if possible.

Thank you very much harsman and Michael Steinberg !!!

God, that code is going to run very slow.
Aside from what everyone else has said, look at all the divisions you’re doing! Just to get your colours from 0-255 down to 0.0f-1.0f ??? Do this as a preprocessing step (ie. not for every vertex-every frame during runtime)
Also, you seem to not be aware that opengl can deal with indexed vertex arrays well, in fact far better than explicitly repeating vertex definitions. I say this, because of these lines


CVertex *pA, *pB, *pC; 
pA = pObject->GetVertexAt(pMesh->GetIndexA());
pB = pObject->GetVertexAt(pMesh->GetIndexB());
pC = pObject->GetVertexAt(pMesh->GetIndexC());
[\code]

You can just give opengl the address of the first vertex in your vertex array, then give it the address of the first index in your index array - it will do the dereferencing for you!

Originally posted by knackered:
[b]Also, you seem to not be aware that opengl can deal with indexed vertex arrays well, in fact far better than explicitly repeating vertex definitions. I say this, because of these lines

CVertex *pA, *pB, *pC;
pA = pObject->GetVertexAt(pMesh->GetIndexA());
pB = pObject->GetVertexAt(pMesh->GetIndexB());
pC = pObject->GetVertexAt(pMesh->GetIndexC());
[\code]

You can just give opengl the address of the first vertex in your vertex array, then give it the address of the first index in your index array - it will do the dereferencing for you![/b]

thank you very much for this tip knackered. After i got the messages of michael steinberg and harseman, i am now going to store vertex-,normal,- and index-data in float arrays which will be dynamically allocated when creating objects like sphere, cone, torus, etc.! My object-class contains now pointers to float-arrays, one for the vertices, another for the vertex-normals and a third one for the indices describing the mesh.
Do you think that this is the right way to define the data-structure in refer to performance. Yesterday i bought the red-book and now i will read, what functions are available to handle the float-arrays.

Best regards
tabor25

Yes, this is a good way to store your data. It’s flexible and efficient. I hope you’re not using float for indices though It might be wise to factor out the handling of this data in a separate vertex buffer class. That’ll probably help if you want to use more advanced geometry management in the future.

Originally posted by harsman:
Yes, this is a good way to store your data. It’s flexible and efficient. I hope you’re not using float for indices though It might be wise to factor out the handling of this data in a separate vertex buffer class. That’ll probably help if you want to use more advanced geometry management in the future.

Hello harsman,

now i am going to store vertex-,normal-,face- and color-data in arrays (pointers to arrays) in my object-class. the data will be calculated only once and then all is rendered by calling glDrawElements like follows:

void C3DViewGL::RenderObject(C3DObject *pObject)
{
CScene *pScene = pObject->GetScene();
if (!pScene) return;

long faceCount;
const GLfloat *pVertList     = pObject->GetVertList();
const GLfloat *pVertNormList = pObject->GetVertNormList();   
const GLfloat *pVertColList  = pObject->GetVertColList();   
const GLuint  *pFaceList     = pObject->GetFaceList(faceCount);
const GLfloat *pFaceNormList = pObject->GetFaceNormList();

if (pScene->GetColorMode() == CM_OBJECT)
{
    glDisableClientState(GL_COLOR_ARRAY);    
    glColor3f(pObject->GetRed(), pObject->GetGreen(), pObject->GetBlue());
}
else
{
    glEnableClientState(GL_COLOR_ARRAY);
    const GLfloat *pVertColList  = pObject->GetVertColList();
    glColorPointer(3,GL_FLOAT,0,pVertColList);
}

if (pScene->GetShadingModel() == SM_FLAT)
{
    glShadeModel(GL_FLAT);
    glNormalPointer(GL_FLOAT,0,pFaceNormList);
}
else
{
    glShadeModel(GL_SMOOTH);
    glNormalPointer(GL_FLOAT,0,pVertNormList);
}

glVertexPointer(3,GL_FLOAT,0,pVertList);    

glDrawElements(GL_TRIANGLES,faceCount,GL_UNSIGNED_INT,pFaceList);

}

Now my test-object contains 45000 polygons and will be rendered at 30 FPS per second :-). What do you think, is this a good rate or goes it also faster ?
Using vertex-arrays i have a problem when i want to use flat-shading: in the code below, i force opengl to use the face-normal-array for shading when flat-shading is enabled. but it seems that the normals of the face-normal-array will not be used or in a wrong way, because the object looks not shaded correctly. Maybe you have an idea ?

Best regards

tabor25