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

Để vẽ đồ hoạ bằng OpenGL ES trong ứng dụng Android, bạn phải tạo một vùng chứa thành phần hiển thị cho các đồ hoạ đó. Một trong những cách đơn giản hơn để thực hiện việc này là triển khai cả GLSurfaceViewGLSurfaceView.Renderer. GLSurfaceView là vùng chứa khung hiển thị cho các đồ hoạ được vẽ bằng OpenGL và GLSurfaceView.Renderer kiểm soát nội dung được vẽ trong khung hiển thị đó. Để biết thêm thông tin về các lớp này, hãy xem hướng dẫn cho nhà phát triển về OpenGL ES.

GLSurfaceView chỉ là một cách để kết hợp đồ hoạ OpenGL ES vào ứng dụng. Đây là lựa chọn hợp lý đối với chế độ xem đồ hoạ toàn màn hình hoặc gần toàn màn hình. Các nhà phát triển muốn kết hợp đồ hoạ OpenGL ES trong một phần nhỏ bố cục của họ nên xem TextureView. Đối với các nhà phát triển thực tế, bạn cũng có thể tạo khung hiển thị OpenGL ES bằng SurfaceView, nhưng việc này đòi hỏi bạn phải viết thêm nhiều mã.

Bài học này giải thích cách hoàn tất việc triển khai tối thiểu GLSurfaceViewGLSurfaceView.Renderer trong một hoạt động đơn giản của ứng dụng.

Khai báo việc sử dụng OpenGL ES trong tệp kê khai

Để ứng dụng của bạn dùng API OpenGL ES 2.0, bạn phải thêm nội dung khai báo sau vào tệp kê khai:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

Nếu ứng dụng dùng tính năng nén kết cấu thì bạn cũng phải khai báo những định dạng nén mà ứng dụng hỗ trợ để chỉ được cài đặt trên các thiết bị tương thích.

<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-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, hãy xem hướng dẫn cho nhà phát triển OpenGL.

Tạo hoạt động cho đồ hoạ OpenGL ES

Ứng dụng Android sử dụng OpenGL ES có các hoạt động giống như mọi ứng dụng khác có giao diện người dùng. Điểm khác biệt chính so với các ứng dụng khác là nội dung bạn đưa vào bố cục cho hoạt động của mình. Mặc dù trong nhiều ứng dụng, bạn có thể sử dụng TextView, ButtonListView, nhưng trong một ứng dụng sử dụng OpenGL ES, bạn cũng có thể thêm GLSurfaceView.

Mã ví dụ sau đây cho thấy cách triển khai tối giản của một hoạt động sử dụng GLSurfaceView làm khung hiển thị chính:

Kotlin

class OpenGLES20Activity : Activity() {

    private lateinit var gLView: GLSurfaceView

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = MyGLSurfaceView(this)
        setContentView(gLView)
    }
}

Java

public class OpenGLES20Activity extends Activity {

    private GLSurfaceView gLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = new MyGLSurfaceView(this);
        setContentView(gLView);
    }
}

Lưu ý: OpenGL ES 2.0 yêu cầu Android 2.2 (API cấp 8) trở lên. Vì vậy, hãy đảm bảo dự án Android của bạn nhắm đến API đó trở lên.

Tạo đối tượng GLSurfaceView

GLSurfaceView là một khung hiển thị chuyên biệt, cho phép bạn vẽ đồ hoạ OpenGL ES. Bản thân nó không làm gì nhiều. Việc vẽ thực tế của các đối tượng được kiểm soát trong GLSurfaceView.Renderer mà bạn đặt trên khung hiển thị này. Trên thực tế, mã cho đối tượng này rất mỏng, bạn có thể muốn bỏ qua việc mở rộng đối tượng và chỉ tạo một thực thể GLSurfaceView chưa sửa đổi, nhưng đừng làm như vậy. Bạn cần mở rộng lớp này để ghi lại các sự kiện chạm. Như trình bày trong bài học Phản hồi sự kiện chạm.

Mã thiết yếu cho GLSurfaceView là ở mức tối thiểu. Vì vậy, để triển khai nhanh, bạn chỉ cần tạo một lớp bên trong hoạt động sử dụng mã đó:

Kotlin

import android.content.Context
import android.opengl.GLSurfaceView

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {

    private val renderer: MyGLRenderer

    init {

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2)

        renderer = MyGLRenderer()

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer)
    }
}

Java

import android.content.Context;
import android.opengl.GLSurfaceView;

class MyGLSurfaceView extends GLSurfaceView {

    private final MyGLRenderer renderer;

    public MyGLSurfaceView(Context context){
        super(context);

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2);

        renderer = new MyGLRenderer();

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer);
    }
}

Một tính năng bổ sung (không bắt buộc) khác cho quá trình triển khai GLSurfaceView là đặt chế độ kết xuất để chỉ vẽ khung hiển thị khi có thay đổi đối với dữ liệu vẽ bằng cách sử dụng chế độ cài đặt GLSurfaceView.RENDERMODE_WHEN_DIRTY:

Kotlin

// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY

Java

// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

Chế độ cài đặt này ngăn việc vẽ lại khung GLSurfaceView cho đến khi bạn gọi requestRender(), điều này hiệu quả hơn đối với ứng dụng mẫu này.

Tạo lớp trình kết xuất

Việc triển khai lớp GLSurfaceView.Renderer hoặc trình kết xuất trong một ứng dụng sử dụng OpenGL ES là lúc mọi thứ bắt đầu trở nên thú vị. Lớp này kiểm soát nội dung được vẽ trên GLSurfaceView liên kết với nội dung đó. Có 3 phương thức trong trình kết xuất được hệ thống Android gọi để tìm ra nội dung và cách vẽ trên GLSurfaceView:

  • onSurfaceCreated() – Được gọi một lần để thiết lập môi trường OpenGL ES của khung hiển thị.
  • onDrawFrame() – Được gọi cho mỗi lần vẽ lại khung hiển thị.
  • onSurfaceChanged() – Được gọi nếu hình dạng của khung hiển thị thay đổi, chẳng hạn như khi hướng màn hình của thiết bị thay đổi.

Dưới đây là cách triển khai rất cơ bản của trình kết xuất OpenGL ES, không làm gì khác ngoài việc vẽ nền đen trong GLSurfaceView:

Kotlin

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

import android.opengl.GLES20
import android.opengl.GLSurfaceView

class MyGLRenderer : GLSurfaceView.Renderer {

    override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
    }

    override fun onDrawFrame(unused: GL10) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
    }

    override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }
}

Java

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

import android.opengl.GLES20;
import android.opengl.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);
    }
}

Vậy là xong! Các ví dụ về mã ở trên tạo một ứng dụng Android đơn giản hiển thị màn hình đen bằng cách sử dụng OpenGL. Mặc dù mã này không làm được bất cứ việc gì thú vị, nhưng bằng cách tạo các lớp này, bạn đã đặt nền tảng để bắt đầu vẽ các thành phần đồ hoạ bằng OpenGL.

Lưu ý: Có thể bạn sẽ thắc mắc tại sao các phương thức này lại có tham số GL10 khi sử dụng các API OpengGL ES 2.0. Các chữ ký phương thức này chỉ được dùng lại cho các API 2.0 để giữ cho mã khung Android đơn giản hơn.

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