OpenGL笔记(五) 着色器渲染(以Android为例)
一、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为例)的更多相关文章
- OpenGl中使用着色器的基本步骤及GLSL渲染简单示例
OpenGL着色语言(OpenGL Shading Language,GLSL)是用来在OpenGL中着色编程的语言,是一种具有C/C++风格的高级过程语言,同样也以main函数开始,只不过执行过程是 ...
- OpenGL官方教程——着色器语言概述
OpenGL官方教程——着色器语言概述 OpenGL官方教程——着色器语言概述 可编程图形硬件管线(流水线) 可编程顶点处理器 可编程几何处理器 可编程片元处理器 语言 可编程图形硬件管线(流水线) ...
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- WebGL着色器渲染小游戏实战
项目起因 经过对 GLSL 的了解,以及 shadertoy 上各种项目的洗礼,现在开发简单交互图形应该不是一个怎么困难的问题了.下面开始来对一些已有业务逻辑的项目做GLSL渲染器替换开发. 起因是看 ...
- OpenGL之shader着色器的应用,三色渐变的三角形
学习自: https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_7 首先放一张效果图: 本次教程,将着色器单独定 ...
- python学习笔记(五):装饰器、生成器、内置函数、json
一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...
- Struts2学习笔记五 拦截器
拦截器,在AOP中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. Struts2中,拦截器是动态拦截Action调用的对象.它提供了一种机制可以使 ...
- Android OpenGL ES 开发(八): OpenGL ES 着色器语言GLSL
前面的文章主要是整理的Android 官方文档对OpenGL ES支持的介绍.通过之前的文章,我们基本上可以完成的基本的形状的绘制. 这是本人做的整理笔记: https://github.com/re ...
- 【OPENGL】第三篇 着色器基础(一)
在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. ...
随机推荐
- 初学HTML-2
HTML标签的分类:单标签:只有开始标签,没有结束标签,即,只由一个<>组成的html. 双标签:有开始标签和结束标签,即,由一个<>和一个</ >组成的h ...
- 截取URL的某个参数值
原文作者链接 https://www.jianshu.com/p/c9324d237a8e
- 锋利的Jquery之插件Cookie记住密码
先下载Jquery cookie js ,下载路径: http://plugins.jquery.com/cookie/ 记住,jquery的包要放在cookie的包前面,否则会产生异常 <!D ...
- ThinkPHP5+Layui实现图片上传加预览
html代码 <div class="layui-upload"> <button type="button" class="lay ...
- iTerm通过堡垒机自动登录服务器
为了保障网络和数据安全,越来越多公司使用堡垒机.iTerm作为一个好用的终端利器,要实现自动通过堡垒机登录服务器的方式有多种.下面我就来介绍一种通过expect脚本的方式完成配置. 第一步,进入/us ...
- 如何在PeopleSoft中找到并更改默认样式表名称
PeopleSoft的默认样式表名称是用来控制应用程序的外观的.在PeopleSoft中可以使用集中样式表来更改应用程序的外观,oracle为每个应用程序版本设置了默认的样式表. 下面是不同应用程序版 ...
- Python+Selenium笔记(四):unittest的Test Suite(测试套件)
(一) Test Suite测试套件 一个测试套件是多个测试或测试用例的集合,是针对被测程序的对应的功能和模块创建的一组测试,一个测试套件内的测试用例将一起执行. 应用unittest的TestSui ...
- 《SQL Server 2008从入门到精通》--20180716
1.锁 当多个用户同时对同一个数据进行修改时会产生并发问题,使用事务就可以解决这个问题.但是为了防止其他用户修改另一个还没完成的事务中的数据,就需要在事务中用到锁. SQL Server 2008提供 ...
- 中式台球 规则 ( ChinaBilliards )
中式台球比赛规则 中式台球兴起于上世纪八十年代末,之前叫法有“中式8球”.“中式9球”.“十六彩”.“美式落袋”.“普尔“.”八球””等等.中国台球协会于2012年宣布统一该项运动称呼,定名为“中式台 ...
- Tidb数据库导入数据出现oom问题
今天使用insert操作向tidb中插入数据,发现正在导入的过程中出现如下错误: mysql: [Warning] Using a password on the command line inter ...