ぬの部屋(仮)
nu-no-he-ya
  •   12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • glFramebufferTexture2D に渡す GL_COLOR_ATTACHMENT0 は何か

    以前フレームバッファをやってみたときに、glFramebufferTexture2D関数を使ったが、第二引数に与えたGL_COLOR_ATTACHMENT0について言及しなかった(気がする)。当時は調べて納得はしていたが改めて読み返して混乱したのでここで明確にしておきたい。

    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
    /* ... */
    
    glGenTextures(1, texture0);
    glGenTextures(1, texture1);
    
    /* ... */
    
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture0, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture1, 0);
    

    このように指定し、フラグメントシェーダ側で以下のように出力する。

    #version 460 core
    
    layout (location = 0) out vec4 DefaultOut;// 0、つまりGL_COLOR_ATTACHMENT0
    layout (location = 1) out vec4 RedOnly; // 1、つまりGL_COLOR_ATTACHMENT1
    
    in vec4 vertexColor;
    
    void main()
    {
      DefaultOut = vertexColor;
      RedOnly = vec4(vertexColor[0],0,0,1);
    
    }
    

    つまり、GL_COLOR_ATTACHMENT0はフラグメントシェーダのlocationを指定している。

    サンプル全体

    #include <memory>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <array>
    
    #include<windows.h>
    #include <gl/glew.h>
    #include "CglfwBase.hpp"
    
    #pragma warning(disable:4996)
    
    #pragma comment(lib,"opengl32.lib")
    #pragma comment(lib,"glew32.lib")
    
    
    //! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] vmax 全てのRGBの中の最大値
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
    void pnmP3_Write(const TCHAR* const fname, const int vmax, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
      
      FILE* fp = _wfopen(fname, L"wb");
      fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax);
    
      size_t k = 0;
      for (size_t i = 0; i < (size_t)height; i++) {
        for (size_t j = 0; j < (size_t)width; j++) {
          fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]);
          k++;
        }
        fprintf(fp, "\n");
      }
    
      fclose(fp);
    }
    //! @brief フレームバッファに関する変数と機能をまとめる
    class FramebufferTest {
    public:
      GLuint ID_texture_0; // テクスチャ1
      GLuint ID_texture_1; // テクスチャ2
    
      GLuint ID_fbo;// フレームバッファ
    
      int width, height;//テクスチャのサイズ
    private:
      GLuint ID_depth;
    
    
      //! @brief テクスチャを一枚作成し、フレームバッファに関連付ける
      void generate_texture(GLuint *texname, GLenum attachment) {
        glGenTextures(1, texname);
    
        glBindTexture(GL_TEXTURE_2D, *texname);
    
        //テクスチャを転送する。
        //ただし最後がnullptrなので実質転送しない
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
    
        //テクスチャのフィルタリングの設定
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
        //描画先の設定
        // attachmentへの書き込みで、texnameに書き込まれるようにする
        glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, *texname, 0);
    
      }

    public:
      // フレームバッファオブジェクトの作成と設定を行う
      // 途中で描画先のテクスチャも作成する
      void prepare(int WIDTH,int HEIGHT) {
        width = WIDTH;
        height = HEIGHT;
    
        //////////////////////////////////////////////////////
        //フレームバッファの作成
        // 削除はglDeleteFrameBuffersを使用する
        glGenFramebuffers(1, &ID_fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo);
    
    
    
        //////////////////////////////////////////////////////
        //テクスチャバッファの作成
        // 削除はglDeleteTextures
        generate_texture(&ID_texture_0, GL_COLOR_ATTACHMENT0);
        generate_texture(&ID_texture_1, GL_COLOR_ATTACHMENT1);
    
        // fragment shaderの
        //  layout (location = 0) ・・・ GL_COLOR_ATTACHMENT0
        //  layout (location = 1) ・・・ GL_COLOR_ATTACHMENT1
        // が書き込み先であることを教える(?)
        GLenum DrawBuffers[2] = { GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 };
        glDrawBuffers(2, DrawBuffers); // "2"はDrawBuffersのサイズです。

    ////////////////////////////////////////////////////// // デプスバッファの作成 // レンダーバッファの一種なので、削除はglDeleteRenderbuffersを使用する glGenRenderbuffers(1, &ID_depth); glBindRenderbuffer(GL_RENDERBUFFER, ID_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ID_depth); /////////////////////////////////////////////////// // フレームバッファのエラーチェック。 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return;/*エラーデータ*/ }
    };
    
    
    class MyWindow :public MyWindowBase {
    
      int width;
      int height;
      FramebufferTest myfb;
    
      GLuint vertexbufferName;
      GLuint colorbufferName;
    
    public:
    
    
      //! @brief glew,glfwの設定 フレームバッファの初期化、シェーダの作成、データの作成
      virtual void setting()override {
    
        glewInit();
        glfwGetFramebufferSize(_window, &width, &height);
    
        //フレームバッファの初期化
        myfb.prepare(width, height);
    
        //シェーダに渡す描画データの作成
        prepare_data();
    
        //シェーダの作成
        prepare_shaders();
      }
    
    
      //! @brief キーイベント。フレームバッファによって書き込んだテクスチャデータをファイルへ出力
      virtual void key(int key, int scancode, int action, int mods)override {  
    
        //テクスチャ(ID_texture_output)に書き込んだデータを取り出す領域を用意
        std::vector<GLubyte> texdata;
        texdata.resize(myfb.width*myfb.height * 3);
    
        ////////////////////////////////////////////////////
        //テクスチャのデータを取り出す
        glBindTexture(GL_TEXTURE_2D, myfb.ID_texture_0);
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &texdata[0]);
        // 取り出したテクスチャをファイルに書き出す
        pnmP3_Write(LR"(C:\test\texture0.ppm)", 255, width, height, texdata.data());
    
        ////////////////////////////////////////////////////
        //テクスチャのデータを取り出す
        glBindTexture(GL_TEXTURE_2D, myfb.ID_texture_1);
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &texdata[0]);
        // 取り出したテクスチャをファイルに書き出す
        pnmP3_Write(LR"(C:\test\texture1.ppm)", 255, width, height, texdata.data());
      }
    
    
      //! @brief 描画関数
      virtual void draw()override
      {
        //以後の描画はフレームバッファに対して行われる
        glBindFramebuffer(GL_FRAMEBUFFER, myfb.ID_fbo);
    
        draw_core();
    
        //以後の描画は画面に対して行われる
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
        draw_core();
    
        glfwSwapBuffers(_window);
    
      }
    
    
      //! @brief 描画関数本体
    void draw_core() { ///////////////////// // 描画 glViewport(0, 0, width, height); glClearColor(0.3, 0.3, 0.3, 1); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(ProgramID); //gl_PointSizeを有効にする glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); // 頂点バッファ glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbufferName); glVertexAttribPointer( 0, // 属性0 3, // 1要素の要素数 x y z GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファ glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbufferName); glVertexAttribPointer( 1, // 属性1 4, // 1要素の要素数 r g b a GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 5頂点を描く glDrawArrays(GL_POINTS, 0, 5); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); // ///////////////////// glFlush(); } GLuint VertexShaderID; GLuint FragmentShaderID; GLuint ProgramID;
      //! @brief シェーダの作成
    //! シェーダコードを直接埋め込んで、compileshaderを呼び出している

    void prepare_shaders() { const char* vshader = R"(
    #version 460 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 incolor;
    
    out vec4 vertexColor;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0);
      vertexColor = vec4(incolor, 1.0);
      gl_PointSize=30.0; // 頂点のサイズ(ピクセル)
    }
    
    )";
        VertexShaderID = compileshader(GL_VERTEX_SHADER, vshader);
    
        const char* fshader = R"(
    
    #version 460 core
    
    layout (location = 0) out vec4 DefaultOut;// 0、つまりGL_COLOR_ATTACHMENT0
    layout (location = 1) out vec4 RedOnly; // 1、つまりGL_COLOR_ATTACHMENT1
    
    //out vec4 FragColor;
      
    in vec4 vertexColor;
    
    void main()
    {
      DefaultOut = vertexColor;
      RedOnly = vec4(vertexColor[0],0,0,1);
    
    }
    )";
    
        FragmentShaderID = compileshader(GL_FRAGMENT_SHADER, fshader);
    
    
        GLint Result = GL_FALSE;
        int InfoLogLength;
    
        ////////////////////////////////////////
        // プログラムをリンクします。
        fprintf(stdout, "Linking program\n");
        ProgramID = glCreateProgram();
        glAttachShader(ProgramID, VertexShaderID);
        glAttachShader(ProgramID, FragmentShaderID);
        glLinkProgram(ProgramID);
    
        ////////////////////////////////////////
        // プログラムをチェックします。
        glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
        glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
        std::vector<char> ProgramErrorMessage((std::max)(InfoLogLength, int(1)));
        glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
        fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
    
    
      }
      //! @brief シェーダに渡す描画データの作成
      void prepare_data() {
    
        using point_t = std::array<GLfloat, 3>; //モデルの座標用 x y z
        using color_t = std::array<GLfloat, 4>;//テクスチャ座標用 r g b a
    
        /////////////////////////////////
        //バッファとデータ
        point_t vertex[5];
        color_t color[5];
        const int elemcount = 5;
        //////////////////////////////////////////
        vertex[0] = { -0.7, 0.7, 0 };
        vertex[1] = { -0.7,-0.7, 0 };
        vertex[2] = { 0.7,-0.7, 0 };
        vertex[3] = { 0.7, 0.7, 0 };
        vertex[4] = { 0  , 0  , 0 };
        color[0] = { 1.0,0.0,0.0,1.0 };
        color[1] = { 0.0,1.0,0.0,1.0 };
        color[2] = { 0.0,0.0,1.0,1.0 };
        color[3] = { 1.0,0.0,1.0,1.0 };
        color[4] = { 1.0,1.0,1.0,1.0 };
        //////////////////////////////////////////
        // バッファの転送
    
        glGenBuffers(1, &vertexbufferName);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbufferName);
        glBufferData(GL_ARRAY_BUFFER, 3 * elemcount * sizeof(GLfloat), vertex, GL_STATIC_DRAW);
    
        glGenBuffers(1, &colorbufferName);
        glBindBuffer(GL_ARRAY_BUFFER, colorbufferName);
        glBufferData(GL_ARRAY_BUFFER, 4 * elemcount * sizeof(GLfloat), color, GL_STATIC_DRAW);
      }
      //! @brief シェーダをコンパイル・リンク
      GLuint compileshader(GLenum type,const char* VertexShaderCode) {
    
        GLuint shaderID;
    
        //////////////////////////////////////////////
          // シェーダを作ります
          // (作るといっても宣言みたいなもの)
        shaderID = glCreateShader(type);
    
        ////////////////////////////////////////////
        // 頂点シェーダをコンパイルします。
        printf("Compiling shader... \n");
        glShaderSource(shaderID, 1, &VertexShaderCode, NULL);
        glCompileShader(shaderID);
    
        ////////////////////////////////////////////
        // エラーチェック
        GLint Result = GL_FALSE;
        int InfoLogLength;
    
        // 頂点シェーダをチェックします。
        glGetShaderiv(shaderID, GL_COMPILE_STATUS, &Result);
        glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
        if (Result == FALSE) {
          std::vector<char> VertexShaderErrorMessage(InfoLogLength);
          glGetShaderInfoLog(shaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
          fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
        }
    
        return shaderID;
      }
    
    
      virtual void framebuffer_size(int _width, int _height)override
      {
        width = _width;
        height = _height;
      }
    
    
    };
    
    
    int main()
    {
    
      MyWindow win;
    
      win.init(600,600,"glfw window");
      win.setting();
    
      win.loop();
    
    }
    

    出力

    画面出力ができたら、キーを何か押すとc:\test\texture0.ppmとtexture1.ppmを出力する。

    画像が逆転しているのはOpenGLは左下原点なので仕方がない。

    画面表示
    C:\test\texture0.ppm
    C:\test\texture1.ppm