OpenGLES坐标、纹理、FBO的一些情况梳理

由于本人懒的绘图,尽可能的用语言进行描述。

1、什么是OpenGL ES?和 OpenGL 是什么关系?

OpenGL ESOpenGL三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计的,去除了许多不必要和性能较低的API接口。这里也提下EGLEGL 是链接OpenGL 与 设备窗口的 管理器,属于跨平台的设计。

2、坐标

在绘图的时候,总会有纹理渲染问题,诸如偏移、倒转以及镜像等等,这里是因为对于各种坐标系还不太了解的原因,接下来梳理下可能用到的各种坐标系。
1、Android view坐标系
	竖屏状态下,坐标原点在左上角,x轴 由左上角点 向右 延申,y轴 由左上角点 向下 延申。
	一般textureCoords就是按照此种方式进行描述,如左上角(0, 0)、右上角(1, 0)、左下角(0, 1)、右下角(1, 1)

2、OpenGL世界坐标系
	坐标原点在屏幕中心,x轴为水平方向,y轴为竖直方向,z轴穿过坐标原点向外为正方向,满足右手法则。
	这也是我们绘图要打交道最多的一个坐标系,一般的vertexCoords就是按照此种坐标系描述,如左上角(-1, 1)、右上角(1, 1)、左下角(-1, -1)、右下角(1, -1)

3、立体坐标系
	此种坐标系在OpenGL中 3D立体绘制 用的较多,数学模型中坐标系为:在2d平面上,水平方向为x轴,y轴垂直于x轴,垂足为坐标原点,z轴穿过坐标原点向上,延伸成为 3D 坐标系。
	在立体几何的绘制过程中,由于 OpenGL 的世界坐标系 与 数学模型中的 立体几何坐标系是存在差异的,所以绘制的时候要多注意,该旋转的旋转。

3、旋转的几种情况

既然上文提到了旋转,这里也简单说下常用的旋转:
1、通过GLSL 在着色器中进行上下翻转,如下:
	"#extension GL_OES_EGL_image_external : require"
	"precision mediump float;" +
	"varying vec2 vCoordinate;" +
	"uniform samplerExternalOES uTexture;" +
	"void main() {" +
	"  gl_FragColor = texture2D(uTexture, vec2(vCoordinate.x, 1.0 - vCoordinate.y));"
	"}";

	我这里有用的采样器因为截取的渲染视频的着色器,所以是拓展采样器,渲染静态的bmp 用的是 Sampler2d。
	这里 顶点着色器 把 纹理坐标传过来后,在要采样的时候,把xy坐标拆出来,由于GL中是归一化的参数,所以上下颠倒就可以很容易的写出:(1 - vCoordinate.y),这种情况用的比较多
	
2、通过矩阵翻转顶点
	这里和 第一种思想是一样的,就不多做解释了,一般不适用。

3、翻转原纹理图片
	这种方法是通过 Matrix 把原始图片进行翻转,然后再进行渲染,一般不适用

4、纹理

1、普通图片纹理
2、从surface流中获取纹理
两种获取原始贴图纹理的方式,本质上是一样的。后续再补充。

5、FBO

FBO其实可以理解为一个容器缓冲,并不能直接用他绘制,里面包含了 多个颜色附着,一个深度附着,以及一个模板附着。

一搬使用流程:创建FBO textureID -> 创建FBO -> 绑定FBO -> draw -> 解绑FBO -> 激活显示纹理单元 -> draw

1、创建 FBO textureID
	public static int createFBOTextureID(int width, int height) {
        //新建纹理
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        //绑定纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);

        //根据参数,为上面的纹理ID,生成一个2D纹理
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

        //配置边缘过渡参数
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

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

        return textures[0];
    }
2、创建FBO
	public static int createFBO() {
        int[] frameBuffer = new int[1];
        GLES20.glGenFramebuffers(1, frameBuffer, 0);
        return frameBuffer[0];
    }
3、绑定 FBO
	public static void bindFBO(int fbo, int textureID) {
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureID, 0);
    }
    绑定之后,下一步的draw动作只会发生在 FBO 中,不会直接显示出来。
4、draw
	4.1、在draw之前,根据需要,更新下坐标系以及显示窗口,因为FBO坐标系需要恢复为opengl的默认坐标(上面有坐标系中有说过),这样采样器能正常取色。
	4.2、执行纹理draw流程。
	4.3、如果在4.1中进行了操作,要及时变更回来,方便下方进行绘制。
5、解绑FBO
	public static void unBindFBO() {
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }
    解绑之后,接下来的draw动作,会显示出来。
6、激活纹理显示单元
	activateTexture(GLES20.GL_TEXTURE_2D, mSoulTextureId, 1, mSoulTextureHandler);
7、draw
	执行纹理draw流程
这里区别于 第四步的 draw,第四步的draw 是绘制到缓冲的FBO中,并不可见,所以需要draw 到屏幕中。

6、示例 Demo

还没来得及上传到git,后续有时间再上传。

7、番外

	OpenGLES 个人觉得 本质上 是面向 textureID 的操作,无论是在 FBO 中的处理,还是 后续的显示draw,都是先绑定 ID,在 用的最多的camera 预览中,也是如此,由GL创建好surface后,传入到camera输出流数组中,后续其实还是和视频数据一样,从流中更新图元数据即可,大概的流程就是这样。
	当然也可以同一个实体,渲染不同的纹理,只要给出纹理坐标以及相应的纹理资源即可,比如3D实体魔方等。(瞎猜,hhh)
	能用OpenGLES 来实现的还有很多小东西,一直在学的路上。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值