Best Performance for CAD

I am developing a CAD application, and will soon be integrating/optimizing the portion where the objects in the model can be added/deleted.

I am using C/C++ and my idea is on how to best handle this so far is:

Each object(line, circle, arc, solids, etc…) are each a struct. I then have a vector of structs so that adding/deleting objects from the model should be fairly straight forward. Each new object added, will create a new display list. When the screen is needing updated, search through the vectors to determine if an object is visible in the window, if so call the corresponding display lists for each object that will be on the screen.

Eventually, I’ll need to add selection of objects, and I believe there is something in gl that returns object names that are visible/on the screen. Is this a better way to go? I’m not sure since I’ll need to somehow link both the objects with the vectors that contain each objects data.

I haven’t found anything elsewhere explaining the best way(or a very good way) to squease the most performance out of an OpenGL CAD program where objects in the model can be added/deleted by the user. I’d appreciate if someone could give me some pointers on this or explain if I am taking the wrong approach at this.

Ancient GL selection-feedback : avoid at any cost. Instead, draw each object with its own color ( = (int)pObject) .
To determine if an object is visible in the window: simply frustum-culling and optionally occlusion-queries.

VBOs: static, dynamic, streaming. Display-lists will be slow to compile, up to 2x faster to draw on nVidia cards but slow to draw on ATi cards.

Display lists perform close to (or a little better than) VBOs on Ati cards. They are not by any means slow.

Nvidia drivers seem to be able to optimize display lists more than VBOs, but the cost is higher list compile times.

Display lists perform close to (or a little better than) VBOs on Ati cards. They are not by any means slow.

I totally agree with you, dl are not slow on ATI hardware. Perhaps their implementation is bit slower than the nvidia one but “slow” is not the right word.

i am developing CAD application myself, we had some thought into how putting it all together. one approach worked in practice is that usually a CAD program doesnt have fancy perpixel lighting or the like except the rendering mode which is a raycast implementation. compiling display lists with integrated transformation glPushMatrix/glPopMatrix/glLoadMatrix/… seems to perform best and culling is still done but on whole object basis not its sub-parts. still there can be moments where you have a huge drawing so performance will be cut depending on system specs. a good hint as a side note is not to use GL_COMPILE_AND_EXECUTE rather GL_COMPILE first and execute afterwards to avoid immediate mode calls.

p.s. worked on all cards even Intel OnBoard (requested by avarage CAD users).

Ah, sorry for the misleading then. I was quoting some posts from almost a year ago on that, as I haven’t benchmarked anything on ATi cards.

Here are some benchmark results:
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=255602#Post255602

Also, when using streaming-VBOs (not static or dynamic, which cache stuff in RAM) in a round-robin fashion, fittable in L1/L2, you can easily leverage the whole PCIe/AGP bandwidth if you want. (read: streaming is also accelerated nicely, don’t try to avoid it at any cost).

Thanks Ilian, I found some resources further describing the methods. The color method seems to work pretty well from the demo source provided from the link below. It seems that frustum culling should only be done when zooming/panning(because thats the only time the viewing volume will change) and use the color picking method for mouse movements(for snap detection, looping through a 2D array of pixels surrounding the mouse cursor when in a CAD command) and clicking(the actual picking of an object).
http://www.lighthouse3d.com/opengl/picking/index.php?color1
http://www.lighthouse3d.com/opengl/viewfrustum/

I think I’ll stick with display lists for now. I’ll try to encapsulate that portion of code so that later on I can add VBO or other options. I’m planning to add some simple benchmarking features later on so I can test on different hardware.

_NK47, at the moment, I have one PushMatrix called before all and one PopMatrix after all drawing operations are executed. I did it because regardless of a display list, it just seems wasteful to have that in each objects display list…or did you mean something else?

I am using GL_COMPILE. Huge drawings/models are one of the main reasons I’d like to get performance as good as it can be. I use CAD at work and have to deal with this lag all the time.

A polyline for example is made up of many sub-parts and could possibly be shaped such that it stretches all throughout the drawing/model. For something as abstract shaped, are you suggesting to just use 1 large box for testing? Maybe anything fairly large in size is broken up into a few boxes?

I am wondering how well my zooming/panning method is performance wise though too. I haven’t made it into a display list as it constantly changes due to where the user wants to go. The performance isn’t bad at all imo so far, but I’m wondering if it could be somehow used as a display list or if a VBO is the best route, or something else. I came up with this method on my own after searching for a decent solution for “Zooming to mouse point” but not finding anything that remotely made sense. The way it works is it saves the last world coords of where the mouse is and then updates the projection and modelview matrices. Takes the difference between the two and then shifts the view accordingly. Right now it’s only set up for 2D, so you are looking at the 2D drawing plane. Suggestions? I’ve read a few things about a different ways to do zooming but some of them seemed like they are faking zooming by decreasing the size of things. I’m not sure how well my method will work when it comes to 3D zooming/rotation.

Here’s a snipplet of the zoom.cpp file for reference, zoomout and panning work similar in nature:


void CADGLObject::Coord2Dto3D(int x2d, int y2d, GLdouble* x3d, GLdouble* y3d, GLdouble* z3d)
{
    glGetIntegerv (GL_VIEWPORT, viewport);
    glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
    glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
    realY = WindowHeight - y2d - 1; //Invert Y for GL Screen coords      
    gluUnProject ((GLdouble) x2d, (GLdouble) realY, 1.0, mvmatrix, projmatrix, viewport, x3d, y3d, z3d);
}

//CAD Like Zooming
void CADGLObject::ZoomIn(int mx, int my)
{
    printf("ZoomIn
");
    MouseX = mx; MouseY = my;
    Coord2Dto3D(mx, my, &DestX, &DestY, &DestZ); //Save the last mouse coords for zooming to point

    //Do the Z zooming and update the matrices
    CameraZ -= ZoomScaleIn;
    if(CameraZ < 1.0f) CameraZ = 1.0f;

    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    glOrtho (-CameraZ*((GLfloat)WindowWidth/(GLfloat)WindowHeight), CameraZ*((GLfloat)WindowWidth/(GLfloat)WindowHeight), -CameraZ, CameraZ, CameraZ/2, CameraZ);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();
    gluLookAt(CameraX, CameraY, CameraZ, TargetX, TargetY, TargetZ, 0.0f, 1.0f, 0.0f);

    //Calculate the X/Y offset so that the destination coordinates are still located under the mouse.
    Coord2Dto3D(mx, my, &WorldX, &WorldY, &WorldZ);
    printf("DestX: %f DestY: %f DestZ: %f
", DestX, DestY, DestZ );
    printf("WordX: %f WordY: %f WordZ: %f
", WorldX, WorldY, WorldZ );
    CameraX += (DestX - WorldX); TargetX = CameraX;
    CameraY += (DestY - WorldY); TargetY = CameraY;

    // Update the matrices one last time and call SetMouseXY() so that the GLcrosscursor drawing will not be jittery
    glMatrixMode(GL_PROJECTION); glLoadIdentity();
    glOrtho (-CameraZ*((GLfloat)WindowWidth/(GLfloat)WindowHeight), CameraZ*((GLfloat)WindowWidth/(GLfloat)WindowHeight), -CameraZ, CameraZ, CameraZ/2, CameraZ);
    glMatrixMode(GL_MODELVIEW); glLoadIdentity();
    gluLookAt(CameraX, CameraY, CameraZ, TargetX, TargetY, TargetZ, 0.0f, 1.0f, 0.0f);
    SetMouseXY(mx, my);
}

“It seems that frustum culling should only be done when zooming/panning”

thats correct, if you have a whole object precompiled in a display list you can still glLoadMatrix before any display list and use glMultMatrix inside the list to describe the relationship between two objects if you fillet f.e. polylines and they become one single polyline. i did that with fonts f.e. you need to rebuild the display lists though if any object changes that’s the time when it can become slow depending on the vertex count etc. because a display list is precompiled and stored on vram it is pretty fast to draw an whole object at once if you not using heavy fragment shaders f.e. thats why i refered to culling by whole objects, not its sub-parts on by one since the whole object is “built” into the display list.