Sunday, December 12, 2010

Chỉ dẫn lập trình game 3D trên Android (P5)

Đang chờ deploy cái web viết tiếp loạt bài về OpenGL vậy.
Bài hôm nay tôi sẽ giới thiệu cho các bạn cách vẽ một hình đa giác cách xoay chúng như thế nào. Bài trước các bạn đã được học về GLSurfaceView và hãy chắc chắn rằng bạn đã đọc nó vì nó rất quan trọng cho bài hôm nay.
Loạt bài trước tôi cũng đã giới thiệu với các bạn một số khái niệm về đỉnh, tam giác, đa giác. Hôm nay trước khi vào vẽ đa giác tôi sẽ giới thiệu cho các bạn thêm một số khái niệm khác.
1, Cạnh:
Cạnh là một đường thẳng nối 2 đỉnh với nhau. Chúng là đường viền của mặt và đa giác. Trong không gian 3D một cạnh có thể là một đường giao nhau của 2 mặt, do đó khi cạnh này chuyển đổi sẽ dẫn đến sự thay đổi theo của các đỉnh, các mặt kết nối với chúng.
Trong OpenGL ES bạn không định nghĩa các cạnh, thay vào đó bạn định nghĩa các mặt bởi các đỉnh khi đó ta sẽ có các cạnh.
Nếu bạn muốn sửa, thay đổi mộ cạnh bạn có thể thay đổi 2 đỉnh tạo nên cạnh đó.
2, Mặt:
Một cách tổng quát, mặt trong toán học là đa tạp n-1 chiều trong không gian n chiều. Trong tô pô, một mặt hai chiều được gọi là mặt đơn giản nếu nó đồng phôi với một hình vuông trên mặt phẳng hai chiều.
Ví dụ: mặt bán cầu là một mặt đơn giản, còn toàn bộ mặt cầu lại không phải là một mặt đơn giản.
Trong không gian ba chiều, mặt được mặc định là đa tạp hai chiều, là tập hợp những điểm trong hệ tọa độ Đề các ba chiều Oxyz thỏa phương trình: z = f(x,y).
Trong OpenGL ES ta hiểu rằng có thể chia mặt tới mức nhỏ nhất khi đó một mặt chỉ là một tam giác, chúng được tạo lên bởi 3 đỉnh, một chuyển đổi của mặt sẽ ảnh hưởng tới các đỉnh, cạnh liên kết với nó.
Khi uốn khúc trên bề mặt của bạn điều này rất quan trọng để thực hiện các điều khiển đúng hướng của nó. Khi đó bạn phải điều khiển những gì sẽ sảy ra với mặt phía trước và cả mặt phía sau nữa. Tại sao điều này lại rất quan trọng bởi vì hiệu năng của ứng dụng sẽ tăng lên khi bạn không phải vẽ cả 2 mặt mà chỉ thực hiện vẽ mặt phía trước. Đó là ý tưởng tốt sử dụng sự uốn khúc cho tất cả các dự án của bạn. Bạn có thể định nghĩa phía trên của bề mặt bằng cách.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
gl.glCullFace(GL10.GL_BACK); // OpenGL docs

3, Render:
Thời gian để bạn đưa một cái j đó ra ngoài màn hình, có 2 phương thức để bạn làm điều này, 2 phương thức đó là:
public abstract void glDrawArrays(int mode, int first, int count); // OpenGL docs

public abstract void glDrawElements(int mode, int count, int type, Buffer indices); // OpenGL docs

Một số render cơ bản nhất:
GL_POINTS: Render một điểm ra màn hình.
GL_LINE_STRIP: Render một dãy các phân đoạn đường thẳng nối liền nhau, nhưng không nối điểm đầu và điểm cuối.
GL_LINE_LOOP: Giống như GL_LINE_STRIP nhưng không nối điểm đầu và điểm cuối.
GL_LINES: Render một đường thẳng.
GL_TRIANGLES: Render một tam giác.
GL_TRIANGLE_STRIP: Render một loạt các tam giác theo thứ tự VD: Ta có các đỉnh v0, v1, v2, v3, v4, v5 khi đó các tam giác được render là (v0, v1, v2) sau đó là (v2, v1, v3) (lưu ý thứ tự), tiếp theo là (v2, v3, v4) ...
Gl_triangle_strip
GL_TRIANGLE_FAN: Render một loạt các tam giác giống như GL_TRIANGLE_STRIP nhưng các tam giác được vẽ giống như một hình quạt dựa vào một gốc.
Gl_triangle_strip

Giờ chúng ta sẽ vẽ thử một tam giác:
Bạn vẫn còn project hôm trước chứ, ta sẽ thay đổi một chút để có thể render ra được một tam giác.
Ta chỉ cần sửa lại lớp VortexRenderer lại như sau:

package vn.vndev.android.opengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;

/**
 * 
 * @author TanNM
 * 
 */
public class VortexRenderer implements GLSurfaceView.Renderer {
 private static final String LOG_TAG = VortexRenderer.class.getSimpleName();

 private float red = 0f;
 private float green = 0f;
 private float blue = 0f;

 // a raw buffer to hold indices allowing a reuse of points.
 private ShortBuffer indexBuffer;

 // a raw buffer to hold the vertices
 private FloatBuffer vertexBuffer;

 private short[] indicesArray = { 0, 1, 2 };
 private int nrOfVertices = 3;

 private float angle;

 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  // preparation
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  initTriangle();
 }

 @Override
 public void onSurfaceChanged(GL10 gl, int w, int h) {
  gl.glViewport(0, 0, w, h);
 }

 public void setAngle(float angle) {
  this.angle = angle;
 }

 @Override
 public void onDrawFrame(GL10 gl) {
  // define the color we want to be displayed as the "clipping wall"
  gl.glClearColor(red, green, blue, 1.0f);

  // clear the color buffer to show the ClearColor we called above...
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

  // set rotation
  gl.glRotatef(angle, 0f, 1f, 0f);

  gl.glColor4f(0.2f, 0.5f, 0.2f, 0.5f);
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  gl.glDrawElements(GL10.GL_TRIANGLES, nrOfVertices,
    GL10.GL_UNSIGNED_SHORT, indexBuffer);
 }

 private void initTriangle() {
  // float has 4 bytes
  ByteBuffer vbb = ByteBuffer.allocateDirect(nrOfVertices * 3 * 4);
  vbb.order(ByteOrder.nativeOrder());
  vertexBuffer = vbb.asFloatBuffer();

  // short has 4 bytes
  ByteBuffer ibb = ByteBuffer.allocateDirect(nrOfVertices * 2);
  ibb.order(ByteOrder.nativeOrder());
  indexBuffer = ibb.asShortBuffer();

  float[] coords = { -0.5f, -0.5f, 0f, // (x1, y1, z1)
    0.5f, -0.5f, 0f, // (x2, y2, z2)
    0f, 0.5f, 0f // (x3, y3, z3)
  };
  vertexBuffer.put(coords);
  indexBuffer.put(indicesArray);
  vertexBuffer.position(0);
  indexBuffer.position(0);
 }

 public void setColor(float r, float g, float b) {
  red = r;
  green = g;
  blue = b;
 }
}

Để hình tam giác của ta quay với tốc độ tùy vào vị chí mà ta click ta set thêm góc giống như
renderer.setAngle((event.getX() + event.getY()) / 20);
trong phương thức
public boolean onTouchEvent(final MotionEvent event)
của lớp VortexView

Bạn có thể download mã nguồn của ứng dụng về chạy thử.

1 comment:

  1. sao e làm y nguyên mà chỉ ra màn hình đen xì nhỉ

    ReplyDelete