OpenGL Probleme (evtl. mit den Buffern)

Alles rund um die Programmierung mit Qt
Antworten
graythornWW
Beiträge: 38
Registriert: 20. Oktober 2008 09:48

OpenGL Probleme (evtl. mit den Buffern)

Beitrag von graythornWW »

Hallo zusammen,

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
Ich hoffe, das diese codefragmente helfen und danke für eure Mühen...
graythornWW
Beiträge: 38
Registriert: 20. Oktober 2008 09:48

Neuer Versuch....

Beitrag von graythornWW »

mangels Antworten ich versuche es mal anders:

Ich möchte in einem QGlWidget im Mouse-Move event testen, ob ein Object sich unter der Mouse befindet.

Dazu nutze ich den Picking-Mechanismus von OpenGL. Dieser ist im Prinzip ja ein neuzeichnen. Die Szene besteht aus drei grünen Würfeln.

Das funktioniert auch, und wenn ich ein Objekt finde, ändere ich die Farbe dieses Objektes und rufe updateGL() auf. Die Objekte werden neu gezeichnet, das Objekt unter der Maus in Rot.

Das funktioniert eine Weile, ich fahre mit der Maus über das Fenster und der jeweilige Würfel unter der Maus wird rot, wenn ich ihn mit der Maus verlasse wird er wieder grün.
Irgendwann jedoch blinkt der Würfel unter der Maus nur noch kurz rot auf und wird dann wieder grün gezeichnet wird. :( :( :(

Es sieht so aus, als ob die vorherige Szene - also die, in der der jetzt rote Würfel noch grün war gezeichnet wird, also ein falscher Buffer (Context) angezeigt wird.

Kann ich vielleicht im Mouse-Move keine Zeichenoperationen bzw. OpenGL-Aufrufe tätigen, oder muß ich zuvor noch irgend etwas initialisieren, z.B. einen Context aktivieren oder ähnliches :?: :?:

Danke und Gruß
Antworten