OpenGL ES

Android hỗ trợ đồ hoạ 2D và 3D hiệu suất cao nhờ Open Graphics Library (OpenGL®), cụ thể là API OpenGL ES. OpenGL là một API đồ hoạ nhiều nền tảng chỉ định giao diện phần mềm tiêu chuẩn cho phần cứng xử lý đồ hoạ 3D. OpenGL ES là một phiên bản của thông số kỹ thuật OpenGL dành cho các thiết bị nhúng. Android hỗ trợ một số phiên bản của API OpenGL ES:

  • OpenGL ES 2.0 – Thông số kỹ thuật của API này được hỗ trợ trên Android 2.2 (API cấp 8) trở lên.
  • OpenGL ES 3.0 – Thông số kỹ thuật của API này được hỗ trợ trên Android 4.3 (API cấp 18) trở lên.
  • OpenGL ES 3.1 – Thông số kỹ thuật API này được hỗ trợ trên Android 5.0 (API cấp 21) trở lên.
  • OpenGL ES 3.2 – Thông số kỹ thuật của API này được hỗ trợ trên Android 7.0 (API cấp 24) trở lên.

Thận trọng: Bất kể phiên bản nền tảng Android là gì, mọi thiết bị đều không thể hỗ trợ API OpenGL ES 3.0, trừ phi nhà sản xuất thiết bị cung cấp phương thức triển khai quy trình đồ hoạ này. Nếu bạn chỉ định trong tệp kê khai rằng bắt buộc phải sử dụng OpenGL ES 3.0, thì bạn có thể chắc chắn rằng phiên bản đó sẽ có trên thiết bị. Nếu bạn chỉ định rằng phiên bản cấp thấp hơn là bắt buộc nhưng bạn muốn sử dụng các tính năng 3.0 nếu có, bạn nên kiểm tra thời gian chạy để xem thiết bị hỗ trợ phiên bản OpenGL nào. Để biết thông tin về cách thực hiện việc này, hãy xem bài viết Kiểm tra phiên bản OpenGL ES.

Lưu ý: Android có hỗ trợ OpenGL ES 1.0 và 1.1, nhưng các phiên bản API này không được dùng nữa và không nên dùng cho các ứng dụng hiện đại.

Lưu ý: API cụ thể do khung Android cung cấp sẽ tương tự như API OpenGL ES J2ME JSR239, nhưng không giống hệt nhau. Nếu bạn quen thuộc với thông số kỹ thuật J2ME JSR239, hãy để ý đến các biến thể.

Xem thêm

Thông tin cơ bản

Android hỗ trợ OpenGL thông qua cả API khung và Bộ phát triển gốc (NDK). Chủ đề này tập trung vào các giao diện khung Android. Để biết thêm thông tin về NDK, hãy xem nội dung Android NDK.

Có 2 lớp cơ bản trong khung Android cho phép bạn tạo và chỉnh sửa đồ hoạ bằng API OpenGL ES: GLSurfaceViewGLSurfaceView.Renderer. Nếu mục tiêu của bạn là sử dụng OpenGL trong ứng dụng Android, thì mục tiêu đầu tiên của bạn là hiểu cách triển khai các lớp này trong một hoạt động.

GLSurfaceView
Lớp này là một View, nơi bạn có thể vẽ và thao tác với các đối tượng bằng lệnh gọi API OpenGL và có chức năng tương tự như SurfaceView. Bạn có thể sử dụng lớp này bằng cách tạo một thực thể của GLSurfaceView và thêm Renderer vào thực thể đó. Tuy nhiên, nếu muốn ghi lại các sự kiện trên màn hình cảm ứng, bạn nên mở rộng lớp GLSurfaceView để triển khai trình nghe thao tác chạm, như trình bày trong bài học huấn luyện về OpenGL, phần Phản hồi sự kiện chạm.
GLSurfaceView.Renderer
Giao diện này xác định các phương thức cần thiết để vẽ đồ hoạ trong GLSurfaceView. Bạn phải cung cấp phương thức triển khai giao diện này dưới dạng một lớp riêng biệt và đính kèm giao diện này vào thực thể GLSurfaceView bằng GLSurfaceView.setRenderer().

Giao diện GLSurfaceView.Renderer yêu cầu bạn triển khai các phương thức sau:

  • onSurfaceCreated(): Hệ thống gọi phương thức này một lần mỗi khi tạo GLSurfaceView. Hãy dùng phương thức này để thực hiện các thao tác chỉ cần thực hiện một lần, chẳng hạn như đặt tham số môi trường OpenGL hoặc khởi chạy các đối tượng đồ hoạ OpenGL.
  • onDrawFrame(): Hệ thống gọi phương thức này trên mỗi lần vẽ lại GLSurfaceView. Sử dụng phương thức này làm điểm thực thi chính để vẽ (và vẽ lại) các đối tượng đồ hoạ.
  • onSurfaceChanged(): Hệ thống gọi phương thức này khi hình dạng của GLSurfaceView thay đổi, bao gồm cả những thay đổi về kích thước của GLSurfaceView hoặc hướng của màn hình thiết bị. Ví dụ: hệ thống gọi phương thức này khi thiết bị thay đổi từ hướng dọc sang hướng ngang. Hãy dùng phương thức này để phản hồi các thay đổi trong vùng chứa GLSurfaceView.

Gói OpenGL ES

Sau khi thiết lập khung hiển thị vùng chứa cho OpenGL ES bằng GLSurfaceViewGLSurfaceView.Renderer, bạn có thể bắt đầu gọi API OpenGL bằng các lớp sau:

  • Lớp API OpenGL ES 2.0
    • android.opengl.GLES20 – Gói này cung cấp giao diện cho OpenGL ES 2.0 và có sẵn kể từ Android 2.2 (API cấp 8).
  • Gói API OpenGL ES 3.0/3.1/3.2
    • android.opengl – Gói này cung cấp giao diện cho các lớp OpenGL ES 3.0/3.1. Phiên bản 3.0 bắt đầu có trên Android 4.3 (API cấp 18). Phiên bản 3.1 có sẵn kể từ Android 5.0 (API cấp 21). Phiên bản 3.2 có sẵn kể từ Android 7.0 (API cấp 24).

Nếu bạn muốn bắt đầu tạo ứng dụng có OpenGL ES ngay, hãy làm theo lớp Displaying graphics with OpenGL ES (Hiển thị đồ hoạ với OpenGL ES).

Khai báo các yêu cầu về OpenGL

Nếu ứng dụng của bạn dùng các tính năng OpenGL không có trên một số thiết bị, bạn phải đưa các yêu cầu này vào tệp AndroidManifest.xml. Dưới đây là các nội dung khai báo phổ biến nhất trong tệp kê khai OpenGL:

  • Yêu cầu đối với phiên bản OpenGL ES – Nếu ứng dụng của bạn yêu cầu một phiên bản OpenGL ES cụ thể, thì bạn phải khai báo yêu cầu đó bằng cách thêm các chế độ cài đặt sau vào tệp kê khai như minh hoạ bên dưới.

    Đối với OpenGL ES 2.0:

    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    Khi bạn thêm phần khai báo này, Google Play sẽ hạn chế việc cài đặt ứng dụng của bạn trên những thiết bị không hỗ trợ OpenGL ES 2.0. Nếu ứng dụng của bạn chỉ dành cho các thiết bị hỗ trợ OpenGL ES 3.0, thì bạn cũng có thể chỉ định thông tin này trong tệp kê khai:

    Đối với OpenGL ES 3.0:

    <!-- Tell the system this app requires OpenGL ES 3.0. -->
    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
    

    Đối với OpenGL ES 3.1:

    <!-- Tell the system this app requires OpenGL ES 3.1. -->
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />
    

    Đối với OpenGL ES 3.2:

    <!-- Tell the system this app requires OpenGL ES 3.2. -->
    <uses-feature android:glEsVersion="0x00030002" android:required="true" />
    

    Lưu ý: API OpenGL ES 3.x có khả năng tương thích ngược với API 2.0, tức là bạn có thể linh hoạt hơn khi triển khai OpenGL ES trong ứng dụng. Bằng cách khai báo API OpenGL ES 2.0 làm yêu cầu trong tệp kê khai, bạn có thể dùng phiên bản API đó làm phiên bản mặc định, kiểm tra tính sẵn có của API 3.x trong thời gian chạy rồi sử dụng các tính năng OpenGL ES 3.x nếu thiết bị hỗ trợ. Để biết thêm thông tin về cách kiểm tra phiên bản OpenGL ES mà thiết bị hỗ trợ, hãy xem bài viết Kiểm tra phiên bản OpenGL ES.

  • Yêu cầu nén kết cấu – Nếu ứng dụng của bạn sử dụng định dạng nén kết cấu, thì bạn phải khai báo các định dạng mà ứng dụng hỗ trợ trong tệp kê khai bằng cách sử dụng <supports-gl-texture>. Để biết thêm thông tin về các định dạng nén kết cấu hiện có, hãy xem phần Hỗ trợ nén kết cấu.

    Việc khai báo yêu cầu nén kết cấu trong tệp kê khai sẽ ẩn ứng dụng khỏi người dùng có thiết bị không hỗ trợ ít nhất một trong các loại nén đã khai báo. Để biết thêm thông tin về cách hoạt động của bộ lọc Google Play khi nén kết cấu, hãy xem phần Google Play và cách lọc định dạng nén kết cấu trong tài liệu <supports-gl-texture>.

Ánh xạ toạ độ cho đối tượng đã vẽ

Một trong những vấn đề cơ bản khi hiển thị đồ hoạ trên thiết bị Android là màn hình có thể thay đổi về kích thước và hình dạng. OpenGL giả định một hệ thống toạ độ hình vuông, đồng nhất và theo mặc định, vui lòng vẽ các toạ độ đó lên màn hình thường không phải hình vuông như thể nó là hình vuông hoàn hảo.

Hình 1. Hệ thống toạ độ OpenGL mặc định (bên trái) được ánh xạ tới màn hình thiết bị Android thông thường (bên phải).

Hình minh hoạ ở trên cho thấy hệ thống toạ độ đồng nhất được giả định cho khung OpenGL ở bên trái và cách các toạ độ này thực sự ánh xạ với màn hình thiết bị thông thường theo hướng ngang ở bên phải. Để giải quyết vấn đề này, bạn có thể áp dụng các chế độ chiếu OpenGL và thành phần hiển thị máy ảnh để biến đổi toạ độ sao cho các đối tượng đồ hoạ có tỷ lệ chính xác trên mọi màn hình.

Để áp dụng phép chiếu và khung hiển thị máy ảnh, bạn sẽ tạo một ma trận chiếu và ma trận khung hiển thị máy ảnh rồi áp dụng các khung hiển thị đó cho quy trình kết xuất OpenGL. Ma trận chiếu sẽ tính toán lại các toạ độ đồ hoạ để ánh xạ chính xác đến màn hình thiết bị Android. Ma trận khung hiển thị máy ảnh tạo ra một phép biến đổi để kết xuất các đối tượng từ một vị trí mắt cụ thể.

Chế độ xem máy ảnh và phép chiếu trong OpenGL ES 2.0 trở lên

Trong các API ES 2.0 và 3.0, bạn áp dụng phép chiếu và khung hiển thị máy ảnh bằng cách thêm một thành phần ma trận vào chương trình đổ bóng đỉnh của đối tượng đồ hoạ. Sau khi thêm thành phần ma trận này, bạn có thể tạo và áp dụng ma trận chiếu và ma trận xem camera cho các đối tượng.

  1. Thêm ma trận vào chương trình đổ bóng đỉnh – Tạo một biến cho ma trận chiếu khung hiển thị và đưa biến đó vào dưới dạng hệ số nhân của vị trí của chương trình đổ bóng. Trong ví dụ sau đây về mã chương trình đổ bóng đỉnh (vertex), thành phần uMVPMatrix đi kèm cho phép bạn áp dụng ma trận chiếu và ma trận xem camera cho toạ độ của các đối tượng sử dụng chương trình đổ bóng này.

    Kotlin

    private val vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n"
    

    Java

    private final String vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n";
    

    Lưu ý: Ví dụ trên xác định một thành phần ma trận biến đổi trong chương trình đổ bóng đỉnh mà bạn sẽ áp dụng ma trận chiếu kết hợp và ma trận khung hiển thị máy ảnh. Tuỳ thuộc vào yêu cầu về ứng dụng, bạn nên xác định các thành phần ma trận chiếu và ma trận xem riêng biệt của máy ảnh trong chương trình đổ bóng đỉnh để có thể thay đổi chúng một cách độc lập.

  2. Truy cập vào ma trận chương trình đổ bóng – Sau khi tạo một hook trong chương trình đổ bóng đỉnh để áp dụng phép chiếu và khung hiển thị camera, bạn có thể truy cập vào biến đó để áp dụng ma trận chiếu và ma trận xem của máy ảnh. Mã sau đây cho biết cách sửa đổi phương thức onSurfaceCreated() của quá trình triển khai GLSurfaceView.Renderer để truy cập vào biến ma trận được xác định trong chương trình đổ bóng đỉnh ở trên.

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
        ...
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        ...
    }
    
  3. Tạo ma trận chiếu và ma trận xem camera – Tạo ma trận chiếu và xem cần áp dụng cho các đối tượng đồ hoạ. Mã ví dụ sau đây cho biết cách sửa đổi phương thức onSurfaceCreated()onSurfaceChanged() của quá trình triển khai GLSurfaceView.Renderer để tạo ma trận khung hiển thị máy ảnh và ma trận chiếu dựa trên tỷ lệ khung hình màn hình của thiết bị.

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
    }
    
    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    
        val ratio: Float = width.toFloat() / height.toFloat()
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }
    
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    
        float ratio = (float) width / height;
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
    
  4. Áp dụng ma trận chiếu và ma trận xem camera – Để áp dụng phép biến đổi phép chiếu và phép biến đổi khung hiển thị camera, hãy nhân các ma trận với nhau rồi đặt chúng vào chương trình đổ bóng đỉnh. Mã ví dụ sau đây cho thấy cách sửa đổi phương thức onDrawFrame() của quá trình triển khai GLSurfaceView.Renderer để kết hợp ma trận chiếu và khung hiển thị máy ảnh đã tạo trong mã ở trên, sau đó áp dụng cho các đối tượng đồ hoạ được OpenGL kết xuất.

    Kotlin

    override fun onDrawFrame(gl: GL10) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0)
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0)
    
        // Draw objects
        ...
    }
    

    Java

    public void onDrawFrame(GL10 unused) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0);
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0);
    
        // Draw objects
        ...
    }
    

Để xem ví dụ đầy đủ về cách áp dụng phép chiếu và khung hiển thị máy ảnh với OpenGL ES 2.0, hãy xem lớp Displaying graphics with OpenGL ES (Hiển thị đồ hoạ với OpenGL ES).

Tạo mặt đồng hồ và uốn lượn

Trong OpenGL, mặt của một hình dạng là một bề mặt được xác định bởi ba điểm trở lên trong không gian ba chiều. Một tập hợp gồm ba điểm ba chiều trở lên (được gọi là đỉnh trong OpenGL) có một mặt trước và một mặt sau. Làm sao bạn biết được khuôn mặt nào ở phía trước và mặt nào ở mặt sau? Đây là một câu hỏi rất hay! Câu trả lời có liên quan đến quá trình cuộn dây hoặc hướng mà bạn xác định các điểm của hình dạng.

Toạ độ các đỉnh của tam giác

Hình 1. Hình minh hoạ một danh sách toạ độ chuyển thành thứ tự vẽ ngược chiều kim đồng hồ.

Trong ví dụ này, các điểm của tam giác được xác định theo thứ tự được vẽ ngược chiều kim đồng hồ. Thứ tự vẽ các toạ độ này sẽ xác định hướng cuộn dây cho hình dạng. Theo mặc định, trong OpenGL, mặt được vẽ ngược chiều kim đồng hồ là mặt trước. Hình tam giác như trong Hình 1 được xác định để bạn nhìn vào mặt trước của hình dạng (theo giải thích của OpenGL) và phía còn lại là mặt sau.

Tại sao việc biết được khuôn mặt nào của hình dạng là mặt trước lại quan trọng? Câu trả lời có liên quan đến một tính năng thường dùng của OpenGL, được gọi là chọn lọc khuôn mặt. Chọn lọc khuôn mặt là một tuỳ chọn cho môi trường OpenGL, cho phép quy trình kết xuất bỏ qua (không tính toán hoặc vẽ) mặt sau của một hình dạng, giúp tiết kiệm thời gian, bộ nhớ và chu kỳ xử lý:

Kotlin

gl.apply {
    // enable face culling feature
    glEnable(GL10.GL_CULL_FACE)
    // specify which faces to not draw
    glCullFace(GL10.GL_BACK)
}

Java

// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);

Nếu bạn cố gắng sử dụng tính năng chọn lọc khuôn mặt mà không biết cạnh nào của hình dạng là mặt trước và mặt sau, thì đồ hoạ OpenGL của bạn sẽ hơi mỏng hoặc có thể hoàn toàn không xuất hiện. Vì vậy, hãy luôn xác định toạ độ của hình dạng OpenGL theo thứ tự vẽ ngược chiều kim đồng hồ.

Lưu ý: Bạn có thể thiết lập môi trường OpenGL để coi mặt theo chiều kim đồng hồ là mặt trước, nhưng việc này sẽ yêu cầu nhiều mã hơn và có thể gây nhầm lẫn cho các nhà phát triển OpenGL giàu kinh nghiệm khi bạn nhờ họ trợ giúp. Vì vậy, đừng làm thế.

Phiên bản OpenGL và khả năng tương thích với thiết bị

Thông số kỹ thuật OpenGL ES 1.0 và 1.1 API được hỗ trợ kể từ Android 1.0. Lập trình đồ hoạ bằng API OpenGL ES 1.0/1.1 khác biệt đáng kể so với việc sử dụng phiên bản 2.0 trở lên. OpenGL ES 2.0 được tất cả thiết bị Android bắt đầu từ Android 2.2 (API cấp 8) hỗ trợ và là phiên bản sớm nhất được đề xuất cho các ứng dụng mới đang được phát triển bằng OpenGL ES. OpenGL ES 3.0 được hỗ trợ trên Android 4.3 (API cấp 18) trở lên, trên các thiết bị cung cấp phương thức triển khai API OpenGL ES 3.0. Để biết thông tin về số lượng tương đối các thiết bị chạy Android hỗ trợ một phiên bản OpenGL ES nhất định, hãy xem Trang tổng quan về phiên bản OpenGL ES.

Bạn nên xem xét cẩn thận các yêu cầu về đồ hoạ và chọn phiên bản API phù hợp nhất với ứng dụng của mình. Để biết thêm thông tin, hãy xem bài viết Chọn phiên bản API OpenGL.

API OpenGL ES 3.0 cung cấp các tính năng bổ sung và mang lại hiệu suất tốt hơn so với API 2.0, đồng thời cũng có khả năng tương thích ngược. Điều này có nghĩa là bạn có thể viết ứng dụng nhắm mục tiêu OpenGL ES 2.0 và đưa vào có điều kiện các tính năng đồ hoạ OpenGL ES 3.0 nếu có. Để biết thêm thông tin về việc kiểm tra phạm vi cung cấp của API 3.0, hãy xem bài viết Kiểm tra phiên bản OpenGL ES

Hỗ trợ nén kết cấu

Tính năng nén kết cấu có thể làm tăng đáng kể hiệu suất của ứng dụng OpenGL bằng cách giảm các yêu cầu về bộ nhớ và sử dụng băng thông bộ nhớ hiệu quả hơn. Khung Android hỗ trợ định dạng nén ETC1 dưới dạng tính năng tiêu chuẩn, bao gồm một lớp tiện ích ETC1Util và công cụ nén etc1tool (nằm trong SDK Android tại <sdk>/tools/). Để xem ví dụ về một ứng dụng Android sử dụng tính năng nén kết cấu, hãy xem mã mẫu CompressedTextureActivity trong SDK Android (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

Định dạng ETC1 được tất cả thiết bị Android hỗ trợ OpenGL ES 2.0 trở lên hỗ trợ.

Lưu ý: Định dạng nén hoạ tiết ETC1 không hỗ trợ hoạ tiết có độ trong suốt (kênh alpha). Nếu ứng dụng của bạn đòi hỏi kết cấu trong suốt, bạn nên điều tra các định dạng nén kết cấu khác có sẵn trên thiết bị mục tiêu. Phương thức hiển thị hoạ tiết kênh alpha bằng ETC1 là liên kết 2 đối tượng hoạ tiết ETC1: thứ nhất với dữ liệu màu, thứ hai với dữ liệu kênh alpha, sau đó kết hợp các giá trị từ 2 kết cấu trong chương trình đổ bóng mảnh.

Các định dạng nén hoạ tiết ETC2/EAC được đảm bảo sẽ có sẵn khi sử dụng API OpenGL ES 3.0. Định dạng hoạ tiết này có tỷ lệ nén tuyệt vời với chất lượng hình ảnh cao và định dạng này cũng hỗ trợ độ trong suốt (kênh alpha).

Ngoài các định dạng ETC, thiết bị Android cũng hỗ trợ nhiều tính năng nén kết cấu dựa trên bộ vi mạch GPU và cách triển khai OpenGL. Bạn nên tìm hiểu khả năng hỗ trợ nén kết cấu trên các thiết bị bạn đang nhắm đến để xác định những kiểu nén mà ứng dụng của bạn nên hỗ trợ. Để xác định định dạng hoạ tiết nào được hỗ trợ trên một thiết bị nhất định, bạn phải truy vấn thiết bị đó và xem lại tên tiện ích OpenGL. Tên này xác định những định dạng nén hoạ tiết (và các tính năng OpenGL khác) được thiết bị hỗ trợ. Sau đây là một số định dạng nén kết cấu thường được hỗ trợ:

  • Nén kết cấu có thể mở rộng (Adaptiveable Texture Com tạp) (ASTC) – Định dạng nén kết cấu được thiết kế để thay thế các định dạng trước đó. Linh hoạt hơn so với các định dạng trước đây do hỗ trợ nhiều kích thước khối.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(dải động cao)
  • S3TC (DXTn/DXTC) – Nén kết cấu S3 (S3TC) có một số biến thể định dạng (DXT1 sang DXT5) và ít được phổ biến hơn. Định dạng này hỗ trợ hoạ tiết RGB với kênh alpha 4 bit hoặc alpha 8 bit. Các định dạng này được biểu thị bằng tên tiện ích OpenGL sau:
    • GL_EXT_texture_compression_s3tc
    Một số thiết bị chỉ hỗ trợ biến thể định dạng DXT1. Khả năng hỗ trợ có giới hạn này được thể hiện bằng tên tiện ích OpenGL sau:
    • GL_EXT_texture_compression_dxt1

Các định dạng nén kết cấu sau đây được coi là định dạng cũ và không nên dùng trong các ứng dụng mới:

  • ATITC (ATC) – Tính năng nén hoạ tiết ATI (ATITC hoặc ATC) được cung cấp trên nhiều thiết bị và hỗ trợ nén tốc độ cố định cho hoạ tiết RGB có và không có kênh alpha. Định dạng này có thể được biểu thị bằng một số tên tiện ích OpenGL, ví dụ:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC – Tính năng nén kết cấu PowerVR (PVRTC) được cung cấp trên nhiều loại thiết bị và hỗ trợ hoạ tiết 2 bit và 4 bit trên mỗi pixel có hoặc không có kênh alpha. Định dạng này được biểu thị bằng tên tiện ích OpenGL sau:
    • GL_IMG_texture_compression_pvrtc
  • 3DC – Nén kết cấu 3DC (3DC) là một định dạng ít được cung cấp rộng rãi hơn, hỗ trợ kết cấu RGB với kênh alpha. Định dạng này được biểu thị bằng tên tiện ích OpenGL sau:
    • GL_AMD_compressed_3DC_texture

Cảnh báo: Các định dạng nén kết cấu này không được hỗ trợ trên mọi thiết bị. Khả năng hỗ trợ cho những định dạng này có thể khác nhau tuỳ theo nhà sản xuất và thiết bị. Để biết thông tin về cách xác định các định dạng nén kết cấu trên một thiết bị cụ thể, hãy xem phần tiếp theo.

Lưu ý: Sau khi quyết định định dạng nén kết cấu mà ứng dụng của bạn sẽ hỗ trợ, hãy nhớ khai báo các định dạng đó trong tệp kê khai bằng cách sử dụng <supports-gl-texture> . Việc sử dụng nội dung khai báo này sẽ bật cơ chế lọc theo các dịch vụ bên ngoài, chẳng hạn như Google Play, để ứng dụng của bạn chỉ được cài đặt trên những thiết bị hỗ trợ các định dạng mà ứng dụng yêu cầu. Để biết thông tin chi tiết, hãy xem phần Khai báo tệp kê khai OpenGL.

Xác định tiện ích OpenGL

Các cách triển khai OpenGL còn tuỳ theo thiết bị Android, về những tiện ích mở rộng cho API OpenGL ES được hỗ trợ. Các tiện ích này bao gồm cả các thao tác nén kết cấu, nhưng cũng thường bao gồm các tiện ích khác cho bộ tính năng OpenGL.

Để xác định những định dạng nén kết cấu và các tiện ích OpenGL khác được hỗ trợ trên một thiết bị cụ thể:

  1. Chạy mã sau trên các thiết bị mục tiêu để xác định những định dạng nén kết cấu được hỗ trợ:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

    String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
    

    Cảnh báo: Kết quả của lệnh gọi này khác nhau tuỳ theo mẫu thiết bị! Bạn phải chạy lệnh gọi này trên một số thiết bị mục tiêu để xác định những loại nén thường được hỗ trợ.

  2. Xem xét kết quả của phương thức này để xác định những tiện ích OpenGL nào được hỗ trợ trên thiết bị.

Gói tiện ích Android (AEP)

AEP đảm bảo rằng ứng dụng của bạn hỗ trợ một tập hợp tiện ích OpenGL chuẩn ở trên và ngoài tập hợp cốt lõi được mô tả trong thông số kỹ thuật OpenGL 3.1. Việc đóng gói các tiện ích này cùng nhau sẽ khuyến khích một nhóm chức năng nhất quán trên các thiết bị, đồng thời cho phép các nhà phát triển khai thác tối đa kiểu thiết bị GPU di động mới nhất.

AEP cũng cải thiện khả năng hỗ trợ hình ảnh, vùng đệm lưu trữ của chương trình đổ bóng và bộ đếm nguyên tử trong chương trình đổ bóng mảnh.

Để ứng dụng của bạn có thể sử dụng AEP, tệp kê khai của ứng dụng phải khai báo rằng AEP là bắt buộc. Ngoài ra, phiên bản nền tảng phải hỗ trợ điều này.

Tất cả các tính năng bổ sung được chỉ định trong AEP đều có trong quy cách OpenGL ES 3.2 cơ sở. Nếu ứng dụng của bạn yêu cầu OpenGL ES 3.2, thì bạn không cần đến AEP.

Khai báo yêu cầu về AEP trong tệp kê khai như sau:

<uses-feature android:name="android.hardware.opengles.aep"
              android:required="true" />

Để xác minh rằng phiên bản nền tảng hỗ trợ AEP, hãy sử dụng phương thức hasSystemFeature(String), truyền vào FEATURE_OPENGLES_EXTENSION_PACK dưới dạng đối số. Đoạn mã sau đây cho thấy ví dụ về cách thực hiện:

Kotlin

var deviceSupportsAEP: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)

Java

boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
     (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);

Nếu phương thức này trả về giá trị true, thì AEP được hỗ trợ.

Để biết thêm thông tin về AEP, hãy truy cập trang của AEP tại Sổ đăng ký OpenGL ES của Khronos OpenGL ES.

Kiểm tra phiên bản OpenGL ES

Có một số phiên bản OpenGL ES trên thiết bị Android. Bạn có thể chỉ định phiên bản API tối thiểu mà ứng dụng yêu cầu trong tệp kê khai, nhưng bạn cũng nên tận dụng các tính năng trong một API mới hơn cùng lúc. Ví dụ: API OpenGL ES 3.0 tương thích ngược với phiên bản API 2.0, vì vậy bạn nên viết ứng dụng để ứng dụng sử dụng các tính năng OpenGL ES 3.0, nhưng sẽ quay lại API 2.0 nếu API 3.0 không có sẵn.

Trước khi sử dụng các tính năng OpenGL ES từ một phiên bản cao hơn phiên bản tối thiểu bắt buộc trong tệp kê khai ứng dụng, ứng dụng của bạn nên kiểm tra phiên bản API có trên thiết bị. Bạn có thể làm việc này bằng một trong hai cách:

  1. Hãy thử tạo ngữ cảnh OpenGL ES cấp cao hơn (EGLContext) rồi kiểm tra kết quả.
  2. Tạo bối cảnh OpenGL ES được hỗ trợ tối thiểu và kiểm tra giá trị phiên bản.

Mã ví dụ sau đây minh hoạ cách kiểm tra phiên bản OpenGL ES có sẵn bằng cách tạo một EGLContext và kiểm tra kết quả. Ví dụ này cho biết cách kiểm tra phiên bản OpenGL ES 3.0:

Kotlin

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
private class ContextFactory : GLSurfaceView.EGLContextFactory {

    override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext {

        Log.w(TAG, "creating OpenGL ES $glVersion context")
        return egl.eglCreateContext(
                display,
                eglConfig,
                EGL10.EGL_NO_CONTEXT,
                intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
        ) // returns null if 3.0 is not supported
    }
}

Java

private static double glVersion = 3.0;

private static class ContextFactory implements GLSurfaceView.EGLContextFactory {

  private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

  public EGLContext createContext(
          EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {

      Log.w(TAG, "creating OpenGL ES " + glVersion + " context");
      int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
              EGL10.EGL_NONE };
      // attempt to create a OpenGL ES 3.0 context
      EGLContext context = egl.eglCreateContext(
              display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
      return context; // returns null if 3.0 is not supported;
  }
}

Nếu phương thức createContext() hiển thị ở trên trả về giá trị rỗng, thì mã của bạn sẽ tạo ngữ cảnh OpenGL ES 2.0 và quay lại chỉ sử dụng API đó.

Mã ví dụ sau đây minh hoạ cách kiểm tra phiên bản OpenGL ES bằng cách tạo một ngữ cảnh tối thiểu được hỗ trợ trước, sau đó kiểm tra chuỗi phiên bản:

Kotlin

// Create a minimum supported OpenGL ES context, then check:
gl.glGetString(GL10.GL_VERSION).also {
    Log.w(TAG, "Version: $it")
}
 // The version format is displayed as: "OpenGL ES <major>.<minor>"
 // followed by optional content provided by the implementation.

Java

// Create a minimum supported OpenGL ES context, then check:
String version = gl.glGetString(GL10.GL_VERSION);
Log.w(TAG, "Version: " + version );
// The version format is displayed as: "OpenGL ES <major>.<minor>"
// followed by optional content provided by the implementation.

Với phương pháp này, nếu phát hiện thấy thiết bị hỗ trợ phiên bản API cấp cao hơn, thì bạn phải huỷ bối cảnh OpenGL ES tối thiểu và tạo một bối cảnh mới có phiên bản API cao hơn.

Chọn phiên bản API OpenGL

OpenGL ES phiên bản 2.0 và phiên bản 3.0 đều cung cấp giao diện đồ hoạ hiệu suất cao để tạo trò chơi 3D, hình ảnh trực quan và giao diện người dùng. Việc lập trình đồ hoạ cho OpenGL ES 2.0 và 3.0 về cơ bản là tương tự nhau, với phiên bản 3.0 đại diện cho một tập mẹ của API 2.0 với các tính năng bổ sung. Việc lập trình cho API OpenGL ES 1.0/1.1 so với OpenGL ES 2.0 và 3.0 có sự khác biệt đáng kể và không nên dùng cho các ứng dụng mới. Nhà phát triển nên xem xét kỹ các yếu tố sau đây trước khi bắt đầu phát triển bằng các API này:

  • Khả năng tương thích với thiết bị – Nhà phát triển nên cân nhắc các loại thiết bị, phiên bản Android và phiên bản OpenGL ES được cung cấp cho khách hàng của mình. Để biết thêm thông tin về khả năng tương thích OpenGL trên các thiết bị, hãy xem phần Các phiên bản OpenGL và khả năng tương thích với thiết bị.
  • Hỗ trợ hoạ tiết – API OpenGL ES 3.0 có khả năng hỗ trợ tốt nhất cho việc nén hoạ tiết vì API này đảm bảo khả năng sử dụng định dạng nén ETC2, hỗ trợ độ trong suốt. Việc triển khai API 2.0 bao gồm cả việc hỗ trợ ETC1, tuy nhiên định dạng kết cấu này không hỗ trợ độ trong suốt. Để triển khai độ trong suốt bằng hoạ tiết được nén, bạn phải sử dụng hai hoạ tiết ETC1 (phân tách giữa màu và alpha) hoặc cung cấp tài nguyên ở các định dạng nén khác được thiết bị mà bạn nhắm đến hỗ trợ. Để biết thêm thông tin, hãy xem bài viết Hỗ trợ nén kết cấu.

Mặc dù khả năng tương thích và khả năng hỗ trợ kết cấu có thể ảnh hưởng đến quyết định của bạn, nhưng bạn nên chọn phiên bản API OpenGL dựa trên những gì bạn cho là mang lại trải nghiệm tốt nhất cho người dùng.