ぬの部屋(仮)
nu-no-he-ya
  •      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
           
  • glslとFrameBufferでオブジェクトのIDをレンダリング

    要点

    • R32UIのテクスチャをフレームバッファに関連づける
    • 頂点ごとに用意したIDバッファを頂点バッファとともに有効にする
      (この時glVertexAttribIPointerを使う)
    • フラグメントシェーダで、レンダリング時に色ではなくIDをテクスチャに書き込む
    • glGetTexImageでテクスチャの内容を取得する。この時上下反転をする。

    ソースコード(C++)

    #pragma comment(lib,"glew32.lib")
    
    #include <gl/glew.h>
    #include <GL/glut.h>
    
    #include <vector>
    
    #include <vector>
    #include <sstream>
    #include <fstream>
    #include <algorithm>
    
    
    //////////////////////////////////////////// //フレームバッファへの描画サイズ int width; int height; //フレームバッファ関連のバッファID GLuint ID_fbo; GLuint ID_texture_output; GLuint ID_depth; //////////////////////////////////////////// // 二次元の三角形を四個 GLfloat vtx[4 * 3 * 2]; // 各頂点に設定するID GLuint vID[4 * 3]; //描画するオブジェクト用のバッファのID GLuint ID_Triangles; GLuint ID_Triangle_Index; //////////////////////////////////////////// // シェーダのプログラムID GLuint ID_program_disp; GLuint ID_program_idrender;

    /////////////////////////////////////////// //テクスチャ(ID_texture_output)に書き込んだデータを取り出す領域を用意 std::vector<GLuint> texdata;
    void prepare_shaders(GLuint* programID,const char* fn_vertex, const char* fn_fragment); void prepare_databuffer(); void prepare_framebuffer(); void display(void); //マウスでクリックした位置のオブジェクトIDをコンソールに出力 void mouse(int button, int state, int x, int y) { if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) return; display(); unsigned int id = texdata[width * y + x]; printf("---- %d\n", id); } //ウィンドウサイズ固定用 void keepwindowsize(int w, int h) { glutReshapeWindow(width, height); } /////////////////////////////////////////////////// // エントリポイント int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutMouseFunc(mouse); //フレームバッファで書き込む先の画像サイズを500x500にする width = 500; height = 500; //IDの書き出し先 texdata.resize(width * height, 0); //ウィンドウサイズをフレームバッファの描画サイズと同じにする glutInitWindowSize(width, height); //ウィンドウサイズは固定にしておきたい glutReshapeFunc(keepwindowsize); // glewの初期化 glewInit(); // シェーダ準備 prepare_shaders(&ID_program_disp,"vertex_disp.shader","fragment_disp.shader"); prepare_shaders(&ID_program_idrender,"vertex_id.shader", "fragment_id.shader"); //フレームバッファ準備 prepare_framebuffer(); //データ準備 prepare_databuffer(); glutMainLoop(); return 0; }
     
    void display(void) { {
    //以後の描画はフレームバッファに対して行われる glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); glUseProgram(ID_program_idrender); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width, height); glLoadIdentity(); // 頂点バッファを有効化 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 2, // 1要素の要素数(x,y)で2要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // IDバッファを有効化 glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangle_Index); glVertexAttribIPointer(//バッファが整数の時はglVertexAttribIPointerを使う 1, // シェーダ内のlayoutとあわせる 1, // 1要素の要素数 GLuintが一つで1要素 GL_UNSIGNED_INT, // タイプ 0, // ストライド (void*)0 // 配列バッファオフセット ); glDrawArrays(GL_TRIANGLES, 0, 12); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); /////////////////////////////////////////
    //テクスチャのデータを取り出す

      glBindTexture(GL_TEXTURE_2D, ID_texture_output); glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, &texdata[0]);
        //texdataはデータのIDが入ったwidht*height個のGLuint型配列
    //上下反転 座標系がウィンドウズとOpenGLで上下逆になっている for (int ya = 0; ya < height / 2; ya++) { int yb = height - ya - 1; if (ya == yb)break; for (size_t x = 0; x < width; x++) { int pa = ya * width + x; int pb = yb * width + x; std::swap(texdata[pa], texdata[pb]); } } glFlush();
    } {
    //ここから先は画面に出力する glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(ID_program_disp); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width, height);//ウィンドウサイズをこれに固定している // 頂点バッファ glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 2, // 1要素の要素数(x,y)で2要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); glDrawArrays(GL_TRIANGLES, 0, 12); glDisableVertexAttribArray(0); glFlush();
    } }
    void prepare_databuffer() {
    //////////////////////////////////////////////////////// // 頂点作成 { int ofs_obj = 3 * 2;//一つのオブジェクトのサイズは二次元3頂点 int ofs_vtx = 2;//一つの頂点のサイズは二次元 //三角形1 vtx[(0 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(0 * ofs_obj) + (0 * ofs_vtx) + (1)] = 1.0; vtx[(0 * ofs_obj) + (1 * ofs_vtx) + (0)] = 1.0; //頂点2 vtx[(0 * ofs_obj) + (1 * ofs_vtx) + (1)] = -1.0; vtx[(0 * ofs_obj) + (2 * ofs_vtx) + (0)] = -1.0; //頂点3 vtx[(0 * ofs_obj) + (2 * ofs_vtx) + (1)] = -1.0; //三角形2 vtx[(1 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(1 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.7; vtx[(1 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.7; //頂点2 vtx[(1 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.7; vtx[(1 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.7; //頂点3 vtx[(1 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.7; //三角形3 vtx[(2 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(2 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.4; vtx[(2 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.4; //頂点2 vtx[(2 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.4; vtx[(2 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.4; //頂点3 vtx[(2 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.4; //三角形4 vtx[(3 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(3 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.2; vtx[(3 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.2; //頂点2 vtx[(3 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.2; vtx[(3 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.2; //頂点3 vtx[(3 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.2;
     }
      ////////////////////////////////////////////////////////
    
    // 頂点ID作成 { int ofs_obj = 3;//一つのオブジェクトのサイズは3頂点×1番号 //三角形1 vID[(0 * ofs_obj) + 0 ] = 1; //頂点1 vID[(0 * ofs_obj) + 1 ] = 1; //頂点2 vID[(0 * ofs_obj) + 2 ] = 1; //頂点3 //三角形2 vID[(1 * ofs_obj) + 0 ] = 2; //頂点1 vID[(1 * ofs_obj) + 1 ] = 2; //頂点2 vID[(1 * ofs_obj) + 2 ] = 2; //頂点3 //三角形3 vID[(2 * ofs_obj) + 0 ] = 3; //頂点1 vID[(2 * ofs_obj) + 1 ] = 3; //頂点2 vID[(2 * ofs_obj) + 2 ] = 3; //頂点3 //三角形4 vID[(3 * ofs_obj) + 0 ] = 4; //頂点1 vID[(3 * ofs_obj) + 1 ] = 4; //頂点2 vID[(3 * ofs_obj) + 2 ] = 4; //頂点3 }
    //////////////////////////////////////////////////////// //バッファ作成 glGenBuffers(1, &ID_Triangles); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * 2 * sizeof(GLfloat), vtx, GL_STATIC_DRAW); glGenBuffers(1, &ID_Triangle_Index); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangle_Index); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * sizeof(GLuint), vID, GL_STATIC_DRAW); }
    void prepare_framebuffer() { ////////////////////////////////////////////////////// //フレームバッファの作成 // 削除はglDeleteFrameBuffersを使用する glGenFramebuffers(1, &ID_fbo); glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); ////////////////////////////////////////////////////// { //テクスチャバッファの作成 (ID記録用) // 削除はglDeleteTextures glGenTextures(1, &ID_texture_output); glBindTexture(GL_TEXTURE_2D, ID_texture_output); //テクスチャを転送する。 //ただし最後がnullptrなので実質転送しない glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr); //テクスチャのフィルタリングの設定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } ////////////////////////////////////////////////////// // デプスバッファの作成 // レンダーバッファの一種なので、削除は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); ////////////////////////////////////////////////////// //描画先の設定 // 「GL_COLOR_ATTACHMENT0」 が ID_texture_outputのテクスチャを表すようにする glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ID_texture_output, 0); /////////////////////////////////////////////////// //描画バッファのリストをセットする //この作業によってフラグメントシェーダの(layout=0) out の出力先がテクスチャになる glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); // "1"はDrawBuffersのサイズです。 /////////////////////////////////////////////////// // フレームバッファのエラーチェック。 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return;/*エラーデータ*/ }
    //シェーダのコンパイルとリンクを行う関数 void prepare_shaders(GLuint* programID,const char* fn_vertex, const char* fn_fragment){ GLint Result = GL_FALSE; int InfoLogLength; ////////////////////////////////////////////// ////////////////////////////////////////////// //頂点シェーダ // シェーダを作ります // (作るといっても宣言みたいなもの) GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 std::string VertexShaderCode; std::ifstream VertexShaderStream(fn_vertex, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } //////////////////////////////////////////// // 頂点シェーダをコンパイルします。 printf("Compiling shader : %s\n", fn_vertex); char const* VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //////////////////////////////////////////// // エラーチェック // 頂点シェーダをチェックします。 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == FALSE) { std::vector<char> VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); } ////////////////////////////////////////////// ////////////////////////////////////////////// //フラグメントシェーダ // シェーダを作ります。 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fn_fragment, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } ///////////////////////////////////////////// // フラグメントシェーダをコンパイルします。 printf("Compiling shader : %s\n", fn_fragment); char const* FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); ///////////////////////////////////////////// // フラグメントシェーダをチェックします。 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == GL_FALSE) { std::vector<char> FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); } //////////////////////////////////////////// //////////////////////////////////////////// // プログラムのリンク //////////////////////////////////////// // プログラムをリンクします。 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]); }

    シェーダ (ID書き込み用)

    頂点シェーダ

    #version 460 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in uint aID;
    
    out flat uint index;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0);
      index = aID;
      
    }
    

    フラグメントシェーダ

    #version 460 core
    
    layout(location = 0) out uint UIntIndex;
    
    in flat uint index;
    
    void main()
    {
      UIntIndex = index;
    
    } 
    

    シェーダ (表示用)

    頂点シェーダ

    #version 460 core
    
    layout (location = 0) in vec2 aPos;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    out float c;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos,0.0, 1.0);
      c = abs(aPos.y);
    }
    

    フラグメントシェーダ

    #version 460 core
    
    out vec4 FragColor;
      
    in float c;
    
    void main()
    {
      FragColor = vec4(c,c,c,1);
    } 
    

    実行結果

    マウスで三角形をクリックすると、
    コンソールに三角形のIDが表示される