1. 程式人生 > >MFC+OpenGL 螢幕座標轉OpenGL座標

MFC+OpenGL 螢幕座標轉OpenGL座標

    最近在寫一個例子用到了OpenGL,OpenGL的中心點(0, 0)點剛好是我們螢幕的中心點。因為我是需要動態的作圖(畫點、線、圓、弧...)需要平移 縮放圖形,所以我在座標轉換這個問題上卡住了。

    滑鼠點選螢幕上的一點可以很方便的獲得通過OnLButtonDown(),但是把取到的螢幕點轉到OpenGL對應點卻需要做相應的計算。用到的核心函式是gluUnProject(),如下:

		glPushMatrix();	//與之相對應的glPopMatrix()也一定不能少

		//這裡的變換需要和繪圖時一致,否則座標會產生錯誤
		glScalef(...);		//縮放
		glRotatef(...);		//旋轉
		glTranslatef(...);	//平移

		glGetIntegerv( GL_VIEWPORT,viewport );	//得到的是最後一個設定視口的引數
		glGetDoublev( GL_MODELVIEW_MATRIX, modelview ); 
		glGetDoublev( GL_PROJECTION_MATRIX, projection ); 

		glPopMatrix();  

		winX = (float)point.x;
		winY = (float)viewport[3] - (float)point.y;
		glReadPixels(point.x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
		gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

    從螢幕座標向OpenGL座標轉換需要經過兩步:第一步是螢幕座標向視景體座標轉換,第二步是視景體座標向OpenGL座標轉換。上述程式碼中winX = (float)point.x; winY = (float)viewport[3] - (float)point.y;反映第一步,gluUnProject()是第二步。一般說來,gluUnProject()的轉換是不會出問題的。

    想要不出現問題就必須:

1. 在glGetIntegerv()之前必須添上模型變換的程式碼,即和繪圖時使用的模型變換程式碼一樣;


2. 必須保證平移、縮放、旋轉的順序和繪圖時的一致;另外,螢幕座標向視景體座標轉換要正確;

3. 在多視口情況下,活動視口必須最後繪製,使它作為當前的視口,這樣才能保證glGetIntegerv()等取值函式能夠得到正確的值;

    以下是我繪圖時的程式碼,注意各種變換的順序要和左邊轉換時一致

	glPushMatrix();

	glLoadIdentity();
	glScalef(...);
	glRotatef(...);
	glTranslatef(...);

	//兩條座標軸
	glBegin(GL_LINES );
	glColor3f(0.5f,1.0f,1.0f);
	glVertex2f(ptStartX, ptStartY);
	glVertex2f(ptEndX, ptEndY);
	glEnd();

	glPopMatrix();