一、Android平台上下文环境的创建及初始化

1. 首先实例化Android上下文环境,即EGL的初始化。

bool EGLCore::init(EGLContext sharedContext) {
EGLint numConfigs;
EGLint width;
EGLint height; const EGLint attribs[] = { EGL_BUFFER_SIZE, , EGL_ALPHA_SIZE, , EGL_BLUE_SIZE, , EGL_GREEN_SIZE, , EGL_RED_SIZE, , EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE };
//eglGetDisplay来返回OpenGL ES渲染的目标,每个厂商都会返回默认的显示设备
if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
LOGE("eglGetDisplay() returned error %d", eglGetError());
return false;
}
// 初始化显示设备
if (!eglInitialize(display, , )) {
LOGE("eglInitialize() returned error %d", eglGetError());
return false;
}
// 得到配置选项信息
if (!eglChooseConfig(display, attribs, &config, , &numConfigs)) {
LOGE("eglChooseConfig() returned error %d", eglGetError());
release();
return false;
}
// 创建OpenGL的上下文环境EGLContext
EGLint eglContextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, , EGL_NONE };
if (!(context = eglCreateContext(display, config, NULL == sharedContext ? EGL_NO_CONTEXT : sharedContext, eglContextAttributes))) {
LOGE("eglCreateContext() returned error %d", eglGetError());
release();
return false;
} pfneglPresentationTimeANDROID = (PFNEGLPRESENTATIONTIMEANDROIDPROC)eglGetProcAddress("eglPresentationTimeANDROID");
if (!pfneglPresentationTimeANDROID) {
LOGE("eglPresentationTimeANDROID is not available!");
} return true;
}

2. 将EGL和设备的屏幕连接起来。使用EGLSurface,通过EGL库提供的eglCreateWindowSurface可以创建一个可实际显示的Surface,通过EGL库提供的eglCreatePbufferSurface可以创建一个OffScreen的Surface。_window就是通过Java层的Surface对象创建出的ANativeWindow类型的对象,即本地设备屏幕的表示。也就是说真实显示的Surface还是通过Java层创建好的, 然后OpenGL只是绘制到了这个target上边?

EGLSurface EGLCore::createWindowSurface(ANativeWindow* _window) {
EGLSurface surface = NULL;
EGLint format;
if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
LOGE("eglGetConfigAttrib() returned error %d", eglGetError());
release();
return surface;
}
ANativeWindow_setBuffersGeometry(_window, , , format);
if (!(surface = eglCreateWindowSurface(display, config, _window, ))) {
LOGE("eglCreateWindowSurface() returned error %d", eglGetError());
}
return surface;
}

通过Java层的Surface对象创建ANativeWindow类型的对象方法如下:

JNIEXPORT void JNICALL Java_com_phuket_tour_opengl_renderer_PngPreviewController_setSurface
(JNIEnv * env, jobject obj, jobject surface) {
if (surface != && NULL != controller) {
window = ANativeWindow_fromSurface(env, surface);
LOGI("Got window %p", window);
controller->setWindow(window);
} else if (window != ) {
LOGI("Releasing window");
ANativeWindow_release(window);
window = ;
}
}

3. 开发者需要开辟一个新的线程,来执行OpenGL ES的渲染操作,而且还必须为该线程绑定显示设备(surface)与上下文环境(Context)。EGL是双缓冲模式,内部有两个FrameBuffer,当EGL将一个FrameBuffer显示到屏幕上的时候,另外一个FrameBuffer就在后台等待OpenGL ES进行渲染输出了。直到调用函数eglSwapBuffers这条指令的时候,才会把前台的FrameBuffer和后台的FrameBuffer进行交换。

bool EGLCore::makeCurrent(EGLSurface eglSurface) {
return eglMakeCurrent(display, eglSurface, eglSurface, context);
}

二、Texture/Shader/Program

1. 创建Texture(纹理)

int PicPreviewTexture::initTexture() {
glGenTextures(, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
return ;
}

2. 创建/初始化/编译Shader

GLuint PicPreviewRender::compileShader(GLenum type, const char *sources) {
GLint status;
GLuint shader = glCreateShader(type);
if (shader == || shader == GL_INVALID_ENUM) {
LOGI("Failed to create shader %d", type);
return ;
}
glShaderSource(shader, , &sources, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
glDeleteShader(shader);
LOGI("Failed to compile shader : %s\n", sources);
return ;
}
return shader;
}

3. 创建并使用Program(显卡可执行程序)

int PicPreviewRender::useProgram() {
program = glCreateProgram();
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
glBindAttribLocation(program, ATTRIBUTE_VERTEX, "position");
glBindAttribLocation(program, ATTRIBUTE_TEXCOORD, "texcoord");
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
LOGI("Failed to link program %d", program);
return -;
}
glUseProgram(program); uniformSampler = glGetUniformLocation(program, "yuvTexSampler"); return ;
}

三、渲染操作

void PicPreviewRender::render(){
glViewport(_backingLeft, _backingTop, _backingWidth, _backingHeight);
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(program);
static const GLfloat _vertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f };
glVertexAttribPointer(ATTRIBUTE_VERTEX, , GL_FLOAT, , , _vertices);
glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
static const GLfloat texCoords[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };
glVertexAttribPointer(ATTRIBUTE_TEXCOORD, , GL_FLOAT, , , texCoords);
glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);
picPreviewTexture->bindTexture(uniformSampler);
glDrawArrays(GL_TRIANGLE_STRIP, , );
}

首先,_vertices有4个顶点,每个顶点都会调用一次顶点着色器程序。按照规则,一共有四个点,每个点为vec2,但是顶点着色器的in输入变量为vec3,在GLSL语法中,vec2传递给vec3,其中扩充的维度的值默认为0,这也可以接受因为所在的是二维平面,不然也不会2个float代表一个点,所以,第三维自动为0。gl_Position 的第四维是和裁剪以及变换有关的,没有相关的变换时候是1.0。

顶点坐标的归一化区间是[-1, 1],纹理坐标的归一化区间是[0, 1]。所以代码是将纹理整体完整铺在显示区域,如果想把纹理的一部分铺上去,那就在[0, 1]区间内部分写进去。

执行完渲染操作后,调用eglSwapBuffers即可显示。至此,一次渲染操作完成。

OpenGL笔记(五) 着色器渲染(以Android为例)的更多相关文章

  1. OpenGl中使用着色器的基本步骤及GLSL渲染简单示例

    OpenGL着色语言(OpenGL Shading Language,GLSL)是用来在OpenGL中着色编程的语言,是一种具有C/C++风格的高级过程语言,同样也以main函数开始,只不过执行过程是 ...

  2. OpenGL官方教程——着色器语言概述

    OpenGL官方教程——着色器语言概述 OpenGL官方教程——着色器语言概述 可编程图形硬件管线(流水线) 可编程顶点处理器 可编程几何处理器 可编程片元处理器 语言 可编程图形硬件管线(流水线) ...

  3. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  4. WebGL着色器渲染小游戏实战

    项目起因 经过对 GLSL 的了解,以及 shadertoy 上各种项目的洗礼,现在开发简单交互图形应该不是一个怎么困难的问题了.下面开始来对一些已有业务逻辑的项目做GLSL渲染器替换开发. 起因是看 ...

  5. OpenGL之shader着色器的应用,三色渐变的三角形

    学习自: https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_7 首先放一张效果图: 本次教程,将着色器单独定 ...

  6. python学习笔记(五):装饰器、生成器、内置函数、json

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...

  7. Struts2学习笔记五 拦截器

    拦截器,在AOP中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. Struts2中,拦截器是动态拦截Action调用的对象.它提供了一种机制可以使 ...

  8. Android OpenGL ES 开发(八): OpenGL ES 着色器语言GLSL

    前面的文章主要是整理的Android 官方文档对OpenGL ES支持的介绍.通过之前的文章,我们基本上可以完成的基本的形状的绘制. 这是本人做的整理笔记: https://github.com/re ...

  9. 【OPENGL】第三篇 着色器基础(一)

    在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. ...

随机推荐

  1. HDU2859(KB12-Q DP)

    Phalanx Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  2. JavaScript中七种数据类型·中·一

    Standing on Shoulders of Giants; 说到JavaScript里的类型很容易就让人想起 42和"42",分别是string型和number型,但是他们可 ...

  3. linux 新建用户和权限分配

    1.创建新用户:testuser 命令:#useradd 选项 用户名 选项: -c comment 指定一段注释性描述. -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主 ...

  4. Oracle 12c SQL Developer连接报错(ORA-12505)

    Oracle 12c SQL Developer连接报错(ORA-12505) 连接时报错码:Listener refused the connection with following error: ...

  5. OSGI企业应用开发(五)使用Blueprint整合Spring框架(二)

    上篇文章中,我们开发了一个自定义的Bundle,接着从网络中下载到Spring和Blueprint的Bundle,然后复制到DynamicRuntime项目下. 需要注意的是,这些Bundle并不能在 ...

  6. SD从零开始55-56, 风险管理, 付款卡

    [原创] SD从零开始55 风险管理的内容 应收款风险最小化Risk Minimization for Receivables 每个信用政策的目的是减少由客户应收款带来的风险: 连同信用管理,你也有权 ...

  7. 简单CNN 测试例

    1.训练数据: import tensorflow as tf import cv2 import os import numpy as np import time import matplotli ...

  8. create-react-app脚手架的安装和目录结构介绍

    1.对脚手架的初步了解 编程领域中的“脚手架”指的是能够快速搭建项目“骨架”的一类工具,例如大多数的React项目都有src,public,webpack配置文件等等,而src目录中又包含compon ...

  9. Djang之Model操作

    Django之Model操作 一.字段 1.字段列表: AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField ...

  10. Python网络爬虫笔记(四):使用selenium获取动态加载的内容

    (一)  说明 上一篇只能下载一页的数据,第2.3.4....100页的数据没法获取,在上一篇的基础上修改了下,使用selenium去获取所有页的href属性值. 使用selenium去模拟浏览器有点 ...