前序
前段時間學習3D MAX,一對比就發現差距是相當大。我也做了一個三維展示的小軟件,但是拖拽操作非常不友好,如果場景的尺寸特別大,會導致拖不動,尺寸過小會導致輕輕拖一下,模型就不知道飛哪去了。我是每次鼠標移動都是讓模型移動相同的距離,所以就出現了這種情況。下面就簡單說一下,怎么做到模型跟隨鼠標移動,就像鼠標抓着模型到處甩的效果。
方法

我們在設置OpenGL的投影矩陣的時候,需要設置近平面和遠平面,這里,BP和DQ分別表示近平面和遠平面。除此外,我們還需要設置攝像機的位置,這里我們用A點代表攝像機,攝像機的角度為2θ,假設觀察的物體位於CF平面上,我們的屏幕分辨率是X * Y,OpenGL的視口長寬設置為屏幕大小,那么,我們可以很容易的算出物體所在表面的高度CF = tanθ * AC。如果鼠標在縱向拖動的像素距離為ybits,那么相應的物體需要在Y軸方向移動的距離ydistance = ybits / Y * CF = ybits / Y * AC * tanθ。現在只要能取到AC的長度就能算出物體需要移動的距離。
深度緩沖
在OpenGL中我們可以通過獲取鼠標所在點的深度值,然后通過gluUnProject函數就能得到這個點所在的z軸坐標。
int winX, winY; //winX和winY分別是窗口的xy坐標
double x, y, z; //鼠標所在點在OpenGL坐標系中的坐標
float depth; //鼠標點所在的深度值
int viewport[4]; //視口數據
double mvMatrix[16], projectMatrix[16]; //當前的modelview矩陣和projection矩陣
glGetIntegerv(GL_VIEWPORT, viewport); //獲取當前視口
glGetDoublev(GL_MODELVIEW_MATRIX, mvMatrix); //獲取當前的modelview矩陣
glGetDoublev(GL_PROJECTTION_MATRIX, projectMatrix); //獲取當前的projection矩陣
//鼠標當前的坐標為mouseX, mouseY, 均為int類型
winX = mouseX;
winY = viewport[3] - mouseY; //Windows上的點坐標遠點位於屏幕左上角
glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, &depth); //獲取深度,保存於depth
//gluUnProject(x坐標,y坐標,深度,modelview矩陣,projection矩陣,OpenGL的x坐標,OpenGL的y坐標,OpenGL的z坐標)
gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)depth, mvMatrix, projectMatrix, &x, &y, &z);
最后的計算
知道了鼠標點在OpenGL坐標系的具體坐標后,可以通過攝像機的坐標與點坐標之間運算,得到一個大概的移動距離(通過屏幕坐標反算OpenGL坐標會有誤差)
