攝影師調整好相機和被拍攝物體的位置角度(modelview) ,對好焦距(projection)后,就可以按下快門拍照了,拍好的照片可以在計算機上使用照片瀏覽器查看照片,放大,縮小,拉伸,并可以將照片顯示窗口在屏幕上任意拖放。對應到3D繪制就是 Viewport 變換,目前的顯示器大多還是 2D 的,viewport(顯示區域)為一個長方形區域,并且使用屏幕坐標系來定義:
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/81.png" alt="" />
OpenGL ES 中使用 glViewport() 來定義顯示視窗的大小和位置:
glViewport(int x, int y, int width, int height)
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/82.png" alt="" />
Android 缺省將 viewport 設置成和顯示屏幕大小一致。
如果投影變換的寬度/高度比 (aspect) 和最后的 Viewport 的 width/height 比不一致的話,最后顯示的圖形就可能需要拉伸以適應 Viewport,從而可能造成圖像變形。比如:現在的電視的顯示模式有 4:3 和 16:9 或是其它模式,如果使用 16:9 的模式來顯示原始寬高比為 4:3 的視頻,圖像就有變形。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/83.png" alt="" />
前面提到的 modelview, projection 變換 同樣應用于 Z 軸坐標,但和屏幕坐標系中 x,y 坐標不同的時,在屏幕坐標系下 ,Android OpenGL ES 將 z 坐標重新編碼,它的值總會在0.0到1.0之間。作為深度 depth 測試的依據。
我們在示例代碼的 OpenGLRenderer 的 onSurfaceChanged 使用和屏幕一樣大小的區域作為Viewport,你也可以通過 glViewport 將視窗設成屏幕的局部某個區域。
并且可以看到透視投影的 aspect 為 width/height ,因此最后的圖形不會有變形:
查看源代碼打印幫助
public void onSurfaceChanged(GL10 gl, int width, int height) {
// Sets the current view port to the new size.
gl.glViewport(0, 0, width, height);
// Select the projection matrix
gl.glMatrixMode(GL10.GL\_PROJECTION);
// Reset the projection matrix
gl.glLoadIdentity();
// Calculate the aspect ratio of the window
GLU.gluPerspective(gl, 45.0f,
(float) width / (float) height,
0.1f, 100.0f);
// Select the modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
// Reset the modelview matrix
gl.glLoadIdentity();
}