当前位置: 首页 > news >正文

福建 专业网站建设公司杭州软件开发培训机构

福建 专业网站建设公司,杭州软件开发培训机构,如何开通自己的网站,网络学习平台一、介绍 1. 帧缓冲对象 默认情况下#xff0c;OpenGL渲染的目标是屏幕#xff0c;但如果你不想直接渲染到屏幕上#xff0c;还需要对渲染结果做某些后期处理、渲染到纹理、阴影映射等操作#xff0c;便可以使用帧缓冲对象#xff0c;实现离屏渲染。 帧缓冲对象#x…一、介绍 1. 帧缓冲对象 默认情况下OpenGL渲染的目标是屏幕但如果你不想直接渲染到屏幕上还需要对渲染结果做某些后期处理、渲染到纹理、阴影映射等操作便可以使用帧缓冲对象实现离屏渲染。 帧缓冲对象Frame Buffer ObjectFBO是一个概念容器它可以包含颜色缓冲区、深度缓冲区、模板缓冲区等形成一个完整的渲染目标。 通过使用帧缓冲对象可以实现离屏渲染、多重渲染目标MRT等高级渲染技术而不必直接渲染到屏幕。 2. 相关概念 以下是帧缓冲对象的一些基本概念 颜色缓冲区Color Buffer存储渲染的颜色信息。一个帧缓冲对象可以包含多个颜色缓冲区用于实现多重渲染目标。深度缓冲区Depth Buffer 存储每个像素的深度信息用于实现深度测试确保正确的渲染顺序。模板缓冲区Stencil Buffer 存储模板测试的结果用于实现各种复杂的渲染效果。渲染缓冲区Renderbuffer 实际上是OpenGL ES 3.0中用于存储颜色、深度和模板信息的内存对象。它可以附加到帧缓冲对象的不同附着点。 3. 渲染缓冲对象 渲染缓冲对象Render Buffer ObjectRBO是一种特殊类型的对象用于存储图形渲染过程中的像素数据优点是它的存储格式是优化过的性能更好适合渲染而不是读取所以不可以直接读取。 用途一般是作为帧缓冲对象的附着点提供一个高效的存储区域用于存储渲染结果。 渲染缓冲对象通常用于只写入不读取的场景而纹理可以作为可读取的附着点。于是渲染缓冲对象经常作为深度和模板附件来使用因为大多数时候并不需要从深度和模板缓冲中读取数据。 4. 关系图 图源OPENGL ES 3.0 编程指南 原书第2版 二、使用 帧缓冲对象的使用通常包括以下步骤 创建帧缓冲对象 使用 glGenFramebuffers 函数创建一个帧缓冲对象其值是一个非零的无符号整数。绑定帧缓冲对象 使用 glBindFramebuffer 函数将帧缓冲对象绑定为当前渲染目标。创建和附着附加点 创建颜色缓冲区和深度缓冲区然后将它们附着到帧缓冲对象的附着点上。渲染 执行渲染操作渲染结果将存储在帧缓冲对象中。解绑帧缓冲对象 使用 glBindFramebuffer(GL_FRAMEBUFFER, 0) 将帧缓冲对象解绑将渲染目标切换回屏幕数字0即表示屏幕。删除帧缓冲对象 使用 glDeleteFramebuffers 函数创建一个帧缓冲对象。 代码示例 #include GLES3/gl3.h// 定义帧缓冲对象和渲染缓冲对象的标识符 GLuint framebuffer; GLuint renderbuffer;// 定义纹理对象的标识符 GLuint texture;// 图像的宽度和高度 int screenWidth 1080; int screenHeight 1440;void init() {// 创建并绑定帧缓冲对象glGenFramebuffers(1, framebuffer);glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);// 创建并绑定渲染缓冲对象用于深度和模板信息glGenRenderbuffers(1, renderbuffer);glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);// 分配存储空间glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight);// 将渲染缓冲对象附着到帧缓冲的深度和模板附着点glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);// 创建并绑定纹理对象用于颜色附着点glGenTextures(1, texture);glBindTexture(GL_TEXTURE_2D, texture);// 分配存储空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);// 设置纹理参数glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 将纹理对象附着到帧缓冲的颜色附着点glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);// 检查帧缓冲完整性if (glCheckFramebufferStatus(GL_FRAMEBUFFER) ! GL_FRAMEBUFFER_COMPLETE) {// 处理错误// ...}// 解绑帧缓冲对象glBindFramebuffer(GL_FRAMEBUFFER, 0); }void render() {// 绑定帧缓冲对象glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);// 渲染操作将渲染结果存储在帧缓冲对象中// 解绑帧缓冲对象glBindFramebuffer(GL_FRAMEBUFFER, 0);// 使用帧缓冲对象的渲染结果进行后期处理或直接显示在屏幕上 }三、应用实例 1. 保存纹理数据 利用FBO绑定纹理到颜色附着上便可以方便的把纹理数据读取出来了。 代码示例 void textureToBuffer(int textureId, int x, int y, int width, int height, unsigned char *buffer) {// 创建FBOGLuint fbo[1];glGenFramebuffers(1, fbo);// 绑定glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);// 读取数据glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); // 这里的format和type需要和纹理一致// 解绑和释放glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbindglDeleteFramebuffers(1, fbo); }2. 渲染结果还需后处理 当需要多次渲染渲染结果还需后处理才能完成的任务时此时无需次次都渲染到屏幕上而是可以选择进行一次或多次离屏渲染最终再渲染到屏幕上。 下面看一个图像虚化的例子来感受一下。关于虚化方法这里不做过多解释可以查看其他文章如opencv图像卷积操作和常用的图像滤波函数 方案一单次滤波完成虚化 使用 BoxFilter 的 fragment shader 文件如下 #version 300 es precision mediump float; layout (location 2) uniform sampler2D s_texture; layout (location 3) uniform int u_kernelSize;in vec2 v_texCoor; out vec4 fragColorvec4 boxFilter() {if (u_kernelSize 1) {return texture(s_texture, v_texCoor);}ivec2 texSize textureSize(s_texture, 0);float xStep 1.0 / float(texSize.x);float yStep 1.0 / float(texSize.y);vec4 sum vec4(0.0);int num 0;// 复杂度N^2for (int i -u_kernelSize; i u_kernelSize; i) {for (int j -u_kernelSize; j u_kernelSize; j) {float x v_texCoor.x float(i) * xStep;float y v_texCoor.y float(j) * yStep;sum texture(s_texture, vec2(x, y));num;}}return sum / float(num); }void main() {fragColor boxFilter(); }我们通过对周围像素采样并求平均值的方式获取当前点虚化后的值。由于实现上是嵌套的两层for循环随着 u_kernelSize 的增大其耗时将急剧增大。 方案二横纵方向两次滤波完成虚化 之前我们是对 N*N 的区域进行采样并求平均值其时间复杂度为 N^2。但如果我们先对横向进行一次采样求平均值再对输出的结再进行一次纵向的采样求平均值这样只需要 N*2 即可以达到相同的效果。在高通6225机器上测试 KernelSize 7 时耗时从44ms降低到9ms。 优化后的 fragment shader 文件如下 #version 300 es precision mediump float; layout (location 2) uniform sampler2D s_texture; layout (location 3) uniform int u_kernelSize; layout (location 4) uniform int u_boxFilterType;in vec2 v_texCoor; out vec4 fragColorvec4 boxFilterHorizontal() {if (u_kernelSize 1) {return texture(s_texture, v_texCoor);}ivec2 texSize textureSize(s_texture, 0);float xStep 1.0 / float(texSize.x);vec4 sum vec4(0.0);int num 0;// 复杂度Nfor (int i -u_kernelSize; i u_kernelSize; i) {float x v_texCoor.x float(i) * xStep;sum texture(s_texture, vec2(x, v_texCoor.y));num;}return sum / float(num); }vec4 boxFilterVertical() {if (u_kernelSize 1) {return texture(s_texture, v_texCoor);}ivec2 texSize textureSize(s_texture, 0);float yStep 1.0 / float(texSize.y);vec4 sum vec4(0.0);int num 0;// 复杂度Nfor (int i -u_kernelSize; i u_kernelSize; i) {float y v_texCoor.y float(i) * yStep;if (y 0.0 || y 1.0) {continue;}sum texture(s_texture, vec2(v_texCoor.x, y));num;}return sum / float(num); }void main() {if (u_boxFilterType 1) {fragColor boxFilter();} else if (u_boxFilterType 2) {fragColor boxFilterHorizontal();} else if (u_boxFilterType 3){fragColor boxFilterVertical();} else {fragColor texture(s_texture, v_texCoor); // origin} }如上我们通过指定 u_boxFilterType 的值来实现使用不同的函数来完成滤波当然你也可以写几个不同的 fragment shader 来实现。 部分调用代码如下完整代码链接在文章末尾 public void drawBitmapUseFBO() {if (mGLProgramBlur 0) {Log.e(TAG, mGLProgram not create!);return;}GLES30.glFinish();long startTime System.currentTimeMillis();GLES30.glUseProgram(mGLProgramBlur); // 指定使用的programGLES30.glEnable(GLES30.GL_CULL_FACE); // 启动剔除// init vertexGLES30.glEnableVertexAttribArray(0);GLES30.glEnableVertexAttribArray(1);GLES30.glVertexAttribPointer(0, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer);GLES30.glVertexAttribPointer(1, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mTextureBitmapBuffer);// 先进行boxFilterHorizontal渲染到FBO上绑定颜色附着的纹理GLES30.glActiveTexture(GLES30.GL_TEXTURE0);GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextures[0]);GLES30.glUniform1i(2, 0);GLES30.glUniform1i(3, mKernelSize); // set u_kernelSizeGLES30.glUniform1i(4, 2); // set u_boxFilterType to boxFilterHorizontalGLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBO[0]);GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mTextures[1], 0);GLES30.glDrawElements(GLES30.GL_TRIANGLE_FAN, VERTEX_ORDER.length, GLES30.GL_UNSIGNED_BYTE, mDrawListBuffer);// 再进行boxFilterVertical渲染到屏幕GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); // 解绑即重新绑定回屏幕// GLES30.glVertexAttribPointer(0, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer);// 这次不需要再对纹理进行上下翻转了重新设置下纹理坐标的值GLES30.glVertexAttribPointer(1, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mTextureRotation0Buffer);GLES30.glActiveTexture(GLES30.GL_TEXTURE1);GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextures[1]);GLES30.glUniform1i(2, 1);GLES30.glUniform1i(3, mKernelSize); // set u_kernelSizeGLES30.glUniform1i(4, 3); // set u_boxFilterType to boxFilterVerticalGLES30.glDrawElements(GLES30.GL_TRIANGLE_FAN, VERTEX_ORDER.length, GLES30.GL_UNSIGNED_BYTE, mDrawListBuffer);GLES30.glDisableVertexAttribArray(0);GLES30.glDisableVertexAttribArray(1);GLES30.glFinish();long endTime System.currentTimeMillis();Log.i(TAG, drawBitmapUseFBO time(ms): (endTime - startTime)); }先进行 boxFilterHorizontal渲染到FBO上再进行 boxFilterVertical渲染到屏幕。 3. 多重渲染目标MRT 通常情况下片段着色器只有一个输出颜色。如果想要同时输出多个颜色则可以使用多重渲染目标来实现通过多重渲染目标片段着色器输出多个颜色用于保存RGBA颜色、法线、深度或纹理坐标。MRT 用于多种高级渲染算法中例如延迟着色和快速环境遮蔽估算SSAO。 使用示例 fragment shader 中指定多个输出颜色 #version 300 es precision mediump float; layout (location 2) uniform sampler2D s_texture;in vec2 v_texCoor; out vec4 fragColor1; // 输出到第一个颜色附着点 out vec4 fragColor2; // 输出到第二个颜色附着点 out vec4 fragColor3; // 输出到第三个颜色附着点void main() {vec4 color texture(s_texture, v_texCoor); // originfragColor1 vec4(1.0) - color; // invertedfragColor2 mix(color, vec4(1.0, 0.0, 0.0, 1.0), 0.5); // mix with color redfragColor3 mix(color, vec4(0.0, 0.0, 1.0, 1.0), 0.5); // mix with color blur }部分调用代码如下完整代码链接在文章末尾 public void drawBitmapUseMRT(int targetIndex) {if (mGlProgramMRT 0) {Log.e(TAG, mGLProgram not create!);return;}GLES30.glFinish();long startTime System.currentTimeMillis();Log.d(TAG, drawBitmapUseMRT mGLProgram: mGlProgramMRT);GLES30.glUseProgram(mGlProgramMRT); // 指定使用的programGLES30.glEnable(GLES30.GL_CULL_FACE); // 启动剔除// init vertexGLES30.glEnableVertexAttribArray(0);GLES30.glEnableVertexAttribArray(1);GLES30.glVertexAttribPointer(0, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer);GLES30.glVertexAttribPointer(1, VERTEX_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, mTextureBitmapBuffer);// bind textureGLES30.glActiveTexture(GLES30.GL_TEXTURE0);GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextures[0]);GLES30.glUniform1i(2, 0);// bind FBO and color attachmentGLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBO[0]);GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mTextures[1], 0);GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT1, GLES30.GL_TEXTURE_2D, mTextures[2], 0);GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT2, GLES30.GL_TEXTURE_2D, mTextures[3], 0);// 假设有两个颜色附着点分别对应 GL_COLOR_ATTACHMENT0 和 GL_COLOR_ATTACHMENT1int drawBuffers[] { GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_COLOR_ATTACHMENT1, GLES30.GL_COLOR_ATTACHMENT2 };// 将颜色附着点指定给帧缓冲对象GLES30.glDrawBuffers(drawBuffers.length, drawBuffers, 0);GLES30.glDrawElements(GLES30.GL_TRIANGLE_FAN, VERTEX_ORDER.length, GLES30.GL_UNSIGNED_BYTE, mDrawListBuffer);GLES30.glFinish();long endTime System.currentTimeMillis();Log.i(TAG, drawBitmapUseMRT time(ms): (endTime - startTime)); }四、示例代码地址 https://github.com/afei-cn/OpenGLSample/tree/master/fbodemo 其中shader代码在 fbodemo/src/main/assets 文件夹下调用代码在 fbodemo/src/main/java/com/afei/fbodemo/JavaDrawer.java 中。
http://www.zqtcl.cn/news/948788/

相关文章:

  • 兰州网站seo技术厂家比较实用的h5网页建设网站
  • 怎样让自己做的网站被百度收录动漫制作软件
  • 西安网站制作哪家公司好怎么向企业推销网站建设
  • 电子商务网站建设新闻深圳坂田网站设计公司有哪些
  • 上海电子商城网站制作wordpress循环该分类子分类
  • 茶山做网站教育网站建设计划书
  • 成品门户网站源码免费海外网络加速器免费
  • 企业网站怎么建设公司深圳企业招聘信息最新招聘信息
  • 天津网站经营性备案下载网站上的表格 怎么做
  • 胶州企业网站设计十大互联网营销公司
  • 视频解析wordpresswordpress 优化版本
  • 柳州网站建设哪家便宜广东省建设厅三库一平台
  • 云南城市建设官方网站wordpress和织梦哪个好
  • 国外企业招聘网站专门做外贸的网站有哪些
  • 陕西交通建设集团网站营销公司是什么意思
  • 网站建设自建与租用区别杭州建设局网站官网
  • 广告公司企业介绍seo研究中心怎么样
  • 苏州网站建设熊掌岳阳做网站哪家好
  • 深圳网站制作公司报价单宝塔做两个网站6
  • 百度站长工具怎么查排名贵港网站制作
  • 运城个人网站建设学校网站建设目的
  • 住房城乡建设部门门户网站购物网站排名大全
  • 手机网站平台江门网站建设模板
  • 做本地网站需要什么资质百度多长时间收录网站
  • 网站建设公司使用图片侵权使用者有无责任夸克免费空间
  • 网站建设制作鸿运通做网站能用python吗
  • 站长源码之家Wordpress 新建标签
  • 太原网站建设详细策划如何建设网站简答题
  • 乡村生态旅游网站建设方案如何做网站的导航栏
  • wordpress百度百科网站开发 seo