ich habe folgendes Programm:
Auf einem GLWidget werden 4 Viewport definiert und in diesen jeweils die gleiche Szene in unterschiedlichen Darstellungen angezeigt, also die gleichen Objekte.
Zwei Useraktionen sind möglich:
1) Mousewheel über einem Viewport => zoomen
2) Mousewheel über einem Viewport => Würfel unter Maus selektieren
Das klappt grundsätzlich prima, wenn man aber das Programm eine Weile laufen läßt, gibt es Darstellungsprobleme.
Könnte ein Problem mit den Buffern vorliegen, d.h. ich rendere zur falschen Zeit in die falschen buffer? So sieht es jedenfalls aus, da die Objekte grundsätzlich in der richtigen Farbe gezeichnet werden (habe ich mit Debugcode überprüft). Mir scheint, ich sehe einen falschen Buffer...
Ich poste ich hier mal den relavanten GL-Code. Das gesamte Projekt ist kaum zu posten. Es besteht aus 5 großen Bibliotheken und massenhaft Dateien. Diese zu durchblicken ist trotz guter Doku einfach zu aufwendig für jemanden, der sie nicht kennt. Das möchte ich niemandem zumuten.
Ich vermute, das das Problem mit dem Picking von Objekte zusammenhängt.
Folgende Klassen gibt es:
- TibasWindow das QGlWidget
- TibasVp: ein Bereich innerhalb des Windows
Das "Setzen der Kamera" geschieht abhängig von vom Mode, also abhängig davon, ob ich mich im normalen Zeichenmodus oder im Picking-Modus befinde.
Der Picking Modus ist aktiv, wenn ich im MouseMove schaue, ob sich ein Würfel unter der Maus befindet.
Der Code für das QGlWidget:
Code: Alles auswählen
///////////////////////////////////////////////////////////////////////////////////
// TibasWindow::initializeGL
///////////////////////////////////////////////////////////////////////////////////
void TibasWindow::initializeGL()
{
// settings for all the views and viewports
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glEnable(GL_SCISSOR_TEST); // Enables Scissor Testing
glEnable(GL_NORMALIZE); // enables normalize after transformation
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
} // TibasWindow::initializeGL
///////////////////////////////////////////////////////////////////////////////////
// TibasWindow::paintGL
///////////////////////////////////////////////////////////////////////////////////
void TibasWindow::paintGL()
{
// erase the whole window
glViewport(0, 0, sizWindow.w, sizWindow.h); // Reset The Current Viewport
glScissor(0, 0, sizWindow.w, sizWindow.h); // clip to the vp
glClearColor(pRgbBG->r, pRgbBG->g, pRgbBG->b, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw all the viewports
for (it=m_lstVP.begin(); it!=m_lstVP.end(); it++)
{
TibasVpI *pVP = *it;
const TibasAttributes &attr = GetTibasAttributes();
if (pVP->IsVisible())
{
// paint the background of the tibas viewport
pVP->OnPrePaint3D(attr);
// first: set the camera
pVP->SetCamera(attr);
// paint the scene
pVP->OnRenderScene(attr);
} // if (pVP->IsVisible())
} // for (it=m_lstVP.begin(); it!=m_lstVP.end(); it++)
} // TibasWindow::paintGL
Der Code für einen Viewport auf dem QGlWidget:
Code: Alles auswählen
///////////////////////////////////////////////////////////////
// TibasVp::OnPrePaint3D
///////////////////////////////////////////////////////////////
void TibasVp::OnPrePaint3D(const TibasAttributes &_attr) // initialize viewport
{
Rect2D<s32> rctGeo = GetGeometry();
Rgb rgbBG = GetBackgroundColor();
// set the viewport dimension
glViewport(rctGeo.x, rctGeo.y, rctGeo.w, rctGeo.h); // Reset The Current TibasVp
glScissor(rctGeo.x, rctGeo.y, rctGeo.w, rctGeo.h); // clip to the vP
// clear the background
glClearColor(rgbBG.r, rgbBG.g, rgbBG.b, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (IsVpRenderState(VP_RENDER_STATE_WIRED))
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
} // TibasVp::OnPrePaint3D
///////////////////////////////////////////////////////////////
// TibasVp::SetCamera
///////////////////////////////////////////////////////////////
void TibasVp::SetCamera(const TibasAttributes &_attr)
{
const Vertex &v3dEye = GetCamera().GetEyepoint();
const Vertex &v3dView = GetCamera().GetViewpoint();
const TIBAS_t tDist = GetCamera().GetViewDistance();
// get viewport dimension
GLint arTibasVp[4];
glGetIntegerv(GL_VIEWPORT, arTibasVp);
GLdouble dW = (GLdouble) arTibasVp[2];
GLdouble dH = (GLdouble) arTibasVp[3];
GLdouble dRatio = dW / dH;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
if (IsPickingMode())
glPushMatrix();
glLoadIdentity();
// select render mode
if (IsPickingMode())
{
glSelectBuffer(PICKING_BUFSIZE, m_arPickingBuffer);
glRenderMode(GL_SELECT);
}
else
{
glRenderMode(GL_RENDER);
}
// set picking area to mousepos +- 1 pixels
if (IsPickingMode())
{
gluPickMatrix(m_dPickX, (GLdouble) (GetTibasWindowI()->GetWindowSize3D().h)-m_dPickY, 1, 1, arTibasVp);
}
// Set the correct perspective.
if (IsVpRenderState(VP_RENDER_STATE_ORTHOGONAL))
{
if (dW > dH)
{
dW = tDist * dW / dH;
glOrtho(-dW, dW, -tDist, tDist, 1, 1000);
}
else
{
dH = tDist * dH / dW;
glOrtho(-tDist, tDist, -dH, dH, 1, 1000);
}
}
else
{
gluPerspective(45, dRatio, 1, 1000);
}
gluLookAt(v3dEye.x, v3dEye.y, v3dEye.z, // eye position
v3dView.x, v3dView.y, v3dView.z, // look at position
0.0f, 1.0f, 0.0f); // up-vector
glMatrixMode(GL_MODELVIEW);
if (IsPickingMode())
glInitNames();
glLoadIdentity();
} // TibasVp::SetCamera
///////////////////////////////////////////////////////////////
// TibasVp::SearchObjAtXY
///////////////////////////////////////////////////////////////
bool TibasVp::SearchObjAtXY(const TibasAttributes &_attr, // return true => >=1 obj found
const s32 _s32X,
const s32 _s32Y,
lstObj3D_t &_lstObj)
{
CHECK_PRE_CONDITION(GetScene() != NULL, false);
GLuint uiHits;
//bool bGizmoMode = (_pGizmo != NULL);
// enter picking mode
SetPickingMode(true);
m_dPickX = (GLdouble) _s32X;
m_dPickY = (GLdouble) _s32Y;
// paint the background of the tibas viewport
OnPrePaint3D(_attr);
// first: set the camera
SetCamera(_attr);
// paint the scene or Gizmo
//if (bGizmoMode)
// OnPaintGizmos(_tibasSettings, _sizWindow, _pGizmo);
//else
OnRenderScene(_attr);
// stop picking
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glFlush();
uiHits = glRenderMode(GL_RENDER); // returning to normal rendering mode
// if there are hits process them
if (uiHits != 0)
{
GLuint i, j;
GLuint *pActHit = m_arPickingBuffer;
RefPtr<TreeItem> pTI;
RefPtr<Obj3D> pHit;
GLuint uiActMinZ = 0xffffffff;
bool bFirstInGroup;
// iter over all hit-groups
for (i=0; i<uiHits; i++)
{
// pActHit[0] := hit count
// pActHit[1] := Minimum depth for hit
// pActHit[2] := Maximum depth for hit
// pActHit[3] := name for 1. hit in this group
// pActHit[4] := name for 2. hit in this group... until hit count
if (pActHit[1] <= uiActMinZ)
{
// iter over all objects in this hit-group
bFirstInGroup = true;
for (j=0; j<pActHit[0]; j++)
{
//if (bGizmoMode)
// pTI = _pGizmo->SearchTI((s32) (pActHit[3]+j));
//else
pTI = GetScene()->SearchTI((s32) (pActHit[3]+j));
pHit = TI2Obj3D(pTI);
// check, whether the obj is found and selectable
if (pHit!=NULL) // && (pHit->IsSelectable() || bGizmoMode))
{
if (bFirstInGroup)
{
// remove the previous obj, because this one is closer
_lstObj.clear();
bFirstInGroup = false;
}
_lstObj.push_back(pHit());
uiActMinZ = pActHit[1];
}
}
}
// jump to next hit-group
pActHit += pActHit[0] + 3;
}
}
// leave picking mode
SetPickingMode(false);
return _lstObj.size() > 0;
} // TibasVp::SearchObjAtXY
MouseMove werden vom QGlWidget an eine Toolklasse weitergeleitet und dort verarbeitet:
Code: Alles auswählen
///////////////////////////////////////////////////////////////
// ToolVp::OnMouseMove
///////////////////////////////////////////////////////////////
enumToolResult ToolVp::OnMouseMove(const u32 _u32Flags, // e.g. KS_LEFT_SHIFT
const s32 _s32MouseX,
const s32 _s32MouseY)
{
qCadVpBase *pVp = FindViewportUnderMouse();
qCadAttributes &attr = App().Get_qCadAttributes();
CHECK_PRE_CONDITION(pVp != NULL, TOOL_HANDLED);
lstObj3D_t lstObj;
SetCursor();
pVp->SearchObjAtXY(attr, _s32MouseX, _s32MouseY, lstObj);
// Alle Objekte werde deselektiert, d.h. alle zuvor selektierten Würfel
// werden als nicht selektiert gekennszeichnet
pVp->GetScene()->UnPreselect();
// jetzt ein evtl. gefundenes Objekt selektieren
if (lstObj.Size() > 0)
{
itObj3D_t it;
for (it=lstObj.begin(); it!=lstObj.end(); it++)
{
// preselect the object
(*it)->Preselect();
}
}
// repaint the window
pVp->updateGL();
return TOOL_HANDLED;
} // ToolVp::OnMouseMove
///////////////////////////////////////////////////////////////
// ToolVp::OnMouseWheel
///////////////////////////////////////////////////////////////
enumToolResult ToolVp::OnMouseWheel(const u32 _u32Flags, // e.g. KS_LEFT_SHIFT
const s32 _s32Degree,
const s32 _s32MouseX,
const s32 _s32MouseY)
{
qCadVpBase *pVp = FindViewportUnderMouse();
if (pVp != NULL)
{
// zoom rein oder raus, d.h. ändere den Eyepoint in der Kamera
if (_s32Degree > 0)
pVp->GetCamera().ZoomIn();
else
pVp->GetCamera().ZoomOut();
// repaint the window
pVp->updateGL();
}
return TOOL_HANDLED;
} // ToolVp::OnMouseWheel