【OpenGL ES】绘制三角形

1 前言

1.1 设置顶点属性

        顶点有位置、颜色等属性,可以通过 glVertexAttribPointer 设置顶点的属性。

void glVertexAttribPointer(
    int index, //顶点属性的索引值,如:位置属性索引为0,颜色属性索引为1
    int size, //每个顶点在待设置属性下的数组大小,如:位置用三维坐标表示,则size为3;颜色用argb表示,则size为4
    int type, //顶点属性的数据类型,如:GLES30.GL_FLOAT
    boolean normalized, //当被访问时,固定点数据值是否应该被归一化
    int stride, //连续顶点属性之间的偏移量,0表示紧密排列在一起的
    Buffer pointer //顶点属性序列
)

1.2 绘制图元

        OpenGL ES 绘制图形主要有 glDrawArrays 和 glDrawElements 2个接口。

        1)glDrawArrays

void glDrawArrays(
    int mode, //渲染的图元类型
    int first, //渲染的起始索引
    int count //渲染的顶点数
)

         图元类型(mode)主要有:

  • GL_POINTS:绘制顶点
  • GL_LINES:绘制线段,如顶点序列:1234,绘制线段:12、34
  • GL_LINE_STRIP:绘制线带,如顶点序列:1234,绘制线带:12、23、34
  • GL_LINE_LOOP:绘制线圈,如顶点序列:1234,绘制线带:12、23、34、41
  • GL_TRIANGLES:绘制三角形:如顶点序列:123456,绘制三角形:123、456
  • GL_TRIANGLE_STRIP:绘制三角形带:如顶点序列:12345,绘制三角形:123、234、345
  • GL_TRIANGLE_FAN:绘制三角形扇:如顶点序列:12345,绘制三角形:123、134、145

        2)glDrawElements

void glDrawElements(
    int mode, //渲染的图元类型
    int count, //渲染的顶点数
    int type, //渲染的顶点序列的数据类型
    Buffer indices //渲染的顶点序列
)

        mode 同 glDrawArrays;indices 必须是 Buffer 类型,如:ByteBuffer;type 为 indices 对应的 OpenGL 的数据类型,如:GLES30.GL_UNSIGNED_BYTE。

        本文将以绘制三角形的案例介绍图元的绘制,项目目录如下:

2 案例

        MainActivity.java

package com.zhyan8.triangle;

import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private GLSurfaceView mGlSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mGlSurfaceView = new MyGLSurfaceView(this);
        setContentView(mGlSurfaceView);
        mGlSurfaceView.setRenderer(new MyRender(this));
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGlSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGlSurfaceView.onPause();
    }
}

        MyGLSurfaceView.java

package com.zhyan8.triangle;

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

public class MyGLSurfaceView extends GLSurfaceView {
    public MyGLSurfaceView(Context context) {
        super(context);
        setEGLContextClientVersion(3);
    }

    public MyGLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setEGLContextClientVersion(3);
    }
}

        MyRender.java

package com.zhyan8.triangle;

import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MyRender implements GLSurfaceView.Renderer {
    private FloatBuffer vertexBuffer;
    private GLUtils mGLUtils;

    public MyRender(Context context) {
        mGLUtils = new GLUtils(context);
        getFloatBuffer();
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
        //设置背景颜色
        GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
        //编译着色器
        final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
        final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
        //链接程序片段
        int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
        GLES30.glUseProgram(programId);
    }

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

    @Override
    public void onDrawFrame(GL10 gl) {
        //将颜色缓冲区设置为预设的颜色
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
        GLES30.glLineWidth(5);
        //启用顶点的数组句柄
        GLES30.glEnableVertexAttribArray(0);
        //准备坐标数据
        GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
//        GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3); //绘制三角形的三个顶点
//        GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 3); //绘制三角形的三条边
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3); //绘制三角形的内部
        //禁止顶点数组句柄
        GLES30.glDisableVertexAttribArray(0);
    }

    private void getFloatBuffer() {
        float[] vertex = new float[] {
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
        };
        vertexBuffer = mGLUtils.getFloatBuffer(vertex);
    }
}

        GLUtils.java

package com.zhyan8.triangle;

import android.content.Context;
import android.opengl.GLES30;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class GLUtils {
    private Context mContext;

    public GLUtils(Context context) {
        mContext = context;
    }

    public FloatBuffer getFloatBuffer(float[] floatArr) {
        FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer();
        fb.put(floatArr);
        fb.position(0);
        return fb;
    }

    //通过代码片段编译着色器
    public int compileShader(int type, String shaderCode){
        int shader = GLES30.glCreateShader(type);
        GLES30.glShaderSource(shader, shaderCode);
        GLES30.glCompileShader(shader);
        return shader;
    }

    //通过外部资源编译着色器
    public int compileShader(int type, int shaderId){
        String shaderCode = readShaderFromResource(shaderId);
        return compileShader(type, shaderCode);
    }

    //链接到着色器
    public int linkProgram(int vertexShaderId, int fragmentShaderId) {
        final int programId = GLES30.glCreateProgram();
        //将顶点着色器加入到程序
        GLES30.glAttachShader(programId, vertexShaderId);
        //将片元着色器加入到程序
        GLES30.glAttachShader(programId, fragmentShaderId);
        //链接着色器程序
        GLES30.glLinkProgram(programId);
        return programId;
    }

    //从shader文件读出字符串
    private String readShaderFromResource(int shaderId) {
        InputStream is = mContext.getResources().openRawResource(shaderId);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line;
        StringBuilder sb = new StringBuilder();
        try {
            while ((line = br.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
}

        vertex_shader.glsl

#version 300 es
layout (location = 0) in vec4 vPosition;
void main() {
     gl_Position  = vPosition;
     gl_PointSize = 20.0; //顶点大小(GL_POINTS模式下才会生效)
}

        顶点着色器的作用:进行矩阵变换位置、根据光照公式计算顶点颜⾊⽣成 / 变换纹理坐标,并且把位置和纹理坐标发送到片元着色器。

        顶点着色器中,如果没有指定默认精度,则 int 和 float 的默认精度都为 highp。

        fragment_shader.glsl

#version 300 es
precision mediump float; //声明float型变量的精度为mediump
out vec4 fragColor;
void main() {
     fragColor = vec4(0.2, 1.0, 1.0, 1.0); //顶点、边线、内部填充颜色
}

        片元着色器的作用:处理经光栅化阶段生成的每个片元,计算每个像素的颜色和透明度

        在片元着色器中,浮点值没有默认的精度值,每个着色器必须声明一个默认的 float 精度。

        运行结果:

        1)GL_POINTS 模式

        2)GL_LINE_LOOP 模式

          3)GL_TRIANGLES 模式

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用NDK和OpenGL ES 3.0来绘制一个三角形可以分为以下几个步骤: 1. 首先,创建一个安卓项目,并配置NDK环境。 2. 在项目的jni目录下,创建一个C/C++源文件triangle.c。 3. 在triangle.c文件中,引入相关的头文件,包括<jni.h>和<GLES3/gl3.h>。 4. 在triangle.c文件中,实现一个JNI函数,用于绘制三角形。函数的参数为Surface对象。 5. 在JNI函数中,通过EGLGLES初始化OpenGL环境,并创建一个EGLSurface用于后续的绘制操作。 6. 在JNI函数中,创建一个顶点数组和顶点缓冲,并将顶点数据存入顶点缓冲。 7. 在JNI函数中,编写着色器代码,包括顶点着色器和片段着色器,并编译和链接它们。 8. 在JNI函数中,通过glClearColor()函数设置清空屏幕时的颜色。 9. 在JNI函数中,通过glClear()函数清空屏幕,并启用深度测试。 10. 在JNI函数中,通过glViewport()函数设置视口大小。 11. 在JNI函数中,通过glUseProgram()函数使用着色器程序。 12. 在JNI函数中,通过glVertexAttribPointer()函数设置顶点数据的属性,并启用顶点属性。 13. 在JNI函数中,通过glDrawArrays()函数绘制三角形。 14. 在JNI函数中,通过eglSwapBuffers()函数交换绘制的缓冲区。 15. 在JNI函数中,清理OpenGL环境,并释放资源。 16. 在Java层的MainActivity中,通过JNI调用C/C++函数进行绘制。 以上是绘制一个三角形的大致步骤。具体的细节和代码实现可以参考相关的OpenGL ES 3.0和NDK的文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little_fat_sheep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值