圖像為一數位影像,因此貼圖其實是由一訊號取樣後之結果,此過程稱為重新取樣 (Re-sampling)。由於為取樣結果,因此會有兩種情況:一是放大取樣,則取樣點的間距較原先貼圖的取樣點間距小;二是縮小取樣,則取樣點的間距較原先貼圖的取樣點間距大。
常見的取樣方法有線性內插法 (Linear Interpolation)、雙線性內插法 (Bi-linear Interpolation)、三次多項式內插法 (Cubic Interpolation)、雙三次多項式內插法 (Bi-cubic Interpolation) 等。
由於貼圖為取樣結果,因此會產生貼圖前後變質的情況,稱為失真。為解決失真的問題,Lance Williams於1983年7月在Computer Graphics Vol. 17 No.3提出一篇名為"Pyramidal Parametrics"的論文,為失真提出解決方法,若事先將貼圖用各種大小的Filter處理,並建立不同的貼圖,則在貼圖縮小時,只要選擇適當的貼圖大小則可,這種方法稱為MIP Map,其中MIP為拉丁文multum in parvo的縮寫,為many things in a small place或much in little之意。
在JOGL中,以com.sun.opengl.util.texture套件處理Texure,其類別包括:
- Texture:建立Texure物件。
- TextureCoords:設定Texure矩形區域的座標,分別為區域的上、下、左、右座標。
- TextureData:代表Texure的相關資料,如高度、寬度、Pixel格式、MIP Map等。
- TextureIO:建立輸出入資料流,以自圖像檔案或資料流中載入至Texure物件、或自Texure物件寫入至記憶體資料流中。
- TextureIO.DDS:Microsoft DirectDraw Surface (DDS) 格式。
- TextureIO.GIF:Graphics Interchange Format (GIF) 格式。
- TextureIO.JPG:Joint Photographic Experts Group (JPEG) 格式。
- TextureIO.PNG:W3C Portable Network Graphics (PNG) 格式。
- TextureIO.SGI:SGI格式。
- TextureIO.SGI_RGB:SGI RGB格式。
- TextureIO.TGA:Targa格式。
- TextureIO.TIFF:Tag Image File Format (TIFF) 格式。
載入圖像的程式架構:
com.sun.opengl.util.texture.Texture texture = null; // Get current classloader ClassLoader cl = this.getClass().getClassLoader(); try { // 載入圖像檔案 texture = TextureIO.newTexture( cl.getResourceAsStream(filename), false, TextureIO.JPG); // 設定Texture的參數 texture.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); texture.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); } catch(Exception e) {...} |
至於貼圖,則依序以Texture類別的enable()、bind()與disable()方法分別啟用、繫結與停止貼圖,所謂繫結 (Bind) 是將圖像貼至物體表面的過程,此過程依序以javax.media.opengl.GL類別的glNormal3f()、glTexCoord2f()與glVertex3f()方法設定物體表面的法線 (Normal)、Texture的座標與頂點 (Vertex),藉由法線可決定表面向內或向外的方向性,藉由座標與頂點可繪製物體表面。
例如以下之程式代表貼圖至物體的正面 (Front View):
// Texture貼圖 Texture cubeTexture; ... // 啟用貼圖 cubeTexture.enable(); // 繫結貼圖 cubeTexture.bind(); gl.glBegin(GL.GL_QUADS); // front // 設定物體表面的法線 gl.glNormal3f(0.0f, 0.0f, 1.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f( 30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f( 30.0f, 30.0f, 30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, 30.0f); ... gl.glEnd(); // 停止貼圖 cubeTexture.disable(); |
請參考以下範例。
// 實作GLEventListener介面之方法 // 初始化JOGL public void init(GLAutoDrawable drawable) { gl = drawable.getGL(); gl.glShadeModel(GL.GL_SMOOTH); gl.glEnable(GL.GL_DEPTH_TEST); gl.glEnable(GL.GL_CULL_FACE); gl.glFrontFace(GL.GL_CCW); gl.glEnable(GL.GL_LIGHTING); // Light 0 gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuseLight, 0); gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, specularLight, 0); gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0); gl.glLightf(GL.GL_LIGHT0, GL.GL_SPOT_CUTOFF, 40.0f); gl.glLightf(GL.GL_LIGHT0, GL.GL_SPOT_EXPONENT, 80.0f); // Light 1 gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, diffuseMaterial, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, diffuseMaterial, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPositionR, 0); // 啟用光源 gl.glEnable(GL.GL_LIGHT0); gl.glEnable(GL.GL_LIGHT1); gl.glEnable(GL.GL_COLOR_MATERIAL); gl.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE); // 設定物體的材質 gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, specularLight, 0); gl.glMateriali(GL.GL_FRONT, GL.GL_SHININESS, 128); // 以目前之顏色清除視窗 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 載入圖像以作為貼圖之用 cubeTexture = loadTexture("opengl.jpg"); } // 載入圖像以作為貼圖之用 private Texture loadTexture(String filename) { com.sun.opengl.util.texture.Texture tex = null; // Get current classloader ClassLoader cl = this.getClass().getClassLoader(); try { // 載入圖像檔案 tex = com.sun.opengl.util.texture.TextureIO.newTexture( cl.getResourceAsStream("images/" + filename), false, TextureIO.JPG); // 設定Texture的參數 tex.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); tex.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); tex.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); tex.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); } catch(Exception e) { System.out.println("Error loading texture " + filename); } return tex; } // 繪製圖形 public void display(GLAutoDrawable drawable) { gl = drawable.getGL(); // increase rotation values objectXRot += 0.5f; objectYRot += 1.0f; objectZRot += 0.5f; // clear screen and depth buffer gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); // 載入單位矩陣 gl.glLoadIdentity(); // Move everything back to (0, 0, -150) gl.glTranslatef(0.0f, 0.0f, -150.0f); // 複製目前之矩陣至堆疊最上層 gl.glPushMatrix(); // 設定目前繪圖顏色 gl.glColor3f(1.0f, 1.0f, 1.0f); // 沿x座標旋轉指定角度 gl.glRotatef(objectXRot, 1.0f, 0.0f, 0.0f); // 沿y座標旋轉指定角度 gl.glRotatef(objectYRot, 0.0f, 1.0f, 0.0f); // 沿z座標旋轉指定角度 gl.glRotatef(objectZRot, 0.0f, 0.0f, 1.0f); drawCube(); // 自堆疊最上層移除矩陣 gl.glPopMatrix(); // 即刻執行JOGL指令 gl.glFlush(); drawable.swapBuffers(); } // 當視窗大小改變時 public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL gl = drawable.getGL(); if (height == 0) height = 1; // 設定視界大小 gl.glViewport(0, 0, width, height); // 設定座標系統 gl.glMatrixMode(GL.GL_PROJECTION); // 載入單位矩陣 gl.glLoadIdentity(); // 設定透視度 glu.gluPerspective(54.0, (double)width/(double)height, 1.0, 1000.0); // 設定座標系統 gl.glMatrixMode(GL.GL_MODELVIEW); // 載入單位矩陣 gl.glLoadIdentity(); } private void drawCube(){ float[] cubeColor = { 1.0f, 1.0f, 1.0f, 1.0f }; gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, cubeColor, 0); gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, cubeColor, 0); gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 50.0f); gl.glEnable(GL.GL_TEXTURE_2D); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); // 啟用貼圖 cubeTexture.enable(); // 繫結貼圖 cubeTexture.bind(); gl.glBegin(GL.GL_QUADS); // front // 設定物體表面的法線 gl.glNormal3f(0.0f, 0.0f, 1.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f( 30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f( 30.0f, 30.0f, 30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, 30.0f); // back // 設定物體表面的法線 gl.glNormal3f(0.0f, 0.0f, -1.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f( 30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, -30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f( 30.0f, 30.0f, -30.0f); // top // 設定物體表面的法線 gl.glNormal3f(0.0f, 1.0f, 0.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-30.0f, 30.0f, 30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f( 30.0f, 30.0f, 30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f( 30.0f, 30.0f, -30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, -30.0f); // bottom // 設定物體表面的法線 gl.glNormal3f(0.0f, -1.0f, 0.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f( 30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f( 30.0f, -30.0f, 30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-30.0f, -30.0f, 30.0f); // left // 設定物體表面的法線 gl.glNormal3f(-1.0f, 0.0f, 0.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(-30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, 30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-30.0f, 30.0f, -30.0f); // right // 設定物體表面的法線 gl.glNormal3f(1.0f, 0.0f, 0.0f); // 設定Texture的座標與頂點(Vertex) gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(30.0f, -30.0f, 30.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(30.0f, -30.0f, -30.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(30.0f, 30.0f, -30.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(30.0f, 30.0f, 30.0f); gl.glEnd(); // 停止貼圖 cubeTexture.disable(); gl.glDisable(GL.GL_TEXTURE_2D); } |
【執行結果】
【參考資料】
[1] Java Platform, Standard Edition 7, API Specification.
[2] JOGL.
[3] 黃嘉輝,完全探索Java遊戲程式設計,上奇資訊。
© Chia-Hui Huang
沒有留言:
張貼留言