关于opengl-es:Opengl-ES之PBO

叨叨一句几句对于Opengl的系列曾经有较长的一段时间没有更新了,然而这个系列还远没有到结束境地,后续至多还有对于Opengl矩阵变换、YUV与RGB互转、Opengl水印贴图、Opengl转场动画等主题文章。 断更的次要起因如果给本人找个借口的话能够说是工作比价忙,如果说的比拟事实一点就是本人懒且没啥能源,毕竟写技术博客文章是一件工夫老本投入很大,而收益产出极小的一件事件... 进入正题... 理解过Opengl的童鞋们都晓得,在Opengl中存在这个各种O,例如VAO、VBO、FBO等,而呈现各种各样的O个别都是因为思考到性能的起因。 明天咱们要介绍的配角PBO,它和之前咱们介绍VBO很像,理解完PBO之后童鞋们能够比照一下PBO与VBO的差别点。 上面从两个方面介绍PBO,什么是PBO以及如何应用PBO。 本文首发于微信公总号号:思想觉悟 更多对于音视频、FFmpeg、Opengl、C++的原创文章请关注微信公众号:思想觉悟 什么是PBOPBO(Pixel Buffer Object像素缓冲对象)。在理解什么是PBO之前,咱们先来理解一下为什么会呈现PBO这么一个货色? 所谓存在即正当,用倒退的眼光看问题,PBO的呈现必定是为了代替某种货色,或者是为了解决某个问题。 在应用Opengl的时候常常须要在GPU和CPU之间传递数据,例如在应用Opengl将YUV数据转换成RGB数据时就须要先将YUV数据上传到GPU,个别应用函数glTexImage2D,处理完毕后再将RGB后果数据读取到CPU,这时应用函数glReadPixels即可将数据取回。然而这两个函数都是比拟迟缓的,特地是在数据量比拟大的时候。PBO就是为了解决这个拜访慢的问题而产生的。 PBO能够让咱们通过一个内存指针,间接拜访显存(GPU)的数据,咱们将这块内存指针称作缓冲区。咱们能够通过函数glMapBuffer失去它的内存指针,而后就对这块缓冲区的数据能够随心所欲了。 例如应用函数glReadPixels本来是要传一个内存指针进去的,然而有了缓冲区,它就能够把数据间接复制到缓冲区中去,而不是复制到内存条中去,这样就大大提高了数据的传递效率。 PBO的次要长处是通过间接内存拜访的形式与显存进行疾速像素数据传输,而无需占用CPU周期。 可能看到这张图你没什么感觉,然而比照看看上面这张CPU与GPU间接传递数据的图你就会有所发现了: 留神:PBO是OpenGL ES 3.0开始提供的一种形式,次要利用于从内存疾速复制纹理到显存,或从显存复制像素数据到内存。 PBO的应用形式既然PBO这么有效率,那么咱们在什么状况下可能会用到PBO呢?有个常见的例子,例如咱们在安卓上开发Camera利用录制视频时,如果须要用到x264进行软编码的话可能就会用到PBO,首先咱们将相机纹理图像送到Surface渲染显示,而后将Surface数据应用PBO的形式读取解决送到X264编码器中进行编码,当然在安卓上你也能够应用ImageReader... 上面咱们来介绍下PBO的应用形式。 PBO的创立和初始化相似于VBO,然而在应用的时候须要用到GL_PIXEL_UNPACK_BUFFER 和GL_PIXEL_PACK_BUFFER 这两个令牌,其中GL_PIXEL_UNPACK_BUFFER绑定示意该PBO用于将像素数据从程序(CPU)传送到OpenGL中;绑定为GL_PIXEL_PACK_BUFFER示意该PBO用于从OpenGL中读回像素数据。 Pbo创立先上代码,跟着正文看 void PBOOpengl::initPbo() { int imgByteSize = imageWidth * imageHeight * 4; // RGBA glGenBuffers(1, &uploadPboId); // 绑定pbo glBindBuffer(GL_PIXEL_UNPACK_BUFFER, uploadPboId); // 设置pbo内存大小 // 这一步非常重要,第2个参数指定了这个缓冲区的大小,单位是字节,肯定要留神 // 而后第3个参数是初始化用的数据,如果你传个内存指针进去,这个函数就会把你的 // 数据复制到缓冲区里,咱们这里一开始并不需要什么数据,所以传个nullptr就行了 glBufferData(GL_PIXEL_UNPACK_BUFFER, imgByteSize, nullptr, GL_STREAM_DRAW); // 解除绑定 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glGenBuffers(1, &downloadPboId); glBindBuffer(GL_PIXEL_PACK_BUFFER, downloadPboId); glBufferData(GL_PIXEL_PACK_BUFFER, imgByteSize, nullptr, GL_STREAM_DRAW); // 解除绑定 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); LOGD("uploadPboId:%d---downloadPboId:%d---imgByteSize:%d", uploadPboId, downloadPboId, imgByteSize);}下面的代码创立了两个PBO,其中uploadPboId用于纹理上传,downloadPboId用于纹理下载。创立好PBO之后而后应用两个PBO专用的令牌进行绑定,之后就调用glBufferData给PBO调配缓冲区,当然,你也能够在应用的时候先进行绑定,而后从新调用glBufferData调配新的缓冲区。 ...

November 23, 2022 · 8 min · jiezi

关于opengl-es:OpenglEs之EGL环境搭建

前言后面咱们公布了一系列的入门教程,例如C++系列的指针扫盲、多线程的应用等,JNI入门系列,ffmpeg入门系列等,有感兴趣的童鞋们能够关注往回自行查阅。 明天咱们的主题仍然是音视频开发的领域,做过音视频开发的都晓得Opengl也是音视频开发中的一项重要技能,特地是波及到视频录制、特效解决、画质渲染细分性能。因而后续笔者打算再出一系列的Opengl ES的学习笔记,心愿能与大家独特温故知新。 因为后面介绍了一些NDK和C++的教程,所以为了坚固,后续的一些demo多以NDK的模式出现给大家,应用Opengl ES3的版本。 明天咱们的主题是Opengl ES的第一篇-->EGL EGL是什么家喻户晓,Opengl是跨平台的,那么面对各种平台的差异性,Opengl是如何抹平而做到跨平台的呢?这兴许就是EGL的功绩吧,简略地说EGL就是Opengl和平台各平台之间的一个适配器,是一系列的接口,具体实现是由具体的设施厂商实现的。 EGL 是渲染 API(如 OpenGL ES)和原生窗口零碎之间的接口.通常来说,OpenGL 是一个操作 GPU 的 API,它通过驱动向 GPU 发送相干指令,管制图形渲染管线状态机的运行状态,然而当波及到与本地窗口零碎进行交互时,就须要这么一个中间层,且它最好是与平台无关的,因而 EGL 被设计进去,作为 OpenGL 和原生窗口零碎之间的桥梁。 EGL API 是独立于 OpenGL 各版本规范的独立的一套 API,其次要作用是为 OpenGL 指令 创立上下文 Context 、绘制指标 Surface 、配置 FrameBuffer 属性、Swap 提交绘制后果等。EGL提供如下机制: 与设施的原生窗口零碎通信查问绘图外表的可用类型和配置创立绘图外表在 OpenGL ES 和其余图形渲染 API 之间同步渲染治理纹理贴图等渲染资源上面这张图可简要看出EGL的接口能力: EGL创立流程想要在安卓上应用Opengl ES咱们能够间接应用GLSurfaceView来进行Opengl的渲染,因为GLSurfaceView外部给咱们封装好了EGL环境和渲染线程。如果咱们想要更高的拓展性,咱们也应用SurfaceView,而后参考SurfaceView中的EGL环境搭建、线程模型来自行搭建Opengl ES的渲染环境。 本着学习摸索的目标,咱们尝试在NDK搭建EGL环境。 上面这张图展现的是安卓零碎上EGL的次要应用API: 须要阐明的一点是EGL是单线程模型的,也就说说EGL环境的创立、渲染操作、EGL环境的销毁都必须在同一个线程内实现,否则是有效的。当然咱们能够通过共享EGL上下文来做多多线程渲染,但这些都是后话了... 任何OpenGL ES应用程序都必须在开始渲染之前应用EGL执行如下工作: 查问并初始化设施商可用的显示器。创立渲染外表。 EGL中创立的外表能够分类为屏幕上的外表或者屏幕外的外表。屏幕上的外表连贯到原生窗口零碎,而屏幕外的外表是不显示然而能够用作渲染外表的像素缓冲区。这些外表能够用来渲染纹理,并能够在多个Khronos API之间共享。创立渲染上下文。 EGL是创立OpenGL ES渲染上下文所必须的。这个上下文必须连贯到适合的外表能力开始渲染。上面是EGL环境创立的次要流程: 说完焦躁的基础理论,那就放码过去吧!!! 应用Android Studio创立一个Native工程,而后配置好CMakeLists.txt引入相干库: cmake_minimum_required(VERSION 3.18.1)project("learn")#找到蕴含所有的cpp文件file(GLOB allCpp *.cpp **/**.cpp **/**/**.cpp **/**/**/**.cpp **/**/**/**/**.cpp)add_library( # Sets the name of the library. # 库名称 learn SHARED ${allCpp})target_link_libraries( learn # 引入egl egl # 引入gles 3 GLESv3 # 安卓相干库 android # 安卓log log)上面咱们创立一个与Native映射的EGLHelper类: ...

October 10, 2022 · 4 min · jiezi

关于opengl-es:OpenGL-ES-压缩纹理

什么是压缩纹理在理论利用特地是游戏中纹理占用了相当大的包体积,而且GPU无奈间接解码目前风行的图片格式,图片必须转换为RGB等类型的格局能力上传到GPU内存,这显然减少了GPU内存的占用。为了解决这些问题于是呈现了GPU反对的压缩纹理格局,在GPU中进行解码。压缩纹理属于有损压缩,更在意解码速度,而编码在程序运行之前,因而速度较慢。 压缩纹理的常见格局基于OpenGL ES的压缩纹理有常见的如下几种实现:1)ETC1(Ericsson texture compression)2)ETC2(Ericsson texture compression)3)PVRTC (PowerVR texture compression)4)ATITC (ATI texture compression)5)S3TC (S3 texture compression) ETC1ETC1格局是OpenGL ES图形规范的一部分,并且被所有的Android设施所反对。扩大名为: GL_OES_compressed_ETC1_RGB8_texture,不反对通明通道,所以仅能用于不通明纹理。且要求大小是2次幂。当加载压缩纹理时,参数反对如下格局: GL_ETC1_RGB8_OES(RGB,每个像素0.5个字节) ETC2ETC2 是 ETC1 的扩大,压缩比率一样,但压缩品质更高,而且反对通明通道,能残缺存储 RGBA 信息。ETC2 须要 OpenGL ES 3.0(对应 WebGL 2.0)环境,目前还有不少低端 Android 手机不兼容,iOS 方面从 iPhone5S 开始都反对 OpenGL ES 3.0。ETC2 和 ETC1 一样,长宽能够不相等,但要求是 2 的幂次方。 PVRTC反对的GPU为Imagination Technologies的PowerVR SGX系列。OpenGL ES的扩大名为: GL_IMG_texture_compression_pvrtc。当加载压缩纹理时,参数反对如下几种格局: GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG (RGB,每个像素0.5个字节) GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG (RGB,每个像素0.25个字节) GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG (RGBA,每个像素0.5个字节) GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG (RGBA,每个像素0.25个字节) ATITC反对的GPU为Qualcomm的Adreno系列。反对的OpenGL ES扩大名为: GL_ATI_texture_compression_atitc。当加载压缩纹理时,参数反对如下类型的纹理: GL_ATC_RGB_AMD (RGB,每个像素0.5个字节) GL_ATC_RGBA_EXPLICIT_ALPHA_AMD (RGBA,每个像素1个字节) GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD (RGBA,每个像素1个字节) S3TC也被称为DXTC,在PC上宽泛被应用,然而在挪动设施上还是属于陈腐事物。反对的GPU为NVIDIA Tegra系列。OpenGL ES扩大名为:GL_EXT_texture_compression_dxt1和GL_EXT_texture_compression_s3tc。当加载压缩纹理时,参数有如下几种格局: GL_COMPRESSED_RGB_S3TC_DXT1 (RGB,每个像素0.5个字节) GL_COMPRESSED_RGBA_S3TC_DXT1 (RGBA,每个像素0.5个字节) GL_COMPRESSED_RGBA_S3TC_DXT3 (RGBA,每个像素1个字节) GL_COMPRESSED_RGBA_S3TC_DXT5 (RGBA,每个像素1个字节) ...

July 5, 2021 · 1 min · jiezi

关于opengl-es:Android-OpenGL-ES-EGL-C实现

PS本篇持续上一篇的内容,咱们来对Native EGL环境实现的各个步骤进行具体解析EGL Native层的实现上一篇文章Android OpenGL ES - EGL源码解析以及C++实现 咱们还是先来回顾一下流程图 以及代码 //(1) 将线程附加到虚拟机,并获取env if (that->m_jvm_for_thread->AttachCurrentThread(&env, NULL) != JNI_OK) { LOGE(that->TAG, "线程初始化异样"); return; } // (2) 初始化 EGL if (!that->InitEGL()) { //解除线程和jvm关联 that->m_jvm_for_thread->DetachCurrentThread(); return; } //进入循环 while (true) { //依据OpenGL渲染状态进入不同的解决 switch (that->m_state) { //刷新Surface,从里面设置Surface后m_state置为该状态,阐明曾经从内部(java层)取得Surface的对象了 case FRESH_SURFACE: LOGI(that->TAG, "Loop Render FRESH_SURFACE") // (3) 初始化Window that->InitDspWindow(env); // (4) 创立EglSurface that->CreateSurface(); // m_state置为RENDERING状态进入渲染 that->m_state = RENDERING; break; case RENDERING: LOGI(that->TAG, "Loop Render RENDERING") // (5) 渲染 that->Render(); break; case STOP: LOGI(that->TAG, "Loop Render STOP") //(6) 解除线程和jvm关联 that->ReleaseRender(); that->m_jvm_for_thread->DetachCurrentThread(); return; case SURFACE_DESTROY: LOGI(that->TAG, "Loop Render SURFACE_DESTROY") //(7) 开释资源 that->DestroySurface(); that->m_state = NO_SURFACE; break; case NO_SURFACE: default: break; } usleep(20000); }}首先第(1)步将线程附加到虚拟机,并获取env,这一步简单明了,咱们从第(2)步开始 ...

December 6, 2020 · 3 min · jiezi

关于opengl-es:Android-OpenGL-ES-EGL源码解析以及C实现

PS咱们在后面的文章中就说过对于EGL的呈现起因以及其作用OpenGL 是一个跨平台的API,而不同的操作系统(Windows,Android,IOS)各有本人的屏幕渲染实现。所以OpenGL定义了一个两头接口层EGL(Embedded Graphics Library)规范,具体实现交给各个操作系统自身 EGL简略来说EGL是一个两头接口层,是一个标准,因为OpenGL的跨平台性,所以说这个标准显得尤其重要,不论各个操作系统如何蹦跶,都不能脱离我所定义的标准。 EGL的一些基础知识EGLDisplayEGL定义的一个形象的零碎显示类,用于操作设施窗口。 EGLConfigEGL配置,如rgba位数 EGLSurface渲染缓存,一块内存空间,所有要渲染到屏幕上的图像数据,都要先缓存在EGLSurface上。 EGLContextOpenGL上下文,用于存储OpenGL的绘制状态信息、数据。 初始化EGL的过程能够说是对下面几个信息进行配置的过程 OpenGL ES绘图残缺流程咱们在应用Java GLSurfaceView的时候其实只是自定义了Render,该Render实现了GLsurfaceView.Renderer接口,而后自定义的Render中的3个办法就会失去回调,Android 零碎其实帮我省掉了其中的很多步骤。所以咱们这里来看一下残缺流程(1). 获取显示设施(对应于下面的EGLDisplay) /* * Get an EGL instance */ mEgl = (EGL10) EGLContext.getEGL(); /* * Get to the default display. */ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);(2). 初始化EGL int[] version = new int[2];//初始化屏幕if(!mEgl.eglInitialize(mEglDisplay, version)) { throw new RuntimeException("eglInitialize failed");}(3). 抉择Config(用EGLConfig配置参数) //这段代码的作用是抉择EGL配置, 即能够本人先设定好一个你心愿的EGL配置,比如说RGB三种色彩各占几位,你能够轻易配,而EGL可能不能满足你所有的要求,于是它会返回一些与你的要求最靠近的配置供你抉择。if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config)) { throw new IllegalArgumentException("eglChooseConfig#2 failed");}(4). 创立EGLContext //从上一步EGL返回的配置列表中抉择一种配置,用来创立EGL Context。egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, mEGLContextClientVersion != 0 ? attrib_list : null);(5). 获取EGLSurface ...

December 2, 2020 · 3 min · jiezi

关于opengl-es:相机图片滤镜应用InstagramXFilter来了

PS之前我用过Instagram的拍照性能,对他的滤镜可是垂涎已久啊,所以这次依据网上的材料有了一个开源我的项目有趣味的能够看看InstagramXFilterInstagramXFilter参考了MagicCamera 以及 GPUImage,目前有几十种滤镜可供选择 读者能够下载Demo运行一下,看看是不是你想要的,InstagramXFilter 1.0.1 我的项目筹备如果读者也对开发一款这样的利用感兴趣的话,那么我后面几篇的博客兴许对你有帮忙Android OpenGL ES - 开篇 Android OpenGL ES - 环境搭建与简略三角形的绘制 Android OpenGL ES - 坐标系 Android OpenGL ES - GLSL根底篇 Android OpenGL ES - 纹理 Android OpenGL ES - 反相、曝光、对比度、饱和度、色调滤镜 Android OpenGL ES - 卷积矩阵这些博客将带你相熟OpenGL ES开发的方方面面。让你也有能力本人开发一款酷炫的相机/图片利用

November 12, 2020 · 1 min · jiezi

关于opengl-es:Android-OpenGL-ES-卷积矩阵

PS上一篇咱们说了一些简略的滤镜,明度、对比度、曝光度等等那么本篇咱们来说一下略微简单一点的卷积,了解卷积对图片解决还是非常重要的卷积从数学上讲,卷积就是一种运算,与减加乘除没有实质的区别的一种运算。就像咱们能够通过A+B的运算来计算A与B的和一样,简略的加减乘除运算符能够看成混合运算符两边元素的信息,咱们能够认为卷积运算也是一种混合信息的伎俩 图像卷积咱们方才说了卷积能够看成一种混合信息的伎俩,咱们来看一下图像卷积 如果咱们有上面一幅图像这幅图像不太清晰,存在很多噪点。 PS噪点又称图像噪声(image noise)是图像中一种亮度或色彩信息的随机变动(被拍摄物体自身并没有),通常是电子噪声的体现。它个别是由扫描仪或数码相机的传感器和电路产生的,也可能是受胶片颗粒或者现实光电探测器中不可避免的的散粒噪声影响产生的。图像噪声是图像拍摄过程中不心愿存在的副产品,给图像带来了谬误和额定的信息。这些噪点,就如同高山矗立的山峰: 咱们要做的就是把山峰刨掉一些土,填到山峰四周去。用数学的话来说,就是把山峰四周的高度均匀一下。 那咱们该如何做到这样呢? 图像卷积运算在计算机上咱们都晓得图像能够用一个二维矩阵来存储,其存储的内容(像素)又对应手机/电脑 硬件屏幕上的点。 有噪点的原图,咱们能够把它转为一个矩阵:然咱们咱们用上面这个矩阵来均匀一下下面的矩阵 如果我要均匀一下a1,1点,运算过程如下 如下图咱们应用上面这个卷积模板进行图像卷积运算,其后果就如动图那样,每个像素值都进行了加权均匀运算。动态的图可能看起来没那么直观,咱们来个动图 假如咱们有个矩阵与原图进行卷积运算 PS不同的矩阵会产生不同的卷积成果,因而有些中央把这个矩阵称为卷积核过程如下 卷积利用最经典的卷积利用就是图像锐化和含糊的解决。在挪动设施上应用GPU做图像锐化,个别就是利用空域滤波器对图像做模板卷积解决。 锐化拉普拉斯算法比拟适宜用于改善图像含糊,是比拟罕用的边缘增强解决算子。 顶点着色器Vertex Shader attribute vec4 position;attribute vec4 inputTextureCoordinate;uniform float imageWidthFactor; // 屏幕宽度步长因子uniform float imageHeightFactor; // 屏幕高度步长因子uniform float sharpness; // 锐化外围值,由外层用户输出varying vec2 textureCoordinate; // 以后纹理坐标varying vec2 leftTextureCoordinate;varying vec2 rightTextureCoordinate;varying vec2 topTextureCoordinate;varying vec2 bottomTextureCoordinate;varying float centerMultiplier; // Laplacian算子核心值varying float edgeMultiplier; // Laplacian算子边缘值void main(){ gl_Position = position; vec2 widthStep = vec2(imageWidthFactor, 0.0); vec2 heightStep = vec2(0.0, imageHeightFactor); textureCoordinate = inputTextureCoordinate.xy; leftTextureCoordinate = inputTextureCoordinate.xy - widthStep; rightTextureCoordinate = inputTextureCoordinate.xy + widthStep; topTextureCoordinate = inputTextureCoordinate.xy + heightStep; bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep; centerMultiplier = 1.0 + 4.0 * sharpness; edgeMultiplier = sharpness;}这次的GLSL显著和前几次不太一样了,前几次都是应用默认的Vertex Shader,那么这次咱们怎么了解那四个 left/top/right/bottom的纹理坐标?还有那两个屏幕步长因子,咱们再来看看下层代码的输出: ...

November 6, 2020 · 2 min · jiezi

关于opengl-es:Android-OpenGL-ES-反相曝光对比度饱和度色调滤镜

通过前几篇的博客,咱们应该队OpenGL有了根底的意识,那么咱们就该来点实际了,它来了,它来了,真正的滤镜它来了先放效果图 滤镜的学习是个循序渐进的过程,咱们本章先说一下简略的滤镜,也让读者揭开一角相机滤镜神秘面纱 OpenGL ES - 简略滤镜通过前几篇的博客,咱们应该能实现如上图中的原图的滤镜了吧,我对后面的工程也做了一些代码重构,类图如下所示,残缺代码请查看文末链接。 咱们前面的滤镜代码将只关注于外围的Shader Code局部,因为GL环境局部咱们后面几篇博客曾经做了十分具体的解说了。如果有读者不太熟悉,请查看后面的博客。 默认滤镜vertex shader attribute vec4 position;attribute vec4 inputTextureCoordinate;varying vec2 textureCoordinate;void main() { gl_Position = position; textureCoordinate = inputTextureCoordinate.xy;}fragment shader precision mediump float;varying highp vec2 textureCoordinate;uniform sampler2D inputImageTexture;void main(){ gl_FragColor = texture2D(inputImageTexture, textureCoordinate);};默认的滤镜咱们后面也说过了,应用texture2D函数对纹理进行取样,既OpenGL展现图片 反相对于图片反相的定义还是很容易了解的,咱们曾经晓得在GL中色彩是用r,g,b,a示意的,r,g,b,a 的范畴是0.0f~1.0f,若染色color = vec4(r,g,b,a),则反相的色彩invert_color = vec4((1.0-color.rgb), color.a); 所以反相的fragment shader 自然而然就是上面了 fragment shader precision mediump float;varying highp vec2 textureCoordinate;uniform sampler2D inputImageTexture;void main(){ lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); // textureColor.w其实就是textureColor.a 透明度,这里不参加反相,因为咱们透明度原本是1(齐全不通明),参加反相的话就是0了,齐全就是通明了, gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);};反相效果图如下 ...

October 30, 2020 · 3 min · jiezi

关于opengl-es:Android-OpenGL-ES-GLSL高级篇

咱们之前说了一下GLSL的基础知识,详情可参见Android OpenGL ES - GLSL根底篇上一张呢咱们也理解了一下纹理,实现了咱们的OpenGL 的第一张图片,不过可能咱们对gl_Position,gl_Fragcolor,texture2D ( uTexture, vCoordinate)等一些GLSL语法不是特地相熟,本篇博客呢,是对GLSL的一些补充,也是为前面的博客打下基础。 PS:无非凡阐明,文中的 GLSL 均指 OpenGL ES 2.0 的着色语言。GLSL 高级篇invariant 限定符invariant 能够作用于顶点着色器输入的任何一个 varying 变量。 当着色器被编译时,编译器会对其进行优化,这种优化操作可能引起指令重排序(instruction reordering),指令重排序可能引起的后果是当两个着色器进行雷同的计算时无奈保障失去雷同的后果。例如,在两个顶点着色器中,变量 gl_Position 应用雷同的表达式赋值,并且当着色程序运行时,在表达式中传入相等的变量值,则两个着色器中 gl_Position 的值无奈保障相等,这是因为两个着色器是别离独自编译的。这将会引起 multi-pass 算法的几何不统一问题。通常状况下,不同着色器之间的这种值的差别是容许存在的。如果要防止这种差别,则能够将变量申明为invariant,能够独自指定某个变量或进行全局设置。 应用 invariant 限定符能够使输入的变量放弃不变。invariant 限定符能够作用于之前已申明的变量使其具备不变性,也能够在申明变量时间接作为申明的一部分,可参考以下两段示例代码: varying mediump vec3 Color;// 使已存在的 color 变量不可变invariant Color;或 invariant varying mediump vec3 Color;以上是仅有的应用 invariant 限定符情境。如果在申明时应用 invariant 限定符,则必须保障其放在存储限定符(varying)之前。只有以下变量能够申明为 invariant: 由顶点着色器输入的内置的非凡变量由顶点着色器输入的 varying 变量向片段着色器输出的内置的非凡变量向片段着色器输出的 varying 变量由片段着色器输入的内置的非凡变量为保障由两个着色器输入的特定变量的不变性,必须遵循以下几点: 该输入变量在两个着色器中都被申明为 invariant影响输入变量的所有表达式、流程管制语句的输出值必须雷同对于影响输入值的所有纹理函数,纹理格局、纹理元素值和纹理过滤必须统一对输出值的所有操作都必须统一。表达式及插值计算的所有操作必须统一,雷同的运算数程序,雷同的联合性,并且按雷同程序计算。插值变量和插值函数的申明,必须有雷同类型,雷同的显式或隐式的精度precision限定符。影响输入值的所有管制流程必须雷同,影响决定管制流程的表达式也必须遵循不变性的规定。最根本的一点是:所有的 invariant 输出量的上游数据流或控制流必须统一。 此限定符情境比拟少,这里就一笔带过了 内置变量顶点着色器(Vertex Shader)内置变量内置变量(输入)形容单位或坐标系highp vec4 gl_Position;变换后的顶点地位裁剪坐标系Vclipmediump float gl_PointSize;变换后的点大小(仅仅表白光栅化后点的大小)像素gl_Position,此变量用于写入齐次顶点地位坐标。一个残缺的顶点着色器的所有执行命令都应该向此变量写入值。该值的输出同时也是图元拆卸、剪切(clipping)、剔除(culling)等对于图元的固定性能操作中的输出值。其决定了一个几何图形的地位与形态。 ...

October 22, 2020 · 1 min · jiezi

关于opengl-es:Android-OpenGL-ES-纹理

上一篇咱们咱们要对GLSL语言有了根底的理解,咱们当初应该对于GLSL Shader脚本起码能了解其中的语法含意,不过这显然是不够的。对于后面几个章节都能够说是对Android OpenGL ES的入门,本篇呢就说一下在咱们的理论工作中遇到的场景下(诸如相机滤镜是怎么实现的、视频如何应用OpenGL 渲染等等实际性问题)来介绍纹理 纹理通过后面的内容咱们曾经理解到,咱们能够为每个顶点增加色彩来减少图形的细节,从而创立出乏味的图像。然而,如果想让图形看起来更实在,咱们就必须有足够多的顶点,从而指定足够多的色彩。这将会产生很多额定开销,因为每个模型都会需要更多的顶点,每个顶点又需要一个色彩属性。这个时候咱们就能够应用纹理(Texture)。 纹理基本概念纹理是一个2D图片(甚至也有1D和3D的纹理),它能够用来增加物体的细节;你能够设想纹理是一张绘有砖块的纸,无缝折叠贴合到你的3D的房子上,这样你的房子看起来就像有砖墙表面了。因为咱们能够在一张图片上插入十分多的细节,这样就能够让物体十分精密而不必指定额定的顶点。 上面你会看到之前教程的那个三角形贴上了一张砖墙图片。 纹理坐标为了可能把纹理映射(Map)到三角形上,咱们须要指定三角形的每个顶点各自对应纹理的哪个局部。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来表明该从纹理图像的哪个局部采样(译注:采集片段色彩)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。 纹理坐标在x和y轴上,范畴为0到1之间(留神咱们应用的是2D纹理图像)。应用纹理坐标获取纹理色彩叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。上面的图片展现了咱们是如何把纹理坐标映射到三角形上的。 咱们为三角形指定了3个纹理坐标点。如上图所示,咱们心愿三角形的左下角对应纹理的左下角,因而咱们把三角形左下角顶点的纹理坐标设置为(0, 0);三角形的上顶点对应于图片的上中地位所以咱们把它的纹理坐标设置为(0.5, 1.0);同理右下方的顶点设置为(1, 0)。咱们只有给顶点着色器传递这三个纹理坐标就行了,接下来它们会被传片段着色器中,它会为每个片段进行纹理坐标的插值。 纹理坐标看起来就像这样://纹理坐标 const GLfloat m_texture_coors[6] = { 0.0f, 0.0f, // 左下角 1.0f, 0.0f, // 右下角 0.5f, 1.0f//上};2D纹理的坐标系是从左下角为原点向上为t轴,向右为s轴的坐标系。这个坐标系的y方向和GL坐标系相同,所以默认按顶点坐标系方向输出的图像是倒置的。 如果想要让纹理正向显示,咱们须要做的一步工作便是将输出的纹理坐标或者顶点坐标进行y轴方向的倒置。这些咱们会在上面的示例中看到 加载图片咱们下面理解了纹理的坐标系之后,那么要做的第一件事天然是把它们加载到咱们的利用中。纹理图像可能被贮存为各种各样的格局,每种都有本人的数据结构和排列,所以咱们如何能力把这些图像加载到利用中呢? 咱们这里采纳Android上的API, BitmapFactory.decodeResource(getResources(), R.mipmap.wall)而后把失去的Bitmap对象传入Native进行解决 AndroidBitmapInfo info; // create a AndroidBitmapInfoint result;// 获取图片信息result = AndroidBitmap_getInfo(env, bitmap, &info);if (result != ANDROID_BITMAP_RESULT_SUCCESS) { LOGE("Player", "AndroidBitmap_getInfo failed, result: %d", result); return 0;}LOGD("Player", "bitmap width: %d, height: %d, format: %d, stride: %d", info.width, info.height, info.format, info.stride);// 获取像素信息unsigned char *data;result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void **>(&data));if (result != ANDROID_BITMAP_RESULT_SUCCESS) { LOGE("Player", "AndroidBitmap_lockPixels failed, result: %d", result); return 0;}size_t count = info.stride * info.height;LOGE("Player", "count: %d", count);unsigned char *resultData = (unsigned char *) malloc(count * sizeof(unsigned char));;memcpy(resultData, data, count);// 像素信息不再应用后须要解除锁定result = AndroidBitmap_unlockPixels(env, bitmap);if (result != ANDROID_BITMAP_RESULT_SUCCESS) { LOGE("Player", "AndroidBitmap_unlockPixels failed, result: %d", result);}最初失去unsigned char *resultData指向图片的内存地址 ...

October 20, 2020 · 3 min · jiezi

关于opengl-es:Android-OpenGL-ES-GLSL基础篇

上节在绘制三角形的时候,简略解说了一些着色器,GLSL 的相干概念,可能看的云里雾里的。不要放心,在本节中,我将具体解说着色语言 GL Shader Language(GLSL)的一些根本的概念。 PS:无非凡阐明,文中的 GLSL 均指 OpenGL ES 2.0 的着色语言。GLSL (GL Shader Language)在上一节中,咱们提到了GLSL 的语法与 C 语言很相似,也看到了一个非常简单的着色器,如下:VertexShader "attribute vec4 aPosition; \n" "void main() \n" "{ \n" " gl_Position = aPosition; \n" "} \n";Fragment Shader "precision mediump float;\n" "void main() \n" "{ \n" " gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n" "} \n";和 C 语言程序对应,用 GLSL 写出的着色器,它同样包含: 变量 position变量类型 vec4限定符 attributemain 函数根本赋值语句 gl_Position = aPosition内置变量 gl_Position…这所有,都是那么像C语言,所以,在把握 C 语言的根底上,GLSL 的学习老本是很低的。 ...

October 16, 2020 · 4 min · jiezi