天天看點

NDK OpenGL ES 3.0 開發(七):Transform Feedback什麼是 Transform FeedbackTransform Feedback 的使用聯系與交流

作者:位元組流動

來源:

https://blog.csdn.net/Kennethdroid/article/details/100083599

什麼是 Transform Feedback

Transform Feedback(變換回報)是在 OpenGLES3.0 渲染管線中,頂點處理階段結束之後,圖元裝配和光栅化之前的一個步驟。 Transform Feedback 可以重新捕獲即将裝配為圖元(點,線段,三角形)的頂點,然後你将它們的部分或者全部屬性傳遞到緩存對象。

Transform Feedback 的主要作用是可以将頂點着色器的處理結果輸出,并且可以有多個輸出,這樣可以将大量的向量或矩陣運算交給 GPU 并行處理,這是 OpenGLES 3.0 的新特性。

NDK OpenGL ES 3.0 開發(七):Transform Feedback什麼是 Transform FeedbackTransform Feedback 的使用聯系與交流

每個頂點在傳遞到圖元裝配階段時,将所有需要捕獲的屬性資料記錄到一個或者多個緩存對象中,程式可以通過這些緩存讀出這些資料,可以将他們用于後續的渲染操作。

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什麼是 Transform FeedbackTransform Feedback 的使用聯系與交流

繼續閱讀