PDA

View Full Version : Performance Problem



tabor25
03-05-2002, 02:20 AM
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

harsman
03-05-2002, 02:38 AM
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 (http://www.mesa3d.org/brianp/sig97/perfopt.htm) 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 (http://developer.nvidia.com) .

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

Michael Steinberg
03-05-2002, 04:52 AM
Also, try to unnest if/else constructs out of for-loops if possible.

tabor25
03-06-2002, 01:48 AM
Thank you very much harsman and Michael Steinberg !!!

knackered
03-06-2002, 05:41 AM
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
[CODE]
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!

tabor25
03-08-2002, 01:37 AM
Originally posted by knackered:
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
[CODE]
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!

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

harsman
03-08-2002, 03:10 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gif 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.

tabor25
03-10-2002, 12:05 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gif 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