该原创文章首发于微信公众号:字节流动

什么是 Transform Feedback

Transform Feedback(变换反馈)是在 OpenGLES3.0 渲染管线中,顶点处理阶段结束之后,图元装配和光栅化之前的一个步骤。 Transform Feedback 可以重新捕获即将装配为图元(点,线段,三角形)的顶点,然后你将它们的部分或者全部属性传递到缓存对象。

Transform Feedback 的主要作用是可以将顶点着色器的处理结果输出,并且可以有多个输出,这样可以将大量的向量或矩阵运算交给 GPU 并行处理,这是 OpenGLES 3.0 的新特性。

每个顶点在传递到图元装配阶段时,将所有需要捕获的属性数据记录到一个或者多个缓存对象中,程序可以通过这些缓存读出这些数据,可以将他们用于后续的渲染操作。

Transform Feedback 对象

Transform Feedback 所有状态通过一个 Transform Feedback 对象管理,主要包括以下状态:

  • 用于记录顶点数据的缓存对象;
  • 用于标识缓存对象的计数器;
  • 用于标识 Transform Feedback 当前是否启用的状态量。

Transform Feedback 对象的创建绑定过程和一般的 OpenGLES 对象类似,如 VAO 。

生成和绑定 Transform Feedback 对象:

glGenTransformFeedbacks(1, &m_TransFeedbackObjId);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TransFeedbackObjId);

Transform Feedback 缓存

Transform Feedback 主要用来管理将顶点捕捉到缓存对象的相关状态。这个状态中包含当前连接到的 Transform Feedback 缓存绑定点的缓存对象。可以同时给 Transform Feedback 绑定多个缓存,也可以绑定缓存对象的多个子块,甚至可以将同一个缓存对象不用子块绑定到不同的 Transform Feedback 缓存绑定点上。

创建 Transform Feedback 缓存类似于创建 VBO 。

glGenBuffers(1, &m_TransFeedbackBufId);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_TransFeedbackBufId);
// 设置缓存的大小,输出是一个 3 维向量和一个 2 维向量,一共 6 个顶点,大小为 (3 + 2) * 6 * sizeof(GLfloat)
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (3 + 2) * 6 * sizeof(GLfloat), NULL, GL_STATIC_READ);

接口 glBindBufferBase 将缓存绑定到当前 Transform Feedback 对象。

void glBindBufferBase(GLenum target, GLuint index, Gluint buffer);

其中:

  • target 参数须设置为 GL_TRANSFORM_FEEDBACK_BUFFER;
  • index 必须是当前绑定的 transform feedback 对象的缓存绑定点索引;
  • buffer 表示被绑定的缓存对象的 ID 。

为 Transform Feedback 对象绑定缓冲区对象。

glGenTransformFeedbacks(1, &m_TransFeedbackObjId);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TransFeedbackObjId);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_TransFeedbackBufId); // Specify the index of the binding point within the array specified by target.
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);

Transform Feedback 变量

glTransformFeedbackVaryings 用于指定变换反馈的变量,也就是顶点着色器需要输出的变量。

声明了 2 个变换反馈变量的顶点着色器:

#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
out vec2 v_texCoord;
out vec3 outPos;
out vec2 outTex;
void main()
{                                          gl_Position = a_position;               v_texCoord = a_texCoord;                outPos = vec3(a_position)*3.0; //将位置向量做一个简单运算后输出         outTex = a_texCoord * 3.0;     //将纹理坐标向量做一个简单运算后输出
}

设置变换反馈变量,需要注意的是 glTransformFeedbackVaryings 需要在 glLinkProgram 之前调用。

glAttachShader(program, vertexShaderHandle);
glAttachShader(program, fragShaderHandle);GLchar const * varyings[] = {"outPos", "outTex"};
glTransformFeedbackVaryings(m_ProgramObj, sizeof(varyings)/ sizeof(varyings[0]), varyings, GL_INTERLEAVED_ATTRIBS);glLinkProgram(program);

Transform Feedback 捕获启动和停止

Transform Feedback 可以随时启动、暂停和停止。

glBeginTransformFeedback 用于开始 Transform Feedback ,它的参数是用来设置将要记录的图元类型,如:GL_POINTS、GL_LINES 和 GL_TRIANGLES 。

glPuaseTransformFeedback 暂停 Transform Feedback 对变量的记录,但 Transform Feedback 还是处于启动状态。如果 Transform Feedback 没有启动则 OpenGLES 产生错误。

glResumeTransformFeedback 重新开启一个之前通过 glPuaseTransformFeedback 暂停的变换反馈过程,如果 Transform Feedback 没有启动,或者没有被处于活动状态,则产生OpenGL错误。

glEndTransformFeedback 用来结束 Transform Feedback 过程。

Transform Feedback 缓冲区读取

Transform Feedback 过程结束后,通过 glMapBufferRange 读取缓冲区数据。

//绑定要读取的缓冲区对象
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_TransFeedbackBufId);//读取缓冲区数据
void* rawData = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,  (3 + 2) * 6 * sizeof(GLfloat), GL_MAP_READ_BIT);float *p = (float*)rawData;
for(int i= 0; i< 6; i++)
{LOGCATE("TransformFeedbackSample::Draw() read feedback buffer outPos[%d] = [%f, %f, %f], outTex[%d] = [%f, %f]", i, p[i * 5], p[i * 5 + 1], p[i * 5 + 2], i, p[i * 5 + 3], p[i * 5 + 4]);
}//解绑
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);

Transform Feedback 的使用

Transform Feedback 的一般使用流程:

  1. 设置变换反馈变量;
  2. 创建 Transform Feedback 缓冲区;
  3. 创建 Transform Feedback 对象,并绑定缓冲区;
  4. 启动变换反馈,在绘制结束后停止变换反馈;
  5. 读取 Transform Feedback 缓冲区数据。

总体实现代码:

//1. 设置变换反馈变量;
glAttachShader(program, vertexShaderHandle);
glAttachShader(program, fragShaderHandle);GLchar const * varyings[] = {"outPos", "outTex"};
glTransformFeedbackVaryings(m_ProgramObj, sizeof(varyings)/ sizeof(varyings[0]), varyings, GL_INTERLEAVED_ATTRIBS);glLinkProgram(program);//2. 创建 Transform Feedback 缓冲区;
glGenBuffers(1, &m_TransFeedbackBufId);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_TransFeedbackBufId);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (3 + 2) * 6 * sizeof(GLfloat), NULL, GL_STATIC_READ);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);//3. 创建 Transform Feedback 对象,并绑定缓冲区;
glGenTransformFeedbacks(1, &m_TransFeedbackObjId);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TransFeedbackObjId);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_TransFeedbackBufId);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);//4. 启动变换反馈,在绘制结束后停止变换反馈;
glViewport(0, 0, screenW, screenH);
glUseProgram(m_ProgramObj);
glBindVertexArray(m_VaoId);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);
glUniform1i(m_SamplerLoc, 0);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_TransFeedbackObjId);
glBeginTransformFeedback(GL_TRIANGLES);
glDrawArrays(GL_TRIANGLES, 0, 6);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
glBindVertexArray(GL_NONE);//5. 读取 Transform Feedback 缓冲区数据。
// Read feedback buffer
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_TransFeedbackBufId);
void* rawData = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,  (3 + 2) * 6 * sizeof(GLfloat), GL_MAP_READ_BIT);
float *p = (float*)rawData;
for(int i= 0; i< 6; i++)
{LOGCATE("TransformFeedbackSample::Draw() read feedback buffer outPos[%d] = [%f, %f, %f], outTex[%d] = [%f, %f]", i, p[i * 5], p[i * 5 + 1], p[i * 5 + 2], i, p[i * 5 + 3], p[i * 5 + 4]);
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);

代码执行后读取 Transform Feedback 缓冲区的数据:

E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[0] = [-3.000000, -1.500000, 0.000000], outTex[0] = [0.000000, 3.000000]
E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[1] = [3.000000, -1.500000, 0.000000], outTex[1] = [3.000000, 3.000000]
E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[2] = [-3.000000, 1.500000, 0.000000], outTex[2] = [0.000000, 0.000000]
E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[3] = [3.000000, -1.500000, 0.000000], outTex[3] = [3.000000, 3.000000]
E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[4] = [3.000000, 1.500000, 0.000000], outTex[4] = [3.000000, 0.000000]
E/ByteFlow: TransformFeedbackSample::Draw() read feedback buffer outPos[5] = [-3.000000, 1.500000, 0.000000], outTex[5] = [0.000000, 0.000000]

联系与交流

技术交流、获取源码可以扫码添加我的微信:Byte-Flow ,领取视频教程

NDK OpenGL ES 3.0 开发(七):Transform Feedback相关推荐

  1. NDK OpenGL ES 3.0 开发(一):绘制一个三角形

    该原创文章首发于微信公众号:字节流动 什么是 OpenGLES OpenGLES 全称 OpenGL for Embedded Systems ,是三维图形应用程序接口 OpenGL 的子集,本质上是 ...

  2. NDK OpenGL ES 3.0 开发(二十):3D 模型

    该原创文章首发于微信公众号:字节流动 OpenGLES 3D 模型 OpenGLES 3D 模型本质上是由一系列三角形在 3D 空间(OpenGL 坐标系)中构建而成,另外还包含了用于描述三角形表面的 ...

  3. NDK OpenGL ES 3.0 开发(二十二):PBO

    该原创文章首发于微信公众号:字节流动 PBO 是什么 OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作.PBO 仅用于执行像素传输,不连 ...

  4. NDK OpenGL ES 3.0 开发(八):坐标系统

    该原创文章首发于微信公众号:字节流动 OpenGL 坐标系统 我们知道 OpenGL 坐标系中每个顶点的 x,y,z 坐标都应该在 -1.0 到 1.0 之间,超出这个坐标范围的顶点都将不可见. 将一 ...

  5. NDK OpenGL ES 3.0 开发(四):VBO、EBO 和 VAO

    该原创文章首发于微信公众号:字节流动 VBO 和 EBO VBO(Vertex Buffer Object)是指顶点缓冲区对象,而 EBO(Element Buffer Object)是指图元索引缓冲 ...

  6. NDK OpenGL ES 3.0 开发(十七):相机基础滤镜

    该原创文章首发于微信公众号:字节流动 相机基础滤镜 上文中我们通过 ImageReader 获取到 Camera2 预览的 YUV 数据,然后利用 OpenGLES 渲染实现相机预览,这一节将利用 G ...

  7. win7下搭建opengl es 2.0开发环境

    原文  http://codingnow.cn/opengles/1501.html 主题 OpenGL ES Windows 7 1. 下载AMD的OpenGL ES2.0的模拟器 ,下载地址:  ...

  8. OpenGL ES 3.0 开发(三):YUV 渲染

    该原创文章首发于微信公众号:字节流动 YUV 渲染原理 前面文章一文掌握 YUV 图像的基本处理介绍了 YUV 常用的基本格式,本文以实现 NV21/NV12 的渲染为例. 前文提到,YUV 图不能直 ...

  9. 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一第6章 让场景更逼真——光照效果...

    本节书摘来异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.1节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社 ...

最新文章

  1. golang的time包:时间字符串和时间戳的相互转换
  2. 2017年秋季个人阅读计划
  3. word2vec 构建中文词向量
  4. matplotlib 横坐标少了一个点_比 matplotlib 效率高十倍的数据可视化神器
  5. CMOS图像传感器——TOF 图像传感器
  6. 2021-2025年中国电子风扇速度控制器行业市场供需与战略研究报告
  7. iOS 网络编程(二)
  8. 文件操作Python
  9. SQL:pgsql中时间戳转换为整数
  10. linux rundeck安装与使用
  11. 开源数据库系统之SQLite3.2.0、FireBird2.0 Alpha-1等
  12. public static void main(String[] args) 是什么意思?
  13. 数据压缩作业一:音频时域频域特性分析(Audacity)及RGB文件熵的计算
  14. 微信公众号授权登录配置
  15. mysql phpmyadmin 安装_phpMyAdmin 安装
  16. 机顶盒ttl无法输入_中兴机顶盒B8601.1T TTL后跑码无法输入指令
  17. 节假日判断工具(Java)
  18. Linux:ftrace: 为什么有些函数没有在available_filter_functions
  19. 给懒懒的Git操作手册
  20. Path In Zigzag Labelled Binary Tree(C++二叉树寻路)

热门文章

  1. 语音识别公司排名YQ5969智能语音识别模块的快速崛起
  2. 【工业机器人】两分钟读懂工业机器人的设计过程
  3. 题解报告`排列组合 (组合 + 牡牛和牝牛 + 方程的解) 7/30
  4. G1-007 小鲁摘苹果 (10 分)(2022/3/15天梯赛校内选拔赛)
  5. 《操作系统》期末考试试卷1
  6. vue百度地图api 获取小区边界值
  7. Total Bummer:透​​视水滴
  8. “温暖中国--贫困民工患病子女生命救助行动”系列活动
  9. node服务器接口不稳定,node服务部署到服务器后,数据接口404
  10. 抖音近期比较火的挤地铁教程+源码