顯示具有 3D 標籤的文章。 顯示所有文章
顯示具有 3D 標籤的文章。 顯示所有文章

2014年2月2日 星期日

JOGL Reflection

反射 (Reflection) 是由於光自物體表面反彈所造成的現象,光反彈的方向受到物體表面的幾何結構影響,非常光滑的表面會產生完全相同的反射方向,就像鏡子一般;若是非常的粗糙表面則會產生散射 (Dispersion),自光滑表面所產生的反射稱為高光反射 (Specular Reflection),自粗糙表面所產生的反射稱為散射反射 (Diffuse Reflection),而介於兩者之間則稱為光滑反射 (Glossy Reflection)。非導電材質的反射總是與光源顏色相同,所以所產生的反射是白色,而導電材質則會讓反射的光線帶有顏色,其顏色由入射角度與材質的化學結構決定。

在JOGL中,反射如同在反射的表面上再繪製物體,使其產生反射的效果。可使用javax.media.opengl.GL類別的glStencilFunc()glStencilOp()方法處理。例如:


gl.glColorMask(false, false, false, false);
gl.glDepthMask(false);

gl.glEnable(GL.GL_STENCIL_TEST);
gl.glStencilFunc(GL.GL_ALWAYS, 1, ~0);
gl.glStencilOp(GL.GL_REPLACE, GL.GL_REPLACE, GL.GL_REPLACE);

drawSurface();

gl.glColorMask(true, true, true, true);
gl.glDepthMask(true);

gl.glStencilFunc(GL.GL_EQUAL, 1, ~0);

gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP);

gl.glPushMatrix();
  gl.glScalef(1.0f, -1.0f, 1.0f);
  gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, g_lightPos, 0);
  drawCube();
gl.glPopMatrix();

gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, g_lightPos, 0);
gl.glEnable(GL.GL_BLEND);
drawSurface();
gl.glDisable(GL.GL_BLEND);

gl.glPushMatrix();
  gl.glDisable(GL.GL_TEXTURE_2D);
  gl.glDisable(GL.GL_LIGHTING);
  gl.glDisable(GL.GL_DEPTH_TEST);
  gl.glEnable(GL.GL_BLEND);
  gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR);
  gl.glColor4f(0.0f, 0.0f, 0.0f, 0.5f);

  gl.glMultMatrixf(g_shadowMatrix, 0);
  drawCube();

  gl.glEnable(GL.GL_TEXTURE_2D);
  gl.glEnable(GL.GL_DEPTH_TEST);
  gl.glDisable(GL.GL_BLEND);
  gl.glEnable(GL.GL_LIGHTING);
gl.glPopMatrix();
gl.glDisable(GL.GL_STENCIL_TEST);

gl.glPushMatrix();
  drawCube();
gl.glPopMatrix();


請參考以下範例。


// 實作GLEventListener介面之方法
// 初始化JOGL
public void init(GLAutoDrawable drawable) {
  gl = drawable.getGL();
  
  // Clear window with color   
  gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

  // set the shading model
  gl.glShadeModel(GL.GL_SMOOTH);

  // set up a single white light
  float lightColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };

  gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, lightColor, 0);
  gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, lightColor, 0);

  gl.glEnable(GL.GL_LIGHTING);
  gl.glEnable(GL.GL_LIGHT0);
  gl.glEnable(GL.GL_DEPTH_TEST);

  gl.glEnable(GL.GL_TEXTURE_2D);
  gl.glTexEnvf(GL.GL_TEXTURE_ENV, 
    GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);

  // load the textures
  cubeTex = loadTexture("opengl.jpg");
  marbleTex = loadTexture("marble.jpg");

  gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

  float[] plane = { 0.0f, 1.0f, 0.0f, 0.0f };

  // dot product of plane and light position
  float dot = plane[0] * g_lightPos[0] + plane[1] * g_lightPos[1] + 
              plane[1] * g_lightPos[2] + plane[3] * g_lightPos[3];

  // first column
  g_shadowMatrix[0]  = dot  - g_lightPos[0] * plane[0];
  g_shadowMatrix[4]  = 0.0f - g_lightPos[0] * plane[1];
  g_shadowMatrix[8]  = 0.0f - g_lightPos[0] * plane[2];
  g_shadowMatrix[12] = 0.0f - g_lightPos[0] * plane[3];

  // second column
  g_shadowMatrix[1]  = 0.0f - g_lightPos[1] * plane[0];
  g_shadowMatrix[5]  =  dot - g_lightPos[1] * plane[1];
  g_shadowMatrix[9]  = 0.0f - g_lightPos[1] * plane[2];
  g_shadowMatrix[13] = 0.0f - g_lightPos[1] * plane[3];

  // third column
  g_shadowMatrix[2]  = 0.0f - g_lightPos[2] * plane[0];
  g_shadowMatrix[6]  = 0.0f - g_lightPos[2] * plane[1];
  g_shadowMatrix[10] =  dot - g_lightPos[2] * plane[2];
  g_shadowMatrix[14] = 0.0f - g_lightPos[2] * plane[3];

  // fourth column
  g_shadowMatrix[3]  = 0.0f - g_lightPos[3] * plane[0];
  g_shadowMatrix[7]  = 0.0f - g_lightPos[3] * plane[1];
  g_shadowMatrix[11] = 0.0f - g_lightPos[3] * plane[2];
  g_shadowMatrix[15] =  dot - g_lightPos[3] * plane[3];    
}

// 載入圖像以作為貼圖之用
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();

  gl.glLoadIdentity();
  glu.gluLookAt(0.0, 3.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  // Clear
  gl.glClear(GL.GL_COLOR_BUFFER_BIT | 
    GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);

  // rotate the scene
  angle += 3.0;
  gl.glRotated(-angle/8.0, 0.0, 1.0, 0.0);
  gl.glRotated(10.0 * Math.sin(angle/45.0), 1.0, 0.0, 0.0);

  gl.glColorMask(false, false, false, false);
  gl.glDepthMask(false);

  gl.glEnable(GL.GL_STENCIL_TEST);
  gl.glStencilFunc(GL.GL_ALWAYS, 1, ~0);
  gl.glStencilOp(GL.GL_REPLACE, GL.GL_REPLACE, GL.GL_REPLACE);

  drawSurface();

  gl.glColorMask(true, true, true, true);
  gl.glDepthMask(true);
  
  gl.glStencilFunc(GL.GL_EQUAL, 1, ~0);
  
  gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP);

  gl.glPushMatrix();
    gl.glScalef(1.0f, -1.0f, 1.0f);
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, g_lightPos, 0);
    drawCube();
  gl.glPopMatrix();

  gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, g_lightPos, 0);
  gl.glEnable(GL.GL_BLEND);
  drawSurface();
  gl.glDisable(GL.GL_BLEND);

  gl.glPushMatrix();
    gl.glDisable(GL.GL_TEXTURE_2D);
    gl.glDisable(GL.GL_LIGHTING);
    gl.glDisable(GL.GL_DEPTH_TEST);
    gl.glEnable(GL.GL_BLEND);
    gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR);
    gl.glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
  
    gl.glMultMatrixf(g_shadowMatrix, 0);
    drawCube();
  
    gl.glEnable(GL.GL_TEXTURE_2D);
    gl.glEnable(GL.GL_DEPTH_TEST);
    gl.glDisable(GL.GL_BLEND);
    gl.glEnable(GL.GL_LIGHTING);
  gl.glPopMatrix();
  gl.glDisable(GL.GL_STENCIL_TEST);

  gl.glPushMatrix();
    drawCube();
  gl.glPopMatrix();
}

private void drawSurface(){
  float[] surfaceColor = { 1.0f, 1.0f, 1.0f, 0.6f };
  gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, surfaceColor, 0);
  gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, 
    surfaceColor, 0);
  gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 200.0f);

  // 啟用貼圖
  cubeTex.enable();
  marbleTex.enable();
  // 繫結貼圖
  marbleTex.bind();

  gl.glBegin(GL.GL_QUADS);
  gl.glNormal3f(0.0f, 1.0f, 0.0f);

  float x = -5.0f;
  float z = -5.0f;

  for (int i = 0; i < 10; i++, x += 1.0f) {
    for (int j = 0; j < 10; j++, z += 1.0f) {
      gl.glTexCoord2f(0.0f, 0.0f);
      gl.glVertex3f(x, 0.0f, z);
      gl.glTexCoord2f(1.0f, 0.0f);
      gl.glVertex3f(x + 1.0f, 0.0f, z);
      gl.glTexCoord2f(1.0f, 1.0f);
      gl.glVertex3f(x + 1.0f, 0.0f, z + 1.0f);
      gl.glTexCoord2f(0.0f, 1.0f);
      gl.glVertex3f(x, 0.0f, z + 1.0f);
    }
    z = -5.0f;
  }

  gl.glEnd();

  marbleTex.disable();  



【執行結果】


【參考資料】

[1] Java Platform, Standard Edition 7, API Specification.
[2] JOGL.
[3] 黃嘉輝,完全探索Java遊戲程式設計,上奇資訊。


© Chia-Hui Huang

JOGL Texture

在實心 (Solid) 物體的表面,可藉由貼圖將圖像貼至物體表面,此稱為Texture (紋理)。

圖像為一數位影像,因此貼圖其實是由一訊號取樣後之結果,此過程稱為重新取樣 (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類別的newTexture()方法自檔案或資料流中載入,其圖像格式可為:
  • 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) 格式。 
並可由Texture類別的setTexParameteri()方法設定其Wrap與Filter的方式。

載入圖像的程式架構:


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

JOGL Animation

在JOGL中,動畫的環境由com.sun.opengl.util.Animator類別處理,其建構函式為:

  public Animator()
  public Animator(GLAutoDrawable drawable)

其中參數drawableGLAutoDrawable介面之物件,可GLCanvasGLJPanel類別建立、或以GLAutoDrawable介面的getGL()方法建立。

Animator物件建立之後,可使用以下方法處理動畫:
  • start()開始處理動畫。
  • stop()停止處理動畫。
  • isAnimating()判斷是否正在執行動畫處理。
以Java Swing為例:


// Set OpenGL Capabilities
GLCapabilities glcapabilities = new GLCapabilities();
// Set Drawable Factory
GLDrawableFactory gldrawablefactory =
  GLDrawableFactory.getFactory();
GLDrawable gldrawable = gldrawablefactory.getGLDrawable(
  this, glcapabilities, null);
// Set Double Buffer
glcapabilities.setDoubleBuffered(true);

// 建立GLJPanel物件 
GLJPanel glpanel = new GLJPanel(glcapabilities);
// 註冊GLEventListener
glpanel.addGLEventListener(this);
...

// 建立Animator物件
Animator animator = new Animator(glpanel);
glpanel.requestFocusInWindow();
// 開始動畫處理
animator.start();
...


當以start()方法開始處理動畫時,則整個GLJPanel物件將處於動畫的狀態,但如何處理動畫,仍需自行設計。

請參考以下範例,以Animator類別處理動畫環境,此外並使用以下的方法:
  • glLoadIdentity():載入單位矩陣 (Identity Matrix)。
  • glMaterialfv():設定物體的材質 (Material)。
  • glMatrixMode():設定座標系統。
  • glPopMatrix():自堆疊最上層移除矩陣。
  • glPushMatrix():複製目前矩陣至堆疊最上層。
  • gluNewQuadric():建立二次曲面 (Quadric)。
  • gluQuadricOrientation():設定二次曲面的方向 (Orientation)。
  • glutWireSphere():繪製線框球體 (Wireframe Sphere)。


// 實作GLEventListener介面之方法
// 初始化JOGL
public void init(GLAutoDrawable drawable) {
  GL gl = drawable.getGL();
  gl.setSwapInterval(1);

  float white[] = {1.0f, 1.0f, 1.0f, 1.0f};

  gl.glEnable(GL.GL_CULL_FACE);
  // 啟用光源 
  gl.glEnable(GL.GL_LIGHTING);
  // 啟用光源0 
  gl.glEnable(GL.GL_LIGHT0);
  gl.glEnable(GL.GL_DEPTH_TEST);

  /* make the Ball */
  ball = gl.glGenLists(1);

  GLUquadric quad;
  quad = glu.gluNewQuadric();
  glu.gluQuadricOrientation(quad, GLU.GLU_OUTSIDE);
  glu.gluQuadricNormals    (quad, GLU.GLU_SMOOTH);
  glu.gluQuadricTexture    (quad, true);

  gl.glNewList(ball, GL.GL_COMPILE);
  gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, white, 0);

  glut.glutWireSphere(5, 25, 25);
  gl.glEndList();
          
  gl.glEnable(GL.GL_NORMALIZE);
}

// 繪製圖形
public void display(GLAutoDrawable drawable) {
  angle += 100.0f;

  GL gl = drawable.getGL();
  
  if ((drawable instanceof GLJPanel) &&
      !((GLJPanel) drawable).isOpaque() &&
      ((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {

    // 以目前之顏色清除視窗
    gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
  } 
  else {
    // 以目前之顏色清除視窗
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
  }
          
  // 複製目前之矩陣至堆疊最上層
  gl.glPushMatrix();
  // 沿x座標旋轉指定角度
  gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
  // 沿y座標旋轉指定角度
  gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
  // 沿z座標旋轉指定角度
  gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
          
  // 沿x,y,z座標旋轉指定角度
  gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
  gl.glCallList(ball);
  // 自堆疊最上層移除矩陣
  gl.glPopMatrix();
  // 即刻執行JOGL指令 
  gl.glFlush();
}

// 當視窗大小改變時
public void reshape(GLAutoDrawable drawable, 
  int x, int y, int width, int height) {
  
  GL gl = drawable.getGL();

  float h = (float)height / (float)width;
          
  // 設定座標系統
  gl.glMatrixMode(GL.GL_PROJECTION);

  gl.glLoadIdentity();
  gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
  // 設定座標系統
  gl.glMatrixMode(GL.GL_MODELVIEW);
  gl.glLoadIdentity();
  gl.glTranslatef(0.0f, 0.0f, -40.0f);
}


【執行結果】


【參考資料】

[1] Java Platform, Standard Edition 7, API Specification.
[2] JOGL.
[3] 黃嘉輝,完全探索Java遊戲程式設計,上奇資訊。

© Chia-Hui Huang