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程序交互. 首先我们先来看看什么叫着色器. ...
随机推荐
- django admin登陆添加修改内容
model文件中 __all__ = ["Book", "Publisher", "Author"] from django.db impo ...
- web自动化开发环境配置详解
1.安装 nodejs Grunt和所有grunt插件都是基于nodejs来运行的, https://nodejs.org/ 安装完成之后在终端 node -v 查看安装版本 2.安装 grunt-C ...
- ViewPager中切换界面Fragment被销毁的问题
ViewPager中切换界面Fragment被销毁的问题分析 使用ViewPager+Fragment实现界面切换,当界面数量大于3时,出现二次滑动后数据消失的情况,下面由Fragment生命周期进行 ...
- UWP开发细节记录:判断文件类型
StorageFile.ContentType 属性,是 string 类型,用来表示文件内容的 MIME 类型.例如,音乐文件可能有 "audio/mpeg" MIME 类型.( ...
- MAYA逼真手枪制作视频教程 中文字幕
下载地址 更多中文字幕教程请关注微镜映画网,有各类CG教程提供
- 为何使用Microsoft SQL Server Management Studio连接Integration Services服务失败
检查是否满足以下各项: 1. 首先你要确保当前你使用的Windows账号是有管理员权限的 2. 其次请在打开Microsoft SQL Server Management Studio时,通过右键Ru ...
- Python中可视化图表处理echarts库的安装
系统环境:Windows 7 企业版 进入cmd 输入:python –m pip install pyecharts
- 微信小程序里使用阿里巴巴矢量图标
登录 阿里巴巴矢量图标 (https://www.iconfont.cn) 选中图标,加入购物车图标 下载源代码 解析出来如下文件结构 有两种使用方式: 1)不转换成base64的文件 找到 icon ...
- Hadoop HBase概念学习系列之HLog(二)
首先,明确,HRegion服务器包含两大部分:HLog和HRegion. HLog用来存储数据日志,采用的是先写日志的方式. 当用户需要更新数据的时候,数据会被分配到对应的HRegion服务器上提交修 ...
- Javaweb学习(三):Servlet程序
好了,既然开发环境已经配置好了.那么我们首先要搞定得便是servlet了,至于为什么不先去研究jsp,这是因为jsp与servlet本就是一体两面,jsp其本身经过编译.载入.转化等步骤最终会成为se ...