openGL ES学习教程 ---基本图像绘制

openGL ES学习教程(一)

android中哪个地方用到了OpenGL ES?

Android中你可以在JNI层或者java层使用OpenGL ES,JNI需要自己去调用OpenGL的库方法;java层你只需要使用GLSurfaceView组件,你就可以使用OpenGL的一些方法,来进行绘图工作了,但是这里OpenGL与GLSurfaceView是绑定在一块的,同生共死。

插入一个疑问,Android中有了view为什么有设计出surfaceView呢?

如何使用OpenGL ES?

先使用java层的openGL ES

因为openGL是一个native的库,所以很多数据都是需要放到jni层去处理,在后面的很多代码细节都可以发现

开发步骤

  1. 布局文件声明GLSurfaceView
  2. 为openGL设置版本号,openGL ES现在又1-2-3这三个版本,我们这里使用2
  3. 设置渲染器,渲染器主要控制如何去渲染我们的图像画面
   	    glSurfaceView = findViewById(R.id.gl_surface);
        glSurfaceView.setEGLContextClientVersion(2);
        glSurfaceView.setRenderer(new GLRender(this));
        //RENDERMODE_WHEN_DIRTY 触发式手动刷新 RENDERMODE_CONTINUOUSLY 持续刷新 固定周期刷新
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
渲染Render

这里我们需要知道openGL是如何来进行画画的,OpenGL只能画三种图像:点、线和三角形,任何复杂的图像都可以由这三种图像构成;openGL是如何画出这三种图像的呢?

通过坐标点和着色器,openGL的坐标系是三维坐标系,常规的数学坐标系,屏幕中心是原点,坐标系 如下图:
在这里插入图片描述

着色器shader分为顶点着色器和片着色器,这两个好比就是画笔和填充桶的关系

综上,我们开发需要的东西:

  1. 图形的坐标
  2. 拿到顶点着色器和片着色器
  3. 调用OpenGL库函数进行作画
坐标

需要注意的openGL要的是ByteFloat类型而不是基础的float类型,大小端字节序问题

private float[] vertexData = new float[]{
            //三角形
            -0.5f,      0,  
            0.5f,   0,  
            0,      1,  
            //歪三角形
            -0.5f,      0,  
            0.5f,   0,  
            1, -1, 
            //线
            -0.5f , 0f, 
            0.5f , 0f, 
            //点
            0, 0.5f
    }; 
	private void init(){
		//千万不要弄成allocate方法了,这个方法产生的内存在java堆上,openGL拿不到的
        floatBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                                .order(ByteOrder.nativeOrder())
                                .asFloatBuffer();
        floatBuffer.put(vertexData);
        floatBuffer.position(0);
    }
着色器

type对应GLES20.GL_VERTEX_SHADER、GLES20.GL_FRAGMENT_SHADER;
拿到shader还需要链接OpenGL代码程序,才能使用其功能

/**
     * 获取编译的sourceCode和shader
     * @param type
     * @param sourceCode
     * @return
     */
    public static int getCompileShader(int type, String sourceCode){
        //创建着色器
        int glShaderId = GLES20.glCreateShader(type);

        if(glShaderId == 0){
            LogHelper.log_i("create shader error!");
            return 0;
        }

        /**
         * 加入我们定义opengl的源码,在raw文件加下
         * 编译源码,为什么要这么做?
         * openGL的所有功能都是JNI层实现的,java层最终都是在jvm中运行的,jni是拿不到数据
         * 所以我们编写的源码,经过编译在jni产生openGL想要的源码
         */
        GLES20.glShaderSource(glShaderId, sourceCode);
        GLES20.glCompileShader(glShaderId);
        int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(glShaderId, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
        if(compileStatus[0] == 0){
            LogHelper.log_i("compile source code error!");
            return 0;
        }
        return glShaderId;
    }

	/**
     * 编译了源码只是我们要的功能,这些功能需要使用OpenGL的东东,所以需要链接openGL program
     * @param vertexShader
     * @param fragShader
     * @return
     */
    public static int linkOpenGLProgram(int vertexShader, int fragShader){
        int glProgram = GLES20.glCreateProgram();
        if(glProgram == 0){
            LogHelper.log_i("create openGL program error!");
            return 0;
        }

        GLES20.glAttachShader(glProgram, vertexShader);
        GLES20.glAttachShader(glProgram, fragShader);
        GLES20.glLinkProgram(glProgram);

        int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(glProgram,GLES20.GL_LINK_STATUS, linkStatus, 0);
        if(linkStatus[0] == 0){
            LogHelper.log_i("link openGL source code error!");
            return 0;
        }
        return glProgram;
    }
开始作画

需要放到Render的onDrawFrame回调方法中去

glUniform4f(fragGLColor, 1.0f, 1.0f, 1.0f, 1.0f):CPU向GPU传递的4个颜色值RGBA,fragGLColor是片元着色器内部的颜色变量

glDrawArrays画画的图形及坐标数组及偏移

		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUniform4f(fragGLColor, 1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);         //绘制三角形  三角形坐标是我们定义数组的0~6位置
        //绘制线
        GLES20.glUniform4f(fragGLColor, 1.0f, 0.0f, 0.0f, 1.0f);
        GLES20.glDrawArrays(GLES20.GL_LINES, 6, 2);
        //绘制点 glUniform4f uniform是不可变类型变量  4f 参数有4个浮点型,该函数主要用于CPU向GPU发送4个颜色值RGBA
        GLES20.glUniform4f(fragGLColor, 0f, 0f, 0f, 0f);
        GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);
最终的效果图

在这里插入图片描述

源码库链接

组合三角形画法

常规的画一个独立的三角形使用GLES20.GL_TRIANGLE标志位进行画画,这种作画需要你指定三角形的3个点坐标,但是一些复杂图形由三角形组合而成的,没有必要一一去列举,可以服用很多坐标,下面两种就是对点和边的服用

Triangle Fan 中心点复用

这种方式,第一个点位中心复用点,其他的数据都会复用这个点,看一组数据,详细的解释看代码注释

			/**
             * Triangle Fan三角形的另一种方式,请看下面前两列数据,
             * 第一列为中心点,后面第二行与第三行和第一行形成三角形;
             * 第三行、第四行与第一行又形成一个三角形 ,依次类推,规律有点类似为123、134、145等
             * 后三列数据是颜色值RGB
            */
			0,      0,     
            -0.5f, -0.5f,  
            0.5f,  -0.5f,  
            0.5f,  0.5f,   
            -0.5f, 0.5f
Triangle strip边复用

直接看数据更容易理解:

/**
             * triangle strip是另一种三角形组成,图形画法如下
             * 123行构成三角形
             * 23行的点构成边,与第4行点形成三角形;也就是
             * 123三角、234三角、345三角
            */
            -0.25f,      0,     
            -0.5f, 0.25f,
            -0.5f, -0.25f,
            -0.75f, 0
添加一个知识点,直接在坐标系中标明颜色值

省去调用FragmentShader的颜色变量再近些赋值的操作,直接在读取的Position位置坐标时,指定颜色值范围,openGL内部直接读取颜色值再自行赋值给FragmentShader颜色

  1. 需要在顶点着色器中定义好颜色变量,该颜色变量需要和片元着色器定义的颜色变量相同
precision mediump float;

varying vec4 v_Color;

void main() {
    gl_FragColor = v_Color;
}
===========================文件分割线=============================
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;

void main(){
    gl_Position = a_Position;
    gl_PointSize = 20.f;    //指定点的大小  不然划出来看不见

    v_Color = a_Color;
}
  1. 导入数据时需要指明哪些是坐标位置,哪些是颜色值
			private final int POS_LEN = 2;
    		private final int COLOR_LEN = 3;
    		private final int STRIDE = (POS_LEN+COLOR_LEN) * 4;
 			private float[] vertexData = new float[]{
            /**
             * Triangle Fan 后面3列是颜色值
            */
            0,      0,     1f, 1f, 1f,
            -0.5f, -0.5f,  0.7f, 0.7f, 0.7f,
            0.5f,  -0.5f,  0.7f, 0.7f, 0.7f,
            0.5f,  0.5f,   0.7f, 0.7f, 0.7f,
            -0.5f, 0.5f,   0.7f, 0.7f, 0.7f,

            /**
             * triangle strip
            */
            -0.25f,      0,     1f, 1f, 1f,
            -0.5f, 0.25f,0.7f, 0.7f, 0.7f,
            -0.5f, -0.25f,0.7f, 0.7f, 0.7f,
            -0.75f, 0, 0.7f, 0.7f, 0.7f
    };

		glPos = GLES20.glGetAttribLocation(glProgram, "a_Position");
        glColor = GLES20.glGetAttribLocation(glProgram, "a_Color");
        //指明数据的分布样式 POS_LEN=2 COLOR_LEN=3
        GLES20.glVertexAttribPointer(glPos, POS_LEN, GLES20.GL_FLOAT, false, STRIDE, floatBuffer);
        GLES20.glEnableVertexAttribArray(glPos);
        GLES20.glVertexAttribPointer(glColor, COLOR_LEN, GLES20.GL_FLOAT, false, STRIDE, floatBuffer);
        GLES20.glEnableVertexAttribArray(glColor);
  1. 画图
@Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 5);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 5, 4);
    }

颜色值的原理,实际上是从数据中读到a_color,a_Color赋值给v_Color,c_Color在赋值给gl_FragColor;

效果图

在这里插入图片描述
项目地址

glsl语法详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

帅气好男人_Jack

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

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

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

打赏作者

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

抵扣说明:

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

余额充值