平常我們使用的Shader有頂點著色器、幾何著色器、片段著色器,這幾個都是為光柵化圖形渲染服務的,OpenGL 4.3之后新出了一個Compute Shader,用于通用計算并行加速,現在對其進行介紹,
介紹Compute Shader之前需要先介紹一下ImageTexture:
普通的Texture在GLSL中只能進行讀取(sampler采樣獲取資料),寫入則必須在Fragment Shader中寫入幀緩沖系結的附件Texture當前像素中,不能隨意指定位置寫入,并且不能同時讀寫同一張紋理(我試過不行,有博客同樣說不行,應該是不行吧),
1、生成Texture
void WKS::ImageTexture::setupTexture() { glGenTextures(1, &this->textureID); glBindTexture(GL_TEXTURE_2D, this->textureID); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, width, height); // turn off filtering and wrap modes glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glBindTexture(GL_TEXTURE_2D, 0); }
注意,要是用 glTexStorage2D()生成固定大小紋理,不能使用glTexImage2D()
2、生成ImageTexture
glBindImageTexture(0, this->inputTexture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
inputTexture對應1、中生成的Texture紋理ID,第一個引數是ImageTexture系結點,與texture紋理系結點應該不重合,
3、GLSL中宣告
layout (rgba32f, binding = 0) uniform image2D input_image;
補充:ImageTexture底層是Texture,那么在Host上可以進行訪問
a、初始化,傳入資料
void WKS::ImageTexture::Transfer2Texture(float* data) { glBindTexture(GL_TEXTURE_2D, this->textureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, data); }
b、讀取資料
float* WKS::Texture::GetTextureData(GLuint width, GLuint height, GLuint channels, GLuint texID) { float* data = https://www.cnblogs.com/chen9510/p/new float[width * height * channels]; glBindTexture(GL_TEXTURE_2D, texID); if(channels==1) glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, data); if(channels==3) glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT, data); if (channels == 4) glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data); glBindTexture(GL_TEXTURE_2D, 0); return data; }
現在來介紹Compute Shader:
#version 430 core layout (local_size_x=16, local_size_y=16) in; uniform float v[4]; layout (rgba32f, binding = 0) uniform image2D input_image; layout (rgba32f, binding = 1) uniform image2D output_image; shared vec4 mat_shared[16][16]; void main(void) { ivec2 pos=ivec2(gl_GlobalInvocationID.xy); mat_shared[pos.x][pos.y]=imageLoad(input_image,pos); barrier(); vec4 data=mat_shared[pos.x][pos.y]; data.r=v[0]+data.r; data.g=v[1]+data.g; data.b=v[2]+data.b; data.a=v[3]+data.a; imageStore(output_image,pos.xy,data); }
計算由一個一個計算單元完成,layout (local_size_x=16, local_size_y=16) in; 是表示本地作業組的由16*16的計算單元組成,本地作業組可以共享Shadered變數,
多個本地作業組構成全域作業組,由:
glDispatchCompute(1, 1, 1);
啟動計算,引數表示全域作業組的維度(以本地作業組為單位),(1,1,1)表示只有一個本地作業組,
注意:Compute Shader 只有一個階段(渲染一般是vertex+fragment 2個階段),編譯型別選擇GL_COMPUTE_SHADER
Shader(const char* computePath) :programId(0) { std::vector<ShaderFile> fileVec; fileVec.push_back(ShaderFile(GL_COMPUTE_SHADER, computePath)); loadFromFile(fileVec); }
示例:
對一個4*4的vec4矩陣的所有元素加上vec4(0, 0.1,0.2,0.3)
初始化:
void SceneRendering::setupAddData() { int num = 4 * 4 * 4; this->inputData = https://www.cnblogs.com/chen9510/p/new float[num]; for (int i = 0; i < num; i++) inputData[i] = i; for (int i = 0; i < 4; i++) v[i] = i*0.1f; shader_add = new Shader("./Shader/add.comp"); WKS::ImageTexture* texturePtr = new WKS::ImageTexture(4, 4); this->inputTexture = texturePtr->GetTextureID(); this->outputTexture = (new WKS::ImageTexture(4, 4))->GetTextureID(); texturePtr->Transfer2Texture(inputData); }
呼叫Compute Shader:
void SceneRendering::performCompute() { this->shader_add->use(); this->shader_add->setVecN("v", 4, v); glBindImageTexture(0, this->inputTexture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); glBindImageTexture(1, this->outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); glDispatchCompute(1, 1, 1); glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); glFinish(); }
主函式呼叫,結果輸出:
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 我們現在不使用模板緩沖//Compute Shader this->performCompute(); float* data = https://www.cnblogs.com/chen9510/p/WKS::Texture::GetTextureData(4, 4, 4, this->outputTexture); int index = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { std::cout << "(" <<data[index]<<","<<data[index+1]<<","<<data[index+2]<<","<<data[index+3]<< ")" << " "; index += 4; } std::cout << std::endl; } std::cout<< std::endl; free(data);
圖片:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/17733.html
標籤:其他
下一篇:WebGL簡易教程(十四):陰影
