Saturday, March 15, 2014

OpenGL ES 2.0 trên android - Áp dụng phép chiếu và camera

Áp dụng phép chiếu và camera

Trong môi trường OpenGL ES, phép chiếu và máy quay cho phép bạn hiển thị các đối tượng hình vẽ theo cách giống cách bạn nhìn thấy đối tượng vật lý với đôi mắt của bạn. Mô phỏng vật lý này được thực hiển với biến đối toán học của tọa độ hình vẽ:
·         Chiếu - chuyển đổi này điều chỉnh tọa độ của đối tượng được vẽ dựa trên chiều rộng và chiều cao của GLSurfaceView nơi chúng được hiển thị. Mà không cần tính toán này, các đối tượng được vẽ bởi OpenGL ES đang sai lệch bởi tỷ lệ đồng đều của cửa sổ xem. Một chuyển đổi chiếu thường chỉ phải được tính toán khi tỷ lệ của khung nhìn OpenGL được thành lập hoặc thay đổi trong onSurfaceChanged() của renderer của bạn. Để biết thêm thông tin về OpenGL ES dự và phối hợp ánh xạ, xem bản đồ tọa độ cho các đối tượng được vẽ.
·         Camera - chuyển đổi này điều chỉnh tọa độ của đối tượng được vẽ dựa trên một vị trí máy quay ảo. Điều quan trọng cần lưu ý là OpenGL ES không định nghĩa một đối tượng máy ảnh thực tế, nhưng thay vì cung cấp phương pháp hữu ích mà mô phỏng một máy ảnh bằng cách biến đổi màn hình hiển thị của các đối tượng vẽ. Một biến đổi camera có thể được tính toán một lần khi bạn thiết lập GLSurfaceView của bạn, hoặc có thể thay đổi tự động dựa trên các hành động sử dụng hay chức năng ứng dụng của bạn.
Bài học này mô tả làm thế nào để tạo ra một chiếu và xem máy ảnh và áp dụng nó cho Shapes được vẽ trong GLSurfaceView của bạn.

1.1.   Định nghĩa phép chiếu

Dữ liệu cho một biến đổi của phép chiếu được tính toán trong hàm onSurfaceChanged() của lớp GLSurfaceView.Renderer. Ví dụ dưới đây lấy chiều cao và rộng của GLSurfaceView và sử dụng để chứa biến đổi ma trận phép chiếu sử dụng hàm Matrix.frustumM().
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {

    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
Mã này chứa một ma trận chiếu, mProjectionMatrix mà bạn có thể kết hợp với sự chuyển đổi camera quan sát trong hàm onDrawFrame(), được thể hiện trong phần tiếp theo.
Lưu ý: Chỉ cần áp dụng một phép chiếu cho đối tượng vẽ của bạn, nếu không kết quả sẽ là một màn hình trống rỗng. Nói chung, bạn cũng phải áp dụng các chuyển camera để cho bất cứ điều gì để hiển thị trên màn hình.

1.2.   Định nghĩa một Camera

Hoàn tất quá trình chuyển đối tượng vẽ của bạn bằng cách thêm một biến đổi camera như một phần của quá trình vẽ. Trong mã ví dụ sau đây, việc chuyển đổi camera được tính toán bằng cách sử dụng Matrix.setLookAtM () và sau đó kết hợp với ma trận chiếu tính trước đó. Các ma trận biến đổi kết hợp này sau đó được thông qua để vẽ ra shape.
@Override

public void onDrawFrame(GL10 unused) {

    ...

    // Set the camera position (View matrix)
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    // Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

    // Draw shape
    mTriangle.draw(mMVPMatrix);
}

1.3.   Áp dụng phép chiếu và camera

Để sử dụng chiếu kết hợp với camera ma trận biến đổi thể hiện trong phần xem trước, chỉnh sửa hàm draw () của đối tượng đồ họa của bạn để chấp nhận các ma trận biến đổi kết hợp và áp dụng nó vào shape:
public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix

    ...

    // get handle to shape's transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    ...
}
Một khi bạn đã tính toán một cách chính xác và áp dụng phép chiếu với camera chuyển đổi, các đối tượng đồ họa của bạn được rút ra theo tỷ lệ chính xác và sẽ giống như thế này:
Figure 1. Triangle drawn with a projection and camera view applied.
Bây giờ bạn có một ứng dụng hiển thị shape của bạn với tỷ lệ chính xác, đã đến lúc để thêm chuyển động cho hình của bạn.

OpenGL ES 2.0 trên android - Định nghĩa Shapes - Hình

Định nghĩa Shapes

Việc có thể để xác định Shapes để vẽ trong context của một khung nhìn OpenGL ES là bước đầu tiên trong việc tạo ra tác phẩm đồ họa cao cấp của bạn. Vẽ với OpenGL ES có thể là một chút khó khăn mà không biết một số điều cơ bản về cách OpenGL ES hy vọng bạn xác định đối tượng đồ họa.
Bài học này giải thích OpenGL ES phối hợp hệ thống liên quan đến một màn hình thiết bị Android, những điều cơ bản của việc xác định Shapes, bề mặt Shapes, cũng như xác định một tam giác và một hình vuông.

1.1.   Định nghĩa một Tam giác

OpenGL ES cho phép bạn xác định đối tượng rút ra sử dụng tọa độ trong không gian ba chiều. Vì vậy, trước khi bạn có thể vẽ một hình tam giác, bạn phải xác định tọa độ của nó. Trong OpenGL, cách điển hình để làm điều này là để xác định một mảng đỉnh của số thực. Cho hiệu quả tối đa, bạn viết các tọa độ vào một ByteBuffer, nó sẽ thông qua vào các đường ống dẫn đồ họa OpenGL ES để xử lý.
public class Triangle {

    private FloatBuffer vertexBuffer;

    // number of coordinates per vertex in this array

    static final int COORDS_PER_VERTEX = 3;

    static float triangleCoords[] = {   // in counterclockwise order:
             0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };

    // Set color with red, green, blue and alpha (opacity) values

    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

    public Triangle() {

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (number of coordinate values * 4 bytes per float)
                triangleCoords.length * 4);
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer();
        // add the coordinates to the FloatBuffer
        vertexBuffer.put(triangleCoords);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);
    }
}
Theo mặc định, OpenGL ES giả định một hệ thống phối hợp nơi [0,0,0] (X, Y, Z) xác định tâm của khung GLSurfaceView, [1,1,0] là góc trên bên phải của khung và [- 1, -1,0] là góc dưới bên trái của khung. Cho một minh họa của hệ thống phối hợp này, hãy xem hướng phát triển OpenGL ES.
Lưu ý rằng các tọa độ của Shapes này được xác định theo một thứ tự ngược chiều kim đồng hồ. Thứ tự bản vẽ là quan trọng vì nó xác định mặt trước và mặt sau của bề mặt của Shapes mà bạn vẽ, với mặt sau bề mặt, bạn có thể chọn không vẽ bằng cách sử dụng tính năng tiêu hủy mặt OpenGL ES. Để biết thêm thông tin về mặt và hủy, xem hướng dẫn phát triển OpenGL ES.

1.2.   Định nghĩa hình vuông

Xác định tam giác là khá dễ dàng trong OpenGL, nhưng nếu bạn muốn phức tạp hơn một chút? Gì nhỉ? một hình vuông? Có một số cách để làm điều này, nhưng một con đường điển hình để vẽ một hình dạng như vậy trong OpenGL ES là sử dụng hai hình tam giác được vẽ với nhau:
Figure 1. Drawing a square using two triangles.
Một lần nữa, bạn nên xác định các đỉnh theo một thứ tự ngược chiều kim đồng hồ cho cả hai hình tam giác mà đại diện cho hình dạng này, và đặt các giá trị trong một ByteBuffer. Để tránh việc xác định tọa độ hai chia sẻ bởi mỗi tam giác hai lần, sử dụng một danh sách bản vẽ để cho các đường ống dẫn đồ họa OpenGL ES cách vẽ các đỉnh. Đây là mã cho hình này:
public class Square {

    private FloatBuffer vertexBuffer;
    private ShortBuffer drawListBuffer;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;

    static float squareCoords[] = {
            -0.5f,  0.5f, 0.0f,   // top left
            -0.5f, -0.5f, 0.0f,   // bottom left
             0.5f, -0.5f, 0.0f,   // bottom right
             0.5f,  0.5f, 0.0f }; // top right

    private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

    public Square() {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
        // (# of coordinate values * 4 bytes per float)
                squareCoords.length * 4);

        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(
        // (# of coordinate values * 2 bytes per short)
                drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);
    }
}
Ví dụ này cung cấp cho bạn một cái nhìn vào những gì nó cần để tạo ra hình dạng phức tạp hơn với OpenGL. Nói chung, bạn sử dụng danh sách các hình tam giác để vẽ các đối tượng. Trong bài học tiếp theo, bạn tìm hiểu làm thế nào để vẽ các hình dạng trên màn hình.

2.      Vẽ Shapes

Sau khi bạn xác định shapes để được vẽ với OpenGL, bạn có thể muốn vẽ chúng. Vẽ hình với OpenGL ES 2.0 có thêm một chút mã hơn bạn có thể tưởng tượng, bởi vì các API cung cấp rất nhiều quyền kiểm soát các đường ống dẫn vẽ đồ họa.
Bài học này giải thích làm thế nào để vẽ các hình dạng bạn định nghĩa trong bài học trước bằng cách sử dụng OpenGL ES 2.0 API.

2.1.   Khởi tạo Shapes

Trước khi bạn vẽ bất kỳ thứ gì, bạn phải khởi tạo và tải các Shapes mà bạn muốn vẽ. Trừ khi cấu trúc của các Shapes thay đổi trong quá trình thực hiện, bạn nên khởi tạo chúng trong onSurfaceCreated () của renderer của bạn cho bộ nhớ và xử lý hiệu quả.
public void onSurfaceCreated(GL10 unused, EGLConfig config) {

    ...
    // initialize a triangle
    mTriangle = new Triangle();
    // initialize a square
    mSquare = new Square();
}

2.2.   Vẽ Shape

Vẽ một định nghĩa Shape bằng cách sử dụng OpenGL ES 2.0 đòi hỏi một số lượng đáng kể của mã, bởi vì bạn phải cung cấp rất nhiều chi tiết để các đường ống dẫn vẽ đồ họa. Cụ thể, bạn phải xác định như sau:
·         Vertex Shader - đồ họa OpenGL ES đang để hiển thị các đỉnh của một Shape.
·         Fragment Shader – mã OpenGL ES cho dựng hình bề mặt của một shape với màu sắc hoặc Textures.
·         Program - Một đối tượng OpenGL ES có chứa các bóng đổ bạn muốn sử dụng để vẽ một hoặc nhiều hình dạng.
Bạn cần ít nhất một vertex shader để vẽ một shape và một fragment shader để tô màu cho shape. Các bóng đổ phải được hoàn chỉnh và sau đó thêm vào một chương trình OpenGL ES, sau đó được sử dụng để vẽ hình dạng. Dưới đây là một ví dụ về cách xác định shaders cơ bản bạn có thể sử dụng để vẽ một hình dạng:
private final String vertexShaderCode =
    "attribute vec4 vPosition;" +
    "void main() {" +
    "  gl_Position = vPosition;" +
    "}";

private final String fragmentShaderCode =
    "precision mediump float;" +
    "uniform vec4 vColor;" +
    "void main() {" +
    "  gl_FragColor = vColor;" +
    "}";
Shaders chứa OpenGL Shading Language (GLSL) mã phải được biên dịch trước khi sử dụng nó trong môi trường OpenGL ES. Để biên dịch mã này, tạo ra một utility method trong lớp renderer của bạn:
public static int loadShader(int type, String shaderCode){

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}
Để vẽ shape của bạn, bạn phải biên dịch shader code, thêm chúng vào một đối tượng program OpenGL ES và sau đó liên kết các program. Làm điều này trong hàm khởi tạo đối tượng, vì vậy nó chỉ được thực hiện một lần.
Lưu ý: Biên dịch shaders OpenGL ES và các liên kết program là tốn kém về chu kỳ CPU và thời gian xử lý, vì vậy bạn nên tránh làm điều này nhiều hơn một lần. Nếu bạn không biết nội dung của các bóng đổ của bạn tại thời gian chạy, bạn nên xây dựng mã của bạn như vậy mà họ chỉ được tạo ra một lần và sau đó lưu lại để sử dụng sau này.
public class Triangle() {

    ...

    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);

    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
}
Tại thời điểm này, bạn đã sẵn sàng để thêm các lời gọi vẽ shape của bạn. Vẽ hình với OpenGL ES yêu cầu bạn chỉ định một số thông số để cho các đường ống dẫn vẽ những gì bạn muốn vẽ và làm thế nào để vẽ nó. Kể từ khi lựa chọn vẽ có thể khác nhau bởi hình dạng, đó là một ý tưởng tốt để có các lớp hình dạng của bạn chứa logic vẽ của mình.
Tạo ra một hàm draw() để vẽ shape. Mã này thiết đặt vị trí và giá trị màu cho vertex shader và fragment shader, và sau đó thực hiện chức năng vẽ.
public void draw() {

    // Add program to OpenGL ES environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                 GLES20.GL_FLOAT, false,
                                 vertexStride, vertexBuffer);

    // get handle to fragment shader's vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}
Một khi bạn có tất cả các mã này, vẽ đối tượng này chỉ đòi hỏi một lời gọi đến draw() từ bên trong phương pháp onDrawFrame()của renderer của bạn. Khi bạn chạy ứng dụng, nó sẽ giống như thế này:
Figure 1. Triangle drawn without a projection or camera view.
Có một vài vấn đề với mã ví dụ này. Trước hết, nó sẽ không gây ấn tượng với bạn bè của bạn. Thứ hai, hình tam giác là một chút bị đè nén và thay đổi hình dạng khi bạn thay đổi hướng màn hình của thiết bị. Lý do hình dạng bị lệch là do thực tế là các đỉnh của đối tượng đã không được sửa chữa cho tỷ lệ diện tích màn hình, nơi các GLSurfaceView được hiển thị. Bạn có thể khắc phục vấn đề bằng cách sử dụng chiếu và xem ảnh trong bài học tiếp theo.

Cuối cùng, hình tam giác là hình cơ bản, nên có một chút nhàm chán. Trong bài học thêm chuyển độn, bạn làm cho hình dạng này xoay và sử dụng thú vị hơn của đường ống đồ họa OpenGL ES.

OpenGL ES 2.0 trên android - Khởi tạo OpenGL ES 2.0 trên Android

Xây dựng một môi trường OpenGL ES

Để vẽ đồ họa với OpenGL ES trong ứng dụng Android của bạn, bạn phải tạo một khung nhìn cho chúng. Một trong những cách thẳng thắn để làm điều này là implements cả hai GLSurfaceView và GLSurfaceView.Renderer. Một GLSurfaceView là một khung nhìn cho đồ họa được vẽ với OpenGL và GLSurfaceView.Renderer kiểm soát những gì được vẽ ra trong khung nhìn đó. Để biết thêm thông tin về các lớp này, hãy xem hướng dẫn phát triển OpenGL ES.
GLSurfaceView chỉ là một cách để kết hợp đồ họa OpenGL ES vào ứng dụng của bạn. Cho toàn màn hình hoặc màn hình gần như đầy màn hình, đó là một lựa chọn hợp lý. Những người phát triển muốn kết hợp đồ họa OpenGL ES trong một phần nhỏ layout của họ, nên cần có một cái nhìn tại TextureView. Đối với thực tế, nếu bản thân bạn là nhà phát triển, bạn cũng có thể xây dựng một cái nhìn OpenGL ES sử dụng SurfaceView, nhưng điều này đòi hỏi phải viết khá nhiều mã bổ sung.
Bài học này giải thích làm thế nào để hoàn thành một cách đơn giản để sử dụng GLSurfaceView và GLSurfaceView.Renderer trong một hoạt động ứng dụng đơn giản.

1.1.   Tuyên bố sử dụng OpenGL ES trong Manifest

Để các ứng dụng của bạn sử dụng OpenGL ES 2.0 API, bạn phải thêm tuyên bố sau đây cho Manifest của bạn:
android:glEsVersion="0x00020000" android:required="true" />
Nếu ứng dụng của bạn sử dụng kết cấu nén, bạn cũng phải khai báo các định dạng nén bạn hỗ trợ để các thiết bị không hỗ trợ định dạng này không cố gắng để chạy ứng dụng của bạn:
 android:name="GL_OES_compressed_ETC1_RGB8_texture" />

 android:name="GL_OES_compressed_paletted_texture" />
Để biết thêm thông tin về các định dạng nén kết cấu, xem hướng dẫn phát triển OpenGL.

1.2.   Tạo ra một Activity cho đồ họa OpenGL ES

Các ứng dụng Android sử dụng OpenGL ES có hoạt động giống như bất kỳ ứng dụng khác mà có một giao diện người dùng. Sự khác biệt chính từ các ứng dụng khác là những gì bạn đặt trong layout cho Activity của bạn. Trong khi trong nhiều ứng dụng bạn có thể sử dụng TextView, Button và ListView, trong một ứng dụng có sử dụng OpenGL ES, bạn cũng có thể thêm một GLSurfaceView.

Ví dụ sau cho thấy một thực hiện tối thiểu của một hoạt động có sử dụng một GLSurfaceView như khung nhìn cơ bản của nó:
public class OpenGLES20Activity extends Activity {



    private GLSurfaceView mGLView;



    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);



        // Create a GLSurfaceView instance and set it

        // as the ContentView for this Activity.

        mGLView = new MyGLSurfaceView(this);

        setContentView(mGLView);

    }

}
Lưu ý: OpenGL ES 2.0 yêu cầu Android 2.2 (API Level 8) hoặc cao hơn, do đó hãy chắc chắn rằng mục tiêu dự án Android của bạn là API 2.2 hoặc cao hơn.

1.3.   Xây dựng một đối tượng GLSurfaceView

Một GLSurfaceView là một khung nhìn đặc biệt mà bạn có thể vẽ đồ họa OpenGL ES. Nó không làm được gì nhiều với chính nó. Bản vẽ thực tế của đối tượng được kiểm soát trong GLSurfaceView.Renderer mà bạn thiết lập cho khung nhìn này. Trong thực tế, mã cho đối tượng này là quá mỏng, bạn có thể bị cám dỗ để bỏ qua mở rộng nó và chỉ cần tạo ra một thể GLSurfaceView chưa sửa đổi, nhưng dừng làm điều đó. Bạn cần phải mở rộng lớp này để nắm bắt sự kiện liên lạc, được bao phủ trong bài học  Responding to Touch Events.
Mã cần thiết cho một GLSurfaceView là tối thiểu, do đó để thực hiện nhanh chóng, chúng ta thường chỉ cần tạo một lớp bên trong Activity sử dụng nó:
class MyGLSurfaceView extends GLSurfaceView {



    public MyGLSurfaceView(Context context){

        super(context);



        // Set the Renderer for drawing on the GLSurfaceView

        setRenderer(new MyRenderer());

    }

}
Khi sử dụng OpenGL ES 2.0, bạn phải thêm lời gọi khác trong hàm khởi tạo của GLSurfaceView, quy định sử dụng API 2.0:
// Create an OpenGL ES 2.0 context

setEGLContextClientVersion(2);
Lưu ý: Nếu bạn đang sử dụng OpenGL ES 2.0 API, chắc chắn rằng bạn khai báo cái này trong manifest của ứng dụng của bạn. Để biết thêm thông tin, xem Khai báo sử dụng OpenGL ES trong Manifest.
Một bổ sung tuỳ chọn khác để thực hiện GLSurfaceView của bạn là để thiết lập chế độ render để chỉ vẽ lên khung nhìn khi có sự thay đổi dữ liệu bản vẽ của bạn bằng cách sử dụng thiết lập GLSurfaceView.RENDERMODE_WHEN_DIRTY:
// Render the view only when there is a change in the drawing data

setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
Thiết lập này ngăn cản khung GLSurfaceView được vẽ lại cho đến khi bạn gọi requestRender (), mà là hiệu quả hơn cho các ứng dụng mẫu này.

1.4.   Xây dựng một lớp Renderer

Việc thực hiện của lớp GLSurfaceView.Renderer, hoặc renderer, trong một ứng dụng có sử dụng OpenGL ES là nơi mà mọi thứ bắt đầu trở nên thú vị. Lớp này kiểm soát những gì được vẽ trên GLSurfaceView mà nó có liên quan. Có ba hàm trong một renderer được gọi bởi hệ thống Android để tìm ra những gì và làm thế nào để vẽ trên một GLSurfaceView:
·         onSurfaceCreated () - Được gọi là một lần để thiết lập môi trường OpenGL ES của khung nhìn.
·         onDrawFrame () - Được gọi mỗi khi vẽ lại khung nhìn.
·         onSurfaceChanged () - Được gọi là nếu khung nhìn thay đổi, ví dụ như khi của thiết bị màn hình thay đổi định hướng.
Dưới đây là một ví dụ rất cơ bản của một renderer OpenGL ES, mà không gì hơn là vẽ một nền màu xám trong GLSurfaceView:
public class MyGLRenderer implements GLSurfaceView.Renderer {



    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        // Set the background frame color

        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    }



    public void onDrawFrame(GL10 unused) {

        // Redraw background color

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    }



    public void onSurfaceChanged(GL10 unused, int width, int height) {

        GLES20.glViewport(0, 0, width, height);

    }

}
Đó là tất cả những gì phải làm! Các ví dụ trên tạo ra một ứng dụng Android đơn giản mà sẽ hiển thị một màn hình màu xám sử dụng OpenGL. Trong khi mã này không làm bất cứ điều gì rất thú vị, bằng cách tạo ra các lớp này, bạn đã đặt nền móng bạn cần để bắt đầu vẽ các yếu tố đồ họa với OpenGL.
Lưu ý: Bạn có thể tự hỏi tại sao những phương pháp này có một tham số GL10, khi bạn đang sử dụng các API OpengGL ES 2.0. Những chữ ký phương pháp chỉ đơn giản là tái sử dụng cho các API 2.0 để giữ mã framework Android đơn giản.

Nếu bạn đã quen thuộc với các API OpenGL ES, bây giờ bạn sẽ có thể thiết lập một môi trường OpenGL ES trong ứng dụng của bạn và bắt đầu vẽ đồ họa. Tuy nhiên, nếu bạn cần nhiều hơn một chút giúp đỡ bắt đầu với OpenGL, đầu vào cho các bài học tiếp theo cho một vài gợi ý hơn.

Tuesday, January 7, 2014

Khái niệm về RMI trong Java

Lập trình đối tượng phân tán là một trong những vấn đề nóng bỗng của công nghệ phân tán phần mềm ngày nay. Java là ngôn ngữ đi tiên phong với RMI (Remote Method Invocation) – một kĩ thuật cài đặt các đối tượng phân tán vô cùng hiệu quả và linh động.
Thông thường các chương trình của chúng ta được viết dưới dạng thủ tục hoặc hàm và việc các hàm gọi lẫn nhau, truyền tham số hay kết quả cho nhau chỉ xảy ra ở máy cục bộ. Kỷ thuật RMI (Remote Method Invoke) – mang ý nghĩa triệu gọi phương thức từ xa – là cách thức giao tiếp giữa các đối tượng trong Java có mã lệnh cài đặt nằm trên các máy khác nhau có thể triệu gọi lẫn nhau.
rmi 1 [Java] Khái niệm về RMI trong Java
Để giải quyết một số vấn đề trong việc truyền thông giữa Client/Server. RMI không gọi trực tiếp mà thông qua lớp trung gian. Lớp này tồn tại ở cả hai phía Client và Server. Lớp ở máy Client gọi là Stub, lớp ở máy Server gọi là Skel (Skeletion).

CÁC ĐẶT TÍNH CỦA RMI

- RMI là mô hình đối tượng phân tán của Java, nó giúp cho việc truyền thông giữa các đối tượng phân tán được dễ dàng hơn.
- RMI là API bậc cao được xây dựng dựa trên lập trình Socket.
- RMI không những cho phép chúng ta truyền dữ liệu giữa các đối tượng trên các hệ thống máy tính khác nhau, mà còn triệu gọi các phương thức trong các đối tượng ở xa (Remote Object).
- Việc truyền dữ liệu giữa các máy khác nhau được xử lý một cách trong suốt bởi máy ảo Java (Java virtual machine).
- Tương tự như mô hình Client/Server, RMI vẫn lấy/duy trì khái niệm của Client và Server, tuy nhiên cách tiếp cận (approach) của RMI linh hoạt hơn, mềm dẻo hơn so với môt hình Client/Server.
- Một điều thuận lợi quan trong nhất của RMI là nó cung cấp cớ chế callbacks, nó cho phép Server triệu gọi các phương thức ở Client.

KIẾN TRÚC CƠ BẢN CỦA RMI

Remote interface: Nên extend từ java.rmi.remote.Nó khai báo tất cả các phương thức mà Client có thể triệu gọi. Tất cả các method trong interface này nên throw RemoteException
Remote implementation: Được thực thi từ Remote interface và mở rộng từ UnicastRemoteObject. Triển khai các method được khai báo trong Interface tại đây. Nó là một Remote Object thực sự. Phát sinh hai lớp trung gian Stub và Skel.
 Server class bao gồm:
- RMI registry: Bộ đăng kí này sẽ đăng kí một Remote object với Naming Registry. Giúp các Remote object được chấp nhận khi gọi các method từ xa.
- Các class thực thi trên server.
Client class: Truy vấn trên tên Remote object trên RMI registry, thông qua stub để gọi các phương thức trên server.
cach hoat dong cua rmi [Java] Khái niệm về RMI trong Java

CÁCH LÀM VIỆC CỦA RMI

- Các Đối tượng ở phía Server đăng kí với bộ đăng kí RMI registry.
- Client kiểm tra các đối tượng ở xa trong RMI Registry.
- Vị trí của một đối tượng ở xa được xác định trong RMI Registry. Một stub được trả về cho Client.
- Remote object có thể được sử dụng tương tự như Local object để truy xuất đến toàn bộ tài nguyên. Việc truyền thông giữa Client và Server được xử lý bởi Stub và Skel.
Tìm hiểu thêm về RMI tại Overview of RMI