GLSL #7: Compute Shader
目標
こちらの内容を参考に,とりあえずCompute Shaderが動作することを確認する. 尚,今回実装する内容は,前回(下記参照)までの実装に基づいております.
http://mugichoko.hatenablog.com/entry/2017/05/17/094426mugichoko.hatenablog.com
実装環境
- Windows 10 64bit
- Visual Studio 2015
- GLEW 3.2.1
- 設定方法はこちらを参照
- GLEW 1.13.0
- 設定方法はこちらを参照
- GLM
- 設定方法はこちらを参照
- DevIL
- 設定方法はこちらを参照
レンダリングの流れ
- Compute Shaderを実行し,テクスチャに結果を書き込む
- 1の結果をmodelTexクラスを用いて画面に描画
サンプルプログラム
シェーダプログラムに関しては,ほとんどがこちらの丸コピです. 前回までに作成した以下のプログラムは変更せずそのまま利用します.
- window.h
- window.cpp
- model.h
- model.cpp
- modelTex.h
- modelTex.cpp
shaderUtil.h
前回から,以下を追加. 追加内容は,Compute Shaderをコンパイルするためのインタフェース「initializeProgram」とCompute Shader実装時のインタフェースとなる「compShader」クラス.
// // shaderUtil.h // // // 前回までの記述 // namespace gl { // Interface for compute shader void initializeProgram( GLuint &theProgram, const string &compShaderFileName ); // ----- Compute shader handlar class compShader { protected: GLuint prog; GLuint texID; const GLint internalFormat; const GLsizei width; const GLsizei height; const GLuint depth; const GLenum format; const GLenum type; public: compShader( GLsizei width, GLsizei height, GLuint dpeth, GLint internalFormat, GLenum format, GLenum type, const string compShaderName ); ~compShader(); GLuint getTexID(); GLint getInternalFormat(); GLsizei getWidth(); GLsizei getHeight(); GLenum getFormat(); GLenum getType(); GLuint getDepth(); virtual void execute() = 0; }; }
shaderUtil.cpp
ヘッダファイルに合わせて,前回から,以下を追加.
// // shaderUtil.cpp // #include "shaderUtil.h" // // 前回までの記述 // namespace gl { void initializeProgram( GLuint &theProgram, const string &compShaderFileName ) { try { cout << "[Shader Utility] Making a shader program..." << endl; vector<GLuint> shaderList; // ----- Load shaders stringstream ssComputeShader; readFile(compShaderFileName, ssComputeShader); // ----- Compile shaders shaderList.push_back(createShader(GL_COMPUTE_SHADER, ssComputeShader.str())); // ----- Link the shaders to the program theProgram = createProgram(shaderList); // ----- Delete std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader); cout << "[Shader Utility] ... done!" << endl; } catch (string e) { cerr << "Error: " << e << endl; exit(EXIT_FAILURE); } } // ----- Compute shader handlar compShader::compShader( GLsizei width, GLsizei height, GLuint dpeth, GLint internalFormat, GLenum format, GLenum type, const string compShaderName ) : internalFormat(internalFormat), width(width), height(height), depth(dpeth), format(format), type(type) { // ----- Generate data texture glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, NULL); // ----- Generate a compute shader program initializeProgram(prog, compShaderName); } compShader::~compShader() { glDeleteTextures(1, &texID); glDeleteProgram(prog); } GLuint compShader::getTexID() { return texID; } GLint compShader::getInternalFormat() { return internalFormat; } GLsizei compShader::getWidth() { return width; } GLsizei compShader::getHeight() { return height; } GLenum compShader::getFormat() { return format; } GLenum compShader::getType() { return type; } GLuint compShader::getDepth() { return depth; } }
main.cpp
// // main.cpp // #include <glm/glm.hpp> #include <glm/ext.hpp> #include "OpenGLWrapper/window.h" #include "OpenGLWrapper/shaderUtil.h" #include "OpenGLWrapper/modelTex.h" class MyCompShader : public gl::compShader { public: MyCompShader( int w, int h, const string &compShaderName ) : gl::compShader(w, h, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT, compShaderName) { } void MyCompShader::execute() { static float frame(0.0f); glUseProgram(prog); { glBindImageTexture(0, texID, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat); glUniform1f(glGetUniformLocation(prog, "roll"), (float)frame * 0.01f); glDispatchCompute(width / 32, height / 32, depth); } glUseProgram(0); frame += 0.5f; if (frame >= FLT_MAX - 1.0f) { frame = 0.0f; } } }; class MyWindow : gl::window { private: gl::modelTex *myTex; MyCompShader *myComp; public: MyWindow( int w, int h, const string &name, const string &texFileName, const string &vertShaderName, const string &fragShaderName, const string &compShaderName ): window(w, h, name) { myTex = new gl::modelTex(w, h, vertShaderName, fragShaderName); myComp = new MyCompShader(w, h, compShaderName); } ~MyWindow() { if (myTex) delete myTex; if (myComp) delete myComp; } void render() { // Rendering loop while (!glfwWindowShouldClose(wnd)) { myComp->execute(); glClearColor(0.3f, 0.5f, 0.8f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); myTex->render(myComp->getTexID()); // Swap front and back buffers glfwSwapBuffers(wnd); // Poll for and process events glfwPollEvents(); } } }; int main() { MyWindow wnd( 512, 512, "GLFW 3 Window", "../data/me.jpg", "../shader/modelTex.vert", "../shader/modelTex.frag", "../shader/sample.comp" ); wnd.render(); return 0; }
sample.comp
// // sample.comp // #version 430 uniform float roll; layout (binding = 0) writeonly uniform image2D data; layout (local_size_x = 32, local_size_y = 32) in; void main(void) { ivec2 storePos = ivec2(gl_GlobalInvocationID.xy); float localCoef = length(vec2(256, 256) - vec2(ivec2(gl_GlobalInvocationID.xy))); float val = 0.5 + 0.5 * sin(localCoef * 0.05 + roll); imageStore( data, storePos, vec4(val, val, val, 0) ); }
結果
動作しました!バッチリです.