返回

开启OpenGL ES探索之旅——EGL环境搭建与三角形纹理渲染初探

Android

在上一篇探索之旅中,我们成功地创建了一个简单的OpenGL ES应用程序,并向你介绍了基本概念。现在,让我们更进一步,深入了解OpenGL ES的图形渲染机制。

定义渲染器基类

为了让渲染过程更加灵活和可重用,我们将创建一个渲染器基类RendererBase,它将包含所有与渲染相关的通用方法。这样,在后续的渲染任务中,我们只需继承该基类即可。

public abstract class RendererBase implements GLSurfaceView.Renderer {

    // 着色器程序
    private int mProgram;

    // 顶点坐标
    private float[] mVertices = {...};

    // 纹理坐标
    private float[] mTexCoords = {...};

    // 纹理ID
    private int mTextureId;

    // 顶点着色器
    private String mVertexShader = {...};

    // 片段着色器
    private String mFragmentShader = {...};

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 初始化着色器程序
        mProgram = createProgram(mVertexShader, mFragmentShader);

        // 加载纹理
        mTextureId = loadTexture(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.triangle));

        // 启用顶点属性数组
        glEnableVertexAttribArray(POSITION_ATTRIBUTE);
        glEnableVertexAttribArray(TEXCOORD_ATTRIBUTE);

        // 设置顶点属性指针
        glVertexAttribPointer(POSITION_ATTRIBUTE, COORDS_PER_VERTEX, GL_FLOAT, false, 0, mVertices);
        glVertexAttribPointer(TEXCOORD_ATTRIBUTE, TEXCOORDS_PER_VERTEX, GL_FLOAT, false, 0, mTexCoords);

        // 启用纹理单元
        glEnable(GL_TEXTURE_2D);

        // 绑定纹理到纹理单元
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mTextureId);

        // 设置纹理环绕方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        // 设置纹理过滤方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 设置视口
        glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // 清空颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);

        // 使用着色器程序
        glUseProgram(mProgram);

        // 绘制三角形
        glDrawArrays(GL_TRIANGLES, 0, mVertices.length / COORDS_PER_VERTEX);
    }

    // 创建着色器程序
    private int createProgram(String vertexShader, String fragmentShader) {
        // 编译顶点着色器
        int vertexShaderId = loadShader(GL_VERTEX_SHADER, vertexShader);

        // 编译片段着色器
        int fragmentShaderId = loadShader(GL_FRAGMENT_SHADER, fragmentShader);

        // 创建着色器程序
        int program = glCreateProgram();

        // 将顶点着色器和片段着色器附加到程序
        glAttachShader(program, vertexShaderId);
        glAttachShader(program, fragmentShaderId);

        // 链接程序
        glLinkProgram(program);

        // 检查程序是否链接成功
        int[] linkStatus = new int[1];
        glGetProgramiv(program, GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] == GL_FALSE) {
            throw new RuntimeException("Could not link program: " + glGetProgramInfoLog(program));
        }

        // 返回程序ID
        return program;
    }

    // 加载着色器
    private int loadShader(int type, String shaderCode) {
        // 创建着色器对象
        int shader = glCreateShader(type);

        // 设置着色器源代码
        glShaderSource(shader, shaderCode);

        // 编译着色器
        glCompileShader(shader);

        // 检查着色器是否编译成功
        int[] compileStatus = new int[1];
        glGetShaderiv(shader, GL_COMPILE_STATUS, compileStatus, 0);
        if (compileStatus[0] == GL_FALSE) {
            throw new RuntimeException("Could not compile shader: " + glGetShaderInfoLog(shader));
        }

        // 返回着色器对象
        return shader;
    }

    // 加载纹理
    private int loadTexture(Bitmap bitmap) {
        // 创建纹理对象
        int[] textureIds = new int[1];
        glGenTextures(1, textureIds, 0);
        int textureId = textureIds[0];

        // 绑定纹理到纹理单元
        glBindTexture(GL_TEXTURE_2D, textureId);

        // 设置纹理参数
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        // 上传纹理数据
        BitmapBuffer bitmapBuffer = new BitmapBuffer(bitmap);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmapBuffer);

        // 解绑纹理
        glBindTexture(GL_TEXTURE_2D, 0);

        // 返回纹理ID
        return textureId;
    }
}

使用Android封装好的EGL环境(GLSurfaceView)来渲染三角形纹理

在Android中,我们可以使用GLSurfaceView来方便地创建和管理一个OpenGL ES渲染环境。GLSurfaceView是一个继承自SurfaceView的视图控件,它提供了对OpenGL ES的封装,让我们可以轻松地进行渲染。

首先,在布局文件中添加GLSurfaceView:

<android.opengl.GLSurfaceView
    android:id="@+id/glSurfaceView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

然后,在Activity中初始化GLSurfaceView:

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

    setContentView(R.layout.activity_main);

    GLSurfaceView glSurfaceView = (GLSurfaceView) findViewById(R.id.glSurfaceView);
    glSurfaceView.setEGLContextClientVersion(2);
    glSurfaceView.setRenderer(new MyRenderer());
}

在上面的代码中,我们首先设置了GLSurfaceView的EGL版本为2.0,然后设置了渲染器为MyRenderer。MyRenderer继承了我们定义的渲染器基类RendererBase,并实现了渲染相关的回调方法。

这样,我们就可以通过GLSurfaceView来渲染三角形纹理了。当GLSurfaceView准备好渲染时,它会调用onSurfaceCreated()方法,我们可以在该方法中初始化着色器程序、加载纹理等。当GLSurfaceView的大小发生变化时,它会调用onSurfaceChanged()方法,我们可以在该方法中设置视口。当GLSurfaceView需要重新渲染时,它会调用onDrawFrame()方法,我们可以在该方法中绘制三角形。

至此,我们就完成了OpenGL ES渲染三角形纹理的示例。通过这篇博客,你已经掌握了OpenGL ES的基本渲染流程和EGL环境的使用方法。在接下来的探索之旅中,我们将继续深入研究OpenGL ES,学习更多的图形渲染技术。

文章概要

  • 定义了一个渲染器基类RendererBase,方便后续渲染任务的重用。

  • 使用Android封装好的EGL环境(GLSurfaceView)来渲染三角形纹理。

  • 介绍了GLSurfaceView的基本用法,包括设置EGL版本、设置渲染器等。

  • OpenGL ES

  • 图形渲染