一、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. 前端面试(原生js篇) - DOM

    根据我的面试经历,一般小公司的面试环节,比较关心框架的熟练程度,以及独立开发组件的能力 但大厂通常有五轮以上的面试,而且对 js 基础语法很是看重 于是我总结了一些关于 js 基础的面试对话,有的当时 ...

  2. inline-block元素间隙处理

    要使多个块级元素并行显示,可使用float或者inline-block进行处理 使用inline-block会出现元素之间的间隙 <div class="demo"> ...

  3. PHP中NOTICE错误常见解决方法

    对于初学者,肯定会遇到不同的错误提示,比如:警告,致命,等等,其中NOTICE错误等级最低,页面中,好多类似 Notice: Use of undefined constant title - ass ...

  4. luogu P4108 [HEOI2015]公约数数列——solution

    -by luogu 不会啊.... 然后%了一发题解, 关键是 考虑序列{$a_n$}的前缀gcd序列, 它是单调不升的,且最多只会改变$log_2N$次,因为每变一次至少除2 于是,当我们询问x时: ...

  5. 【读书笔记】iOS-网络-HTTP-URL结构

    http://user:password@hostname:port/absolute-path?query. http:  协议 user:password@   认证 hostname:  主机名 ...

  6. 自定义适用于手机和平板电脑的 Dynamics 365(五):可视控件

    使用 适用于手机的 Dynamics 365 和平板电脑中的可视控件帮助移动用户更快地输入 Dynamics 365 数据并提供更丰富的可视体验. 此组自定义控件包括滑块.开关.星数评级.视频嵌入以及 ...

  7. Expo大作战(六)--expo开发模式,expo中exp命令行工具,expo中如何查看日志log,expo中的调试方式

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,将全部来与官网 我猜去全部机翻+个人 ...

  8. AWS CSAA -- 04 AWS Object Storage and CDN - S3 Glacier and CloudFront(三)

    021 Storage Gateway 022 Snowball 023 Snowball - Lab 024 S3 Transfer Acceleration

  9. win10 安装microsoft.net framework3.5

    转载于:https://www.windows10.pro/win10-net-framework-3-5/ 之前手残不小心把microsoft.net framework3.5删了,结果导致Sql ...

  10. Oracle EBS PO rcv_shipment_headers 数据缺失

    Datafix : How to Recreate Missing Receipt or Shipment Header Records (RCV_SHIPMENT_HEADERS table) (D ...