ぬの部屋(仮)
nu-no-he-ya
  •   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
           
  • GLSLを試す (6) ワイヤーフレーム表示

    シェーダを使ってワイヤーフレーム表示します。

    原理

    ●Vertex Shaderは各頂点ごとに呼び出される。
    ●Fragment Shaderはピクセルごとに呼び出される

    つまり処理単位が違う。では、

    #version 460 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 2) in vec3 color;//頂点ごとの入力
    
    out vec3 vColor;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0);
      vColor = color;//フラグメントシェーダに出力
    }
    

    というVertex Shaderがあったとき、頂点毎にoutされたvColorはFragment Shader側でどうなっているのか?

    答えは、各頂点でoutされたvColor、つまり三つのvColorの値が、重心座標系で補間されて入力される。

    重心座標系

    描画したい三角形の各頂点にそれぞれ(1,0,0),(0,1,0),(0,0,1)のデータを付加し、それを頂点シェーダで読み取り、そのままフラグメントシェーダに渡すと、勝手に重心座標系で補間された座標値になる。

    つまりフラグメントシェーダ側で、重心座標系で「( 0.01 , 0.0 , 0.0 )未満 or ( 0.0 , 0.01 , 0.0 ) 未満 or ( 0.0 , 0.0 , 0.01 ) 未満」 の領域を塗れば、ワイヤーフレーム表示と同じ状態になる。

    ソースコード

    C言語側

    データ準備

    //バッファとデータ
    typedef GLfloat points_t[3];
    GLuint vertexbuffer;//バッファのIDを格納する変数
    GLuint colorbuffer;//バッファのIDを格納する変数
    GLuint barycentricbuffer;
    points_t position[9];
    points_t color[9];
    points_t barycentric[9];
    
    void set(GLfloat* p, GLfloat a, GLfloat b, GLfloat c) {
      p[0] = a;
      p[1] = b;
      p[2] = c;
    }
    //////////////////////////////////////////////////
    void prepare_buffers() {
    
      // position ... 頂点座標
      // barycentric ... 重心座標系用
      // color ... 色
    
      //三角形1
      set(position[0],  0.0,  0.5, 0);set(barycentric[0], 1, 0, 0);set(color[0], 1, 0, 0);
      set(position[1],  0.5, -0.5, 0);set(barycentric[1], 0, 1, 0);set(color[1], 0, 1, 0);
      set(position[2], -0.5, -0.5, 0);set(barycentric[2], 0, 0, 1);set(color[2], 0, 0, 1);
    
      //三角形2
      set(position[3],  0.0,  0.5, 0);set(barycentric[3], 1, 0, 0);set(color[3], 1, 0, 0);
      set(position[4], -1.0,  0.5, 0);set(barycentric[4], 0, 1, 0);set(color[4], 1, 1, 0);
      set(position[5], -0.5, -0.5, 0);set(barycentric[5], 0, 0, 1);set(color[5], 0, 0, 1);
    
      //三角形3
      set(position[6], -1.0,  0.5, 0); set(barycentric[6], 1, 0, 0); set(color[6], 1, 1, 0);
      set(position[7], -1.5, -0.5, 0); set(barycentric[7], 0, 1, 0); set(color[7], 0, 1, 1);
      set(position[8], -0.5, -0.5, 0); set(barycentric[8], 0, 0, 1); set(color[8], 0, 0, 1);
    
    
      glGenBuffers(1, &vertexbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        position,
        GL_STATIC_DRAW);
    
      glGenBuffers(1, &colorbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        color,
        GL_STATIC_DRAW);
    
      glGenBuffers(1, &barycentricbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        barycentric,
        GL_STATIC_DRAW);
    }
    

    表示

    void display(void)
    {
      glClearColor(0, 0, 0, 1);
      glClear(GL_COLOR_BUFFER_BIT);
    
      glLoadIdentity();
      glTranslated(0.5, 0.0, 0.0);//平行移動
    
      // シェーダを使う
      glUseProgram(ProgramID);
    
      // 頂点バッファ:頂点
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glVertexAttribPointer(
        0,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(x,y,z)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // カラーバッファを有効にする
      glEnableVertexAttribArray(1);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glVertexAttribPointer(
        1,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(r,g,b)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      //重心座標計算用バッファを有効にする
      glEnableVertexAttribArray(2);
      glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer);
      glVertexAttribPointer(
        2,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // 三角形を描きます!
      glDrawArrays(GL_TRIANGLES, 0, 9);
    
      glDisableVertexAttribArray(0);//バッファを無効にする
      glDisableVertexAttribArray(1);
      glDisableVertexAttribArray(2);
    
      glFlush();
    }
    

    シェーダ側

    頂点シェーダ

    #version 460 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 incolor;
    layout (location = 2) in vec3 barycentric;
    
    out vec4 vertexColor;
    out vec3 baryxyz;
    
    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);
      baryxyz = barycentric;
    }
    

    フラグメントシェーダ

    #version 460 core
    
    out vec4 FragColor;
    in vec4 vertexColor;
    
    in vec3 baryxyz;
    
    void main()
    {
      if( baryxyz.x < 0.01 || baryxyz.y < 0.01 || baryxyz.z < 0.01 ){
        FragColor= vec4(1,1,1,1);
      }
      else{
        FragColor = vertexColor;
      }
    } 
    

    改良

    ところが重心座標系の座標値は三角形の形状に依存する。つまり、鋭角三角形などではエッジがちゃんと表示できない。

    鋭角三角形や鈍角三角形でエッジが均一にならない

    フラグメントシェーダの書き換え

    https://tchayen.github.io/wireframes-with-barycentric-coordinates/
    http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/

    上記サイトではfwidthを使って解決している。(解説したいが自分自身がわかっていない)

    #version 460 core
    
    out vec4 FragColor;
    in vec4 vertexColor;
    
    in vec3 baryxyz;
    
    const float lineWidth = 1.0; //エッジの太さ
    
    const vec3 lineColor = vec3(1.0, 1.0, 1.0); //エッジの色
    
    float edgeFactor() {
      vec3 d = fwidth( baryxyz );
      vec3 f = step( d * lineWidth, baryxyz );
      return min( min( f.x, f.y ), f.z );
    }
    
    void main()
    {
      FragColor.rgb = mix(
      
        lineColor,
        vertexColor.xyz,
        edgeFactor()
        
      );
    
    } 
    
    • fwidth( a ) … abs(dFdx( p )) + abs(dFdy( p )) を返す
    • step( a , b ) … 閾値a未満なら0.0,それ以外は1.0を返す
    • mix( x , y , a ) … x(1-a)+y*aを返す

    https://qiita.com/edo_m18/items/71f6064f3355be7e4f45
    https://qiita.com/gam0022/items/1342a91d0a6b16a3a9ba

    実行結果

    ワイヤーフレーム表示

    上記フラグメントシェーダのedgeFactorは、そのピクセルがエッジ該当領域なら0.0を、そうでなければ1.0を返す。

    0.0が帰ってきたらエッジ色で塗り、それ以外のケースではdiscardして着色を破棄するとワイヤーフレーム表示になる。

    フラグメントシェーダ(ワイヤフレーム用)

    #version 460 core
    
    out vec4 FragColor;
    in vec4 vertexColor;
    
    in vec3 baryxyz;
    
    const float lineWidth = 3.0; //エッジの太さ
    
    const vec3 lineColor = vec3(1.0, 1.0, 1.0); //エッジの色
    
    float edgeFactor() {
      vec3 d = fwidth(baryxyz);
      vec3 f = step(d * lineWidth, baryxyz);
      return min(min(f.x, f.y), f.z);
    }
    
    void main()
    {
    
      if( edgeFactor() < 0.1 ){ //0.0ならエッジ。シェーダは詳しくないが浮動小数点を==比較したくな
        FragColor.rgb = lineColor;
      }
      else{
        discard;
      }
    
    }
    

    実行結果

    全体のソースコード(C言語側)

    #pragma warning(disable:4996)
    
    #pragma comment(lib,"glew32.lib")
    
    
    #include <gl/glew.h>
    #include <GL/glut.h>
    
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <algorithm>
    
    
    void init(void);
    void display(void);
    
    int main(int argc, char* argv[])
    {
      glutInit(&argc, argv);
      glutInitDisplayMode(GLUT_RGBA);
      glutCreateWindow(argv[0]);
      glutDisplayFunc(display);
      glewInit(); // glewの初期化
      init();
      glutMainLoop();
      return 0;
    }
    
    void prepare_buffers();
    void prepare_vertex_shader();
    void prepare_fragment_shader();
    void link_program();
    
    
    void init(void)
    {
    
      //頂点データと色情報の作成
      prepare_buffers();
    
      //頂点シェーダの準備
      prepare_vertex_shader();
    
      //フラグメントシェーダの準備
      prepare_fragment_shader();
    
      //プログラムのリンク
      link_program();
    
    }
    
    //バッファとデータ
    typedef GLfloat points_t[3];
    GLuint vertexbuffer;//バッファのIDを格納する変数
    GLuint colorbuffer;//バッファのIDを格納する変数
    GLuint barycentricbuffer;
    points_t position[9];
    points_t color[9];
    points_t barycentric[9];
    
    void set(GLfloat* p, GLfloat a, GLfloat b, GLfloat c) {
      p[0] = a;
      p[1] = b;
      p[2] = c;
    }
    //////////////////////////////////////////////////
    void prepare_buffers() {
    
      // position ... 頂点座標
      // barycentric ... 重心座標系用
      // color ... 色
    
      //三角形1
      set(position[0],  0.0,  0.5, 0);set(barycentric[0], 1, 0, 0);set(color[0], 1, 0, 0);
      set(position[1],  0.5, -0.5, 0);set(barycentric[1], 0, 1, 0);set(color[1], 0, 1, 0);
      set(position[2], -0.5, -0.5, 0);set(barycentric[2], 0, 0, 1);set(color[2], 0, 0, 1);
    
      //三角形2
      set(position[3],  0.0,  0.5, 0);set(barycentric[3], 1, 0, 0);set(color[3], 1, 0, 0);
      set(position[4], -1.0,  0.5, 0);set(barycentric[4], 0, 1, 0);set(color[4], 1, 1, 0);
      set(position[5], -0.5, -0.5, 0);set(barycentric[5], 0, 0, 1);set(color[5], 0, 0, 1);
    
      //三角形3
      set(position[6], -1.0, 0.5, 0); set(barycentric[6], 1, 0, 0); set(color[6], 1, 1, 0);
      set(position[7], -1.5, -0.5, 0); set(barycentric[7], 0, 1, 0); set(color[7], 0, 1, 1);
      set(position[8], -0.5, -0.5, 0); set(barycentric[8], 0, 0, 1); set(color[8], 0, 0, 1);
    
    
      glGenBuffers(1, &vertexbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        position,
        GL_STATIC_DRAW);
    
      glGenBuffers(1, &colorbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        color,
        GL_STATIC_DRAW);
    
      glGenBuffers(1, &barycentricbuffer);
      glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        3 * 9 * sizeof(GLfloat),
        barycentric,
        GL_STATIC_DRAW);
    }
    
    GLuint VertexShaderID;
    
    void prepare_vertex_shader() {
    
      //////////////////////////////////////////////
        // シェーダを作ります
        // (作るといっても宣言みたいなもの)
      VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    
      ////////////////////////////////////////////
      // ファイルから頂点シェーダを読み込みます。
      // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、
      // OpenGL命令は一つも無い。
      const char* vertex_file_path = ".\\vertex.shader";
      std::string VertexShaderCode;
      std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
      if (VertexShaderStream.is_open())
      {
        std::stringstream sstr;
        sstr << VertexShaderStream.rdbuf();
        VertexShaderCode = sstr.str();
        VertexShaderStream.close();
      }
      ////////////////////////////////////////////
      // 頂点シェーダをコンパイルします。
      printf("Compiling shader : %s\n", vertex_file_path);
      char const* VertexSourcePointer = VertexShaderCode.c_str();
      glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
      glCompileShader(VertexShaderID);
    
      ////////////////////////////////////////////
      // エラーチェック
      GLint Result = GL_FALSE;
      int InfoLogLength;
    
      // 頂点シェーダをチェックします。
      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;
    
    void prepare_fragment_shader() {
    
      /////////////////////////////////////////////
      // シェーダを作ります。
      FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
    
      /////////////////////////////////////////////
      // ファイルからフラグメントシェーダを読み込みます。
      const char* fragment_file_path = ".\\fragment.shader";
      std::string FragmentShaderCode;
      std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
      if (FragmentShaderStream.is_open()) {
        std::stringstream sstr;
        sstr << FragmentShaderStream.rdbuf();
        FragmentShaderCode = sstr.str();
        FragmentShaderStream.close();
      }
    
      /////////////////////////////////////////////
      // フラグメントシェーダをコンパイルします。
      printf("Compiling shader : %s\n", fragment_file_path);
      char const* FragmentSourcePointer = FragmentShaderCode.c_str();
      glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
      glCompileShader(FragmentShaderID);
    
      GLint Result = GL_FALSE;
      int InfoLogLength;
    
      /////////////////////////////////////////////
      // フラグメントシェーダをチェックします。
      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]);
      }
    }
    
    GLuint ProgramID;
    
    void link_program() {
    
      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]);
    
    }
    
    void display(void)
    {
      glClearColor(0, 0, 0, 1);
      glClear(GL_COLOR_BUFFER_BIT);
    
      glLoadIdentity();
      glTranslated(0.5, 0.0, 0.0);//平行移動
    
      // シェーダを使う
      glUseProgram(ProgramID);
    
      // 頂点バッファ:頂点
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glVertexAttribPointer(
        0,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(x,y,z)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // カラーバッファを有効にする
      glEnableVertexAttribArray(1);
      glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
      glVertexAttribPointer(
        1,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数(r,g,b)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      //重心座標計算用バッファを有効にする
      glEnableVertexAttribArray(2);
      glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer);
      glVertexAttribPointer(
        2,                  // シェーダ内のlayoutとあわせる
        3,                  // 1要素の要素数
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // 三角形を描きます!
      glDrawArrays(GL_TRIANGLES, 0, 9);
    
      glDisableVertexAttribArray(0);//バッファを無効にする
      glDisableVertexAttribArray(1);
    
      glFlush();
    }