ぬの部屋(仮)
nu-no-he-ya
  •      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
           
  • GLSLを試す (7) シェーディング

    この記事の概要

    モダンOpenGLではシェーディングは光源の座標から何から全部自分でUniform変数として転送した上で、反射角から何から何まで全部自分で計算しなければならない。わかる。わかるがそれは3DCGライブラリとして見たときどうなんだと・・・。


    以下の記事の中のシェーダをコピペしてシェーディングを行う。

    The Basics of GLSL 4.0 Shaders
    https://www.gamedev.net/articles/programming/graphics/the-basics-of-glsl-40-shaders-r2861

    この記事はADS シェーディング(= Ambient Diffuse Specular Shading)のソースコードが載っているのでほぼそのままコピペで使える。

    Implementing per-vertex ambient, diffuse, and specular (ADS) shading
    基本のADSシェーディングのコード
    Using functions in shaders
    基本のを関数化したもの
    Implementing two-sided shading
    裏面も表示できるようにしたもの
    Implementing flat shading
    フラットシェーディング。つまり面法線で反射計算するようなやつ。

    今回はこの中でUsing Functions in Shadersの項目にあるシェーダを使う。

    ただし以下私が書いたCのソースでは各面ごとに頂点を用意してそれぞれの頂点に同じ面法線を用意しているのでスムーズシェーディングのシェーダなんだけれどフラットシェーディングと同じ効果になっている。

    ソースコード

    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);
    
    void timer(int value) {
      glutPostRedisplay();
      glutTimerFunc(20, timer, 0);
    }
    
    int width, height;
    void resize(int w, int h) {
      width = w;
      height = h;
    }
    int main(int argc, char* argv[])
    {
      glutInit(&argc, argv);
      glutInitDisplayMode(GLUT_RGBA);
      glutCreateWindow(argv[0]);
      glutDisplayFunc(display);
      glutReshapeFunc(resize);
      glutTimerFunc(20, timer, 0);
      glewInit(); // glewの初期化
      init();
      glutMainLoop();
      return 0;
    }
    
    void prepare_buffers();
    void prepare_vertex_shader();
    void prepare_fragment_shader();
    void link_program();
    
    void init(void)
    {
      //頂点シェーダの準備
      prepare_vertex_shader();
    
      //フラグメントシェーダの準備
      prepare_fragment_shader();
    
      //プログラムのリンク
      link_program();
    
      //頂点データと色情報の作成
      prepare_buffers();
    
    }
    
    GLuint VertexShaderID;
    void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 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 set(std::vector<GLfloat>& v, GLfloat x, GLfloat y, GLfloat z) { v.push_back(x); v.push_back(y); v.push_back(z); }
     

    //////////////////////////////////////////////////
    // バッファ名 /////////////////////////////////// GLuint buf_v_name; GLuint buf_c_name; GLuint buf_n_name;
    /////////////////////////////////////////////////// // ライトのLocation /////////////////////////////// GLint m_loc_Light_Position; GLint m_loc_Light_La; GLint m_loc_Light_Ld; GLint m_loc_Light_Ls;
    ///////////////////////////////////////////////////
    // マテリアルのLocation /////////////////////////// GLint m_loc_Material_Ka; GLint m_loc_Material_Kd; GLint m_loc_Material_Ks; GLint m_loc_Material_Shiniess;
    ///////////////////////////////////////////////////
    // 変換行列のLocation ///////////////////////////// GLint m_loc_ModelViewMatrix; GLint m_loc_ProjectionMatrix;
     
    ////////////////////////////////////////////////// // バッファ作成 ////////////////////////////////// void prepare_buffers() { std::vector<GLfloat> vtx; std::vector<GLfloat> col; std::vector<GLfloat> nrm;//法線 double size = 1; double m = -size / 2; double p = size / 2; double xp = p; double yp = p; double zp = p; double xm = m; double ym = m; double zm = m; //////////////////////////////////
      // 頂点 //////////////////////////
      //(A)
    
    set(vtx, xp, yp, zm); set(vtx, xp, ym, zm); set(vtx, xm, yp, zm); set(vtx, xm, ym, zm); //(B) set(vtx, xp, yp, zp); set(vtx, xp, ym, zp); set(vtx, xp, yp, zm); set(vtx, xp, ym, zm); //(C) (Aの反対) set(vtx, xm, ym, zp); set(vtx, xp, ym, zp); set(vtx, xm, yp, zp); set(vtx, xp, yp, zp); //(D)(Bの反対) set(vtx, xm, ym, zm); set(vtx, xm, ym, zp); set(vtx, xm, yp, zm); set(vtx, xm, yp, zp); //上 set(vtx, xp, yp, zm); set(vtx, xm, yp, zm); set(vtx, xp, yp, zp); set(vtx, xm, yp, zp); //下 set(vtx, xp, ym, zp); set(vtx, xm, ym, zp); set(vtx, xp, ym, zm); set(vtx, xm, ym, zm); //////////////////////////////////
      // 頂点の色 //////////////////////
    
    //(A) set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); //(B) set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); //(C) (Aの反対) set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); //(D)(Bの反対) set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); //上 set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); //下 set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); ////////////////////////////////// // 頂点法線 ////////////////////// //(A) set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); //(B) set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); //(C) (Aの反対) set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); //(D)(Bの反対) set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); //上 set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); //下 set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); glGenBuffers(1, &buf_v_name); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &vtx[0], GL_STATIC_DRAW ); glGenBuffers(1, &buf_c_name); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &col[0], GL_STATIC_DRAW ); glGenBuffers(1, &buf_n_name); glBindBuffer(GL_ARRAY_BUFFER, buf_n_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &nrm[0], GL_STATIC_DRAW ); glUseProgram(ProgramID); m_loc_Light_Position = glGetUniformLocation(ProgramID, "Light.Position"); m_loc_Light_La = glGetUniformLocation(ProgramID, "Light.La"); m_loc_Light_Ld = glGetUniformLocation(ProgramID, "Light.Ld"); m_loc_Light_Ls = glGetUniformLocation(ProgramID, "Light.Ls"); m_loc_Material_Ka = glGetUniformLocation(ProgramID, "Material.Ka"); m_loc_Material_Kd = glGetUniformLocation(ProgramID, "Material.Kd"); m_loc_Material_Ks = glGetUniformLocation(ProgramID, "Material.Ks"); m_loc_Material_Shiniess = glGetUniformLocation(ProgramID, "Material.Shininess"); m_loc_ModelViewMatrix = glGetUniformLocation(ProgramID, "ModelViewMatrix"); m_loc_ProjectionMatrix = glGetUniformLocation(ProgramID, "ProjectionMatrix"); }
    //////////////////////////////////////////////////////
    //かなり強引に各種行列を求める
    //本当はこんなことをしてはいけない
    
    void calc_matrixes(GLfloat* proj, GLfloat* model) { double asp = width / (double)height; static int r1 = 0; static int r2 = 0; r1 += 1; r2 += 1; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0, 0, -5); glRotatef(r1, 1, 0, 0); glRotatef(r2, 0, 1, 0); glGetFloatv(GL_MODELVIEW_MATRIX, model); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, asp, 0.1, 10); glGetFloatv(GL_PROJECTION_MATRIX, proj); glLoadIdentity(); }
    //////////////////////////////////////////////////////
    //表示
    
    void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // シェーダを使う glUseProgram(ProgramID); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); // 法線バッファを有効にする glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, buf_n_name); glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glViewport(0, 0, width, height); GLfloat mt_projection[16]; GLfloat mt_modelview[16]; //行列を作成 calc_matrixes(mt_projection, mt_modelview); glUniformMatrix4fv(m_loc_ProjectionMatrix, 1, GL_FALSE, mt_projection); glUniformMatrix4fv(m_loc_ModelViewMatrix, 1, GL_FALSE, mt_modelview); glUniform4f(m_loc_Light_Position, 1, 1, 2, 1); glUniform3f(m_loc_Light_La, 0.3, 0.3, 0.3); glUniform3f(m_loc_Light_Ld, 1.0, 1.0, 1.0); glUniform3f(m_loc_Light_Ls, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Ka, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Kd, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Ks, 1.0, 1.0, 1.0); glUniform1f(m_loc_Material_Shiniess, 100.0); // 三角形を描きます! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glFlush(); }

    頂点シェーダ

    #version 460 core
    
    //Using functions in shaders
    
    layout (location = 0) in vec3 VertexPosition;
    layout (location = 1) in vec3 VertexColor;
    layout (location = 2) in vec3 VertexNormal;
    
    
    // CPU側から転送する
    uniform mat4 ModelViewMatrix;
    uniform mat4 ProjectionMatrix;
    
    //この二つはコピペ元ではuniform変数になっているが、面倒なのでGPU側で計算する。
    mat3 NormalMatrix;
    mat4 MVP;
    
    
    out vec3 LightIntensity;
    
    struct LightInfo {
      vec4 Position;// Light position in eye coords.
      vec3 La;      // Ambient light intensity
      vec3 Ld;      // Diffuse light intensity
      vec3 Ls;      // Specular light intensity
    };
    uniform LightInfo Light;
    
    struct MaterialInfo {
      vec3 Ka;         // Ambient reflectivity
      vec3 Kd;         // Diffuse reflectivity
      vec3 Ks;         // Specular reflectivity
      float Shininess; // Specular shininess factor
    };
    uniform MaterialInfo Material;
    
    
    void getEyeSpace( out vec3 norm, out vec4 position )
    {
      norm = normalize( NormalMatrix * VertexNormal);
      position = ModelViewMatrix * vec4(VertexPosition,1.0);
    }
    
    vec3 phongModel( vec4 position, vec3 norm )
    {
      vec3 s = normalize(vec3(Light.Position - position));
      vec3 v = normalize(-position.xyz);
      vec3 r = reflect( -s, norm );
      vec3 ambient = Light.La * Material.Ka;
      float sDotN = max( dot(s,norm), 0.0 );
      vec3 diffuse = Light.Ld * Material.Kd * sDotN;
      vec3 spec = vec3(0.0);
      if( sDotN > 0.0 )
    	  spec = Light.Ls * Material.Ks *
    			 pow( max( dot(r,v), 0.0 ), Material.Shininess );
      return ambient + diffuse + spec;
    }
    
    void main()
    {
    
      //MVPは本来GPUにやらせるような作業じゃないけれど、
      //CPU側のソースコードが無駄に膨れるのを避けるためここで計算する
      MVP = ProjectionMatrix * ModelViewMatrix;
      
      // モデルビュー行列の上3x3の逆行列の転置行列
      // これも多分CPU側でやったほうがいい
      NormalMatrix = transpose(inverse(mat3(ModelViewMatrix)));
    
    
      vec3 eyeNorm;
      vec4 eyePosition;
      // Get the position and normal in eye space
      getEyeSpace(eyeNorm, eyePosition);
    
      // Evaluate the lighting equation.
      LightIntensity = phongModel( eyePosition, eyeNorm );
    
      gl_Position = MVP * vec4(VertexPosition,1.0);
    }	
    

    フラグメントシェーダ

    #version 460 core
    
    out vec4 FragColor;
    
    in vec3 LightIntensity;
    
    void main() {
    	FragColor = vec4(LightIntensity, 1.0);
    }
    

    実行結果1

    色がついていないように見えるのはMaterialで渡したのがグレイスケールなのでそれがそのまま反映されている。オブジェクト単位で同じ色を使うなら素直な方法だが頂点ごとに色指定したい場合はどうやってVertexColorを反映させるか・・・。

    頂点シェーダ(色反映版)

    マテリアルに VertexColor をかけてみた。C++側から渡したMaterialはどれもグレースケールなのでそのまま重みとして使うことができる。

    #version 460 core
    
    //Using functions in shaders
    
    layout (location = 0) in vec3 VertexPosition;
    layout (location = 1) in vec3 VertexColor;
    layout (location = 2) in vec3 VertexNormal;
    
    
    // CPU側から転送する
    uniform mat4 ModelViewMatrix;
    uniform mat4 ProjectionMatrix;
    
    //この二つはコピペ元ではuniform変数になっているが、面倒なのでGPU側で計算する。
    mat3 NormalMatrix;
    mat4 MVP;
    
    
    out vec3 LightIntensity;
    
    struct LightInfo {
      vec4 Position;// Light position in eye coords.
      vec3 La;      // Ambient light intensity
      vec3 Ld;      // Diffuse light intensity
      vec3 Ls;      // Specular light intensity
    };
    uniform LightInfo Light;
    
    struct MaterialInfo {
      vec3 Ka;         // Ambient reflectivity
      vec3 Kd;         // Diffuse reflectivity
      vec3 Ks;         // Specular reflectivity
      float Shininess; // Specular shininess factor
    };
    uniform MaterialInfo Material;
    
    
    void getEyeSpace( out vec3 norm, out vec4 position )
    {
      norm = normalize( NormalMatrix * VertexNormal);
      position = ModelViewMatrix * vec4(VertexPosition,1.0);
    }
    
    vec3 phongModel( vec4 position, vec3 norm )
    {
      vec3 s = normalize(vec3(Light.Position - position));
      vec3 v = normalize(-position.xyz);
      vec3 r = reflect( -s, norm );
      vec3 ambient = Light.La * Material.Ka * VertexColor;
      float sDotN = max( dot(s,norm), 0.0 );
      vec3 diffuse = Light.Ld * Material.Kd * VertexColor * sDotN;
      vec3 spec = vec3(0.0);
      if( sDotN > 0.0 )
    	  spec = Light.Ls * Material.Ks *
    			 pow( max( dot(r,v), 0.0 ), Material.Shininess );
      return ambient + diffuse + spec;
    }
    
    void main()
    {
    
      //MVPは本来GPUにやらせるような作業じゃないけれど、
      //CPU側のソースコードが無駄に膨れるのを避けるためここで計算する
      MVP = ProjectionMatrix * ModelViewMatrix;
      
      // モデルビュー行列の上3x3の逆行列の転置行列
      // これも多分CPU側でやったほうがいい
      NormalMatrix = transpose(inverse(mat3(ModelViewMatrix)));
    
    
      vec3 eyeNorm;
      vec4 eyePosition;
      // Get the position and normal in eye space
      getEyeSpace(eyeNorm, eyePosition);
    
      // Evaluate the lighting equation.
      LightIntensity = phongModel( eyePosition, eyeNorm );
    
      gl_Position = MVP * vec4(VertexPosition,1.0);
    }	
    

    glsl+GL_TRIANGLE_STRIPでCube

    GL_QUADが非推奨になったらしいので(知ってた)GL_TRIANGLE_STRIPで立方体を描きます。

    これをやる理由はシェーディングをやりたいんだけどある程度まともな形をしてないと見ても評価ができないから。

    インデクスバッファつかうのが正しいのだろうけれどまだできないので面ごとに描きます。

    実行結果

    ※矢印は別

    データ定義

    データ定義用関数

    void set(std::vector<GLfloat>& v, GLfloat x, GLfloat y, GLfloat z) {
      v.push_back(x);
      v.push_back(y);
      v.push_back(z);
    }
    

    データ定義部分

      std::vector<GLfloat> vtx;
      std::vector<GLfloat> col;
    
      double width = 1;
      double m = -width / 2;
      double p = width / 2;
      double xp = p;
      double yp = p;
      double zp = p;
      double xm = m;
      double ym = m;
      double zm = m;
      //(A)
      set(vtx,xp, yp, zm);
      set(vtx,xp, ym, zm);
      set(vtx,xm, yp, zm);
      set(vtx,xm, ym, zm);
      //(B)
      set(vtx, xp, yp, zp);
      set(vtx, xp, ym, zp);
      set(vtx, xp, yp, zm);
      set(vtx, xp, ym, zm);
      //(C) (Aの反対)
      set(vtx, xm, ym, zp);
      set(vtx, xp, ym, zp);
      set(vtx, xm, yp, zp);
      set(vtx, xp, yp, zp);
      //(D)(Bの反対)
      set(vtx, xm, ym, zm);
      set(vtx, xm, ym, zp);
      set(vtx, xm, yp, zm);
      set(vtx, xm, yp, zp);
    
      //上
      set(vtx, xp, yp, zm);
      set(vtx, xm, yp, zm);
      set(vtx, xp, yp, zp);
      set(vtx, xm, yp, zp);
    
      //下
      set(vtx, xp, ym, zp);
      set(vtx, xm, ym, zp);
      set(vtx, xp, ym, zm);
      set(vtx, xm, ym, zm);
    
      //(A)
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 1.0, 0.0);
      set(col, 0.0, 0.0, 1.0);
      set(col, 1.0, 1.0, 1.0);
    
      //(B)
      set(col, 1.0, 1.0, 0.0);
      set(col, 0.0, 1.0, 1.0);
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 1.0, 0.0);
    
      //(C) (Aの反対)
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 1.0, 1.0);
      set(col, 0.0, 1.0, 0.0);
      set(col, 1.0, 1.0, 0.0);
    
      //(D)(Bの反対)
      set(col, 1.0, 1.0, 1.0);
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 0.0, 1.0);
      set(col, 0.0, 1.0, 0.0);
    
      //上
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 0.0, 1.0);
      set(col, 1.0, 1.0, 0.0);
      set(col, 0.0, 1.0, 0.0);
    
      //下
      set(col, 0.0, 1.0, 1.0);
      set(col, 1.0, 0.0, 0.0);
      set(col, 0.0, 1.0, 0.0);
      set(col, 1.0, 1.0, 1.0);
    
    
      glGenBuffers(1, &buf_v_name);
      glBindBuffer(GL_ARRAY_BUFFER, buf_v_name);
      glBufferData(
        GL_ARRAY_BUFFER,
        4 * 6 * 3 * sizeof(GLfloat),
        &vtx[0],
        GL_STATIC_DRAW
      );
    
      glGenBuffers(1, &buf_c_name);
      glBindBuffer(GL_ARRAY_BUFFER, buf_c_name);
      glBufferData(
        GL_ARRAY_BUFFER,
        4 * 6 * 3 * sizeof(GLfloat),
        &col[0],
        GL_STATIC_DRAW
      );
    

    描画部分

      glUseProgram(m_shader.getProgramID());
      // 頂点バッファ:頂点
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, buf_v_name);
      glVertexAttribPointer(
        0,                  // シェーダ内のlayoutとあわせる
        3, // 1要素の要素数(x,y,z)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
      // カラーバッファを有効にする
      glEnableVertexAttribArray(1);
      glBindBuffer(GL_ARRAY_BUFFER, buf_c_name);
      glVertexAttribPointer(
        1,                  // シェーダ内のlayoutとあわせる
        3, // 1要素の要素数(r,g,b)で3要素
        GL_FLOAT,           // タイプ
        GL_FALSE,           // 正規化しない(データが整数型の時)
        0,                  // ストライド
        (void*)0            // 配列バッファオフセット
      );
    
    
      glEnable(GL_CULL_FACE);
    
      // 三角形を描きます!
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
      glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
      glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
      glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
      glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
      glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
      glDisableVertexAttribArray(0);
      glDisableVertexAttribArray(1);
    
    
      glUseProgram(0);
    

    シェーダ

    両方とも特に変わったことはしていない

    頂点シェーダ

    #version 460 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 color;
    
    //行列
    uniform mat4 gl_ModelViewMatrix;  //モデルビュー行列
    uniform mat4 gl_ProjectionMatrix; //透視投影変換行列
    
    out vec3 c; //色の出力先
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0);
      c = color;
    }
    

    フラグメントシェーダ

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

    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();
    }
    

    GLSLを試す (5) 点の表示(gl_PointSize)

    順序が大幅にずれた感があるが点の表示について。

    • glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); を使う
    • 頂点シェーダgl_PointSize=30.0; と点のサイズを指定する
    • glDrawArrays(GL_POINTS, 0, 5); とGL_POINTSで描画

    バッファの準備

    データの定義

    typedef GLfloat point_t[3]; //モデルの座標用 x y z
    typedef GLfloat color_t[4];//テクスチャ座標用 r g b a
    
    /////////////////////////////////
    //バッファとデータ
    GLuint vertexbufferName;
    point_t vertex[5];
    GLuint colorbufferName;
    color_t color[5];
    

    データの準備

    //////////////////////////////////////////
    //////////////////////////////////////////
    
    vertex[0][0] = -0.7;
    vertex[0][1] =  0.7;
    vertex[0][2] = 0;
    
    vertex[1][0] = -0.7;
    vertex[1][1] = -0.7;
    vertex[1][2] = 0;
    
    vertex[2][0] =  0.7;
    vertex[2][1] = -0.7;
    vertex[2][2] = 0;
    
    vertex[3][0] = +0.7;
    vertex[3][1] = +0.7;
    vertex[3][2] = 0;
    
    vertex[4][0] = 0;
    vertex[4][1] = 0;
    vertex[4][2] = 0;
    
    
    //////////////////////////////////////////
    //////////////////////////////////////////
    color[0][0] = 1.0;
    color[0][1] = 0.0;
    color[0][2] = 0.0;
    color[0][3] = 1.0;//α
    
    color[1][0] = 0.0;
    color[1][1] = 1.0;
    color[1][2] = 0.0;
    color[1][3] = 1.0;//α
    
    color[2][0] = 0.0;
    color[2][1] = 0.0;
    color[2][2] = 1.0;
    color[2][3] = 1.0;//α
    
    color[3][0] = 1.0;
    color[3][1] = 0.0;
    color[3][2] = 1.0;
    color[3][3] = 1.0;//α
    
    color[4][0] = 1.0;
    color[4][1] = 1.0;
    color[4][2] = 1.0;
    color[4][3] = 1.0;//α
    
    //////////////////////////////////////////
    //////////////////////////////////////////
    
    glGenBuffers(1, &vertexbufferName);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbufferName);
    glBufferData(GL_ARRAY_BUFFER, 3 * 5 * sizeof(GLfloat), vertex, GL_STATIC_DRAW);
    
    glGenBuffers(1, &colorbufferName);
    glBindBuffer(GL_ARRAY_BUFFER, colorbufferName);
    glBufferData(GL_ARRAY_BUFFER, 4 * 5 * sizeof(GLfloat), color, GL_STATIC_DRAW);
    

    描画 (CPU側)

    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);
    
    ////////////////////////////////////////
    ////////////////////////////////////////
    

    頂点シェーダ

    #version 460 core
    
    layout (location = 0) in vec3 vtx;
    layout (location = 1) in vec4 color;
    
    out vec4 vColor;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(vtx, 1.0);
      vColor = color;
      gl_PointSize=30.0; // 頂点のサイズ(ピクセル)
    }
    

    フラグメントシェーダ

    #version 460 core
    
    out vec4 FragColor;
    
    in vec4 vColor;
    
    void main()
    {
      FragColor = vColor;
    
    }
    

    実行結果

    C++CLIでXDocumentでXML

    準備

    参照の追加

    System::XML::Linqをリンクする

    1. プロジェクトを右クリック
    2. 追加→参照
    3. アセンブリ→System.Xml.Linqをチェック
    4. OKボタン

    名前空間

    以下を先頭に追加

    using namespace System::Xml::Linq;

    使い方

    XML書き出し

    書き出しコード

    using namespace System::Xml::Linq;
    
    int main(array<System::String^>^ args)
    {
    
      // ② 追加する要素を作成
      XElement ^man1;
      {
        XElement^ ext;
    
        ext = gcnew XElement("その他");
        ext->Add(gcnew XElement("特技", L"昼寝"));
    
        man1 =
          gcnew XElement("個人データ",
            gcnew XElement("名前", "山田太郎"),
            gcnew XElement("年齢", 45),
            gcnew XElement("住所", "愛媛県松山市"),
            ext
          );
      }
    
      // ② 追加する要素を作成
      XElement^ man2;
      {
        XElement^ ext;
        ext = gcnew XElement("その他");
        ext->Add(gcnew XElement("特技", L"懸垂"));
    
        man2 =
          gcnew XElement("個人データ",
            gcnew XElement("名前", "西田花子"),
            gcnew XElement("年齢", 15),
            gcnew XElement("住所", "北海道札幌市"),
            ext
          );
      }
    
      // ② 追加する要素を作成
      XElement^ man3;
      {
        XElement^ ext;
        ext = gcnew XElement("その他");
        ext->Add(gcnew XElement("特技", L"読書"));
    
        man3 =
          gcnew XElement("個人データ",
            gcnew XElement("名前", "岡田広美"),
            gcnew XElement("年齢", 35),
            gcnew XElement("住所", "沖縄県中城村"),
            ext
          );
      }
    
      XElement^ root = gcnew XElement("root");
    
      // ① XDocumentオブジェクトを作成
      XDocument^ alldata = gcnew XDocument(
        gcnew XComment("利用者の全情報"),
        root
      );
    
      // ③ XDocumentにXElementを追加
      root->Add(man1);
      root->Add(man2);
      root->Add(man3);
    
      // ④ ファイル保存
      alldata->Save("C:\\mydata\\others\\個人データ1.xml");
    
    }
    

    書き出し結果

    <?xml version="1.0" encoding="utf-8"?>
    <!--利用者の全情報-->
    <root>
      <個人データ>
        <名前>山田太郎</名前>
        <年齢>45</年齢>
        <住所>愛媛県松山市</住所>
        <その他>
          <特技>昼寝</特技>
        </その他>
      </個人データ>
      <個人データ>
        <名前>西田花子</名前>
        <年齢>15</年齢>
        <住所>北海道札幌市</住所>
        <その他>
          <特技>懸垂</特技>
        </その他>
      </個人データ>
      <個人データ>
        <名前>岡田広美</名前>
        <年齢>35</年齢>
        <住所>沖縄県中城村</住所>
        <その他>
          <特技>読書</特技>
        </その他>
      </個人データ>
    </root>
    

    XML読み込み

    読み込みコード

    using namespace System::Xml::Linq;
    
    int main(array<System::String ^> ^args)
    {
    
      // XMLファイルを開く
      XDocument^ xml = XDocument::Load("C:\\mydata\\others\\個人データ1.xml");
    
      XElement^ root = xml->Element("root");
    
      //イテレータの取得
      System::Collections::Generic::IEnumerable<XElement^>^ 
        xelements = root->Elements();
    
      for each (XElement ^ k in xelements)
      {
        // k には<個人データ>の内容が入っている
        System::String^ name = k->Element("名前")->Value;
        int age = int::Parse(k->Element("年齢")->Value);
        System::String^ addr = k->Element("住所")->Value;
    
        System::String^ adv = k->Element("その他")->Element("特技")->Value;
    
        //読み取った内容表示
        System::Console::WriteLine(name);
        System::Console::WriteLine(age);
        System::Console::WriteLine(addr);
        System::Console::WriteLine(adv);
        System::Console::WriteLine("--------------");
    
      }
    
      return 0;
    }
    

    読み込みコード実行結果

    この記事を書いた理由

    CSharpの情報はたくさん出てくる。そしてそれを真似ればうまくいく。99.9%うまくいく。しかしC++CLIから使う場合CSharpのコードからは必要な情報が読み取りにくい。具体的には型情報と名前空間あたりがさっぱりわからない。そもそもC++CLIなんて積極的に使う言語じゃないから自分の中に技術が蓄積しない。加えて情報が少ない。公式にすらろくに無い。その上CSharpの情報で大抵事足りる。故に逆に一度詰まると基本的なことがわからなくて彷徨うことになる。というか、彷徨った。

    doxygenの@warningと@attentionには何を書くか

    @warningと@attentionの違いが今ひとつわからない。英語を母国語とするものにとっては明確に違うのかもしれない。意味が全然違うとか言われそうだ。しかし私にはわからないので調べてみる。

    PCLのソースコード内を検索検索

    ちょうど手元にあったPCLのソースコードでwarningとattentionを検索してみた。

    attention

    • @attention Holds a reference to the environment it was created from.
    • \attention A second version of this function template exists which explicitly
    • \attention It will be invoked from the new process.
    • \attention alnum is equivalent to /[[:alnum:]]/ in perl. ~alnum is equivalent
    • \attention keep(expr) is equivalent to the perl (?>…) extension.
    • \attention Skipping does not affect how nested regexes are handled because
    • \attention The default implementation doesn’t do proper Unicode
    • \attention Not currently used
    • \attention Since 1.4.0, Eigen matrices are forced to Row Major to increase the efficiency of the algorithms in PCL
    • \attention The input normals given by setInputNormalsSmall and setInputNormalsLarge have
    • @attention untested code
    • \attention The focal length may change, depending whether the depth stream is registered/mapped to the RGB stream or not.
    • \attention its not the system time, thus can not be used directly to synchronize different sensors.
    • \attention The PCD data is \b always stored in ROW major format!
    • \attention This method does not do any bounds checking for the input index

    warning

    • \warning If the launching and the child process use the input, this leads to undefined behaviour.
    • \warning This feature requires boost/process/async.hpp to be included and a reference to boost::asio::io_service to be passed to the launching function.
    • \warning Invalid arguments cause undefined behaviour.
    • \warning Throwing an exception may cause data loss. This will also throw if a small vector resize throws, in which case there will be no data loss.
    • \warning This method will be removed in the future. Use setNegative() instead.
    • \warning The vertices must be valid and unique (each vertex may be contained only once). Not complying with this requirement results in undefined behavior!
    • \warning Please make sure to NOT add or remove elements from the cloud.
    • \warning Does NOT check if the stored mesh pointer is valid. You have to ensure this yourself when constructing the circulator.
    • \warning The vertices must be valid and unique (each vertex may be contained only once). Not complying with this requirement results in undefined behavior!
    • \warning PCLPointCloud2 inserted into the tree must have x,y,z fields, and must be of same type of any other points inserted in the tree
    • @warning Image type changes if a calibration pattern is discovered/lost;
    • @warning This functionality is not supported with the legacy OpenGL backend.

    所感

    @attention … 使う上で考慮しておくべき項目など。たとえば、 @attention untested code などは使ってはいけないとも、使うと問題が起こるとも限らないが、考慮必須の項目である。

    @warning … やってはいけない使い方・問題が起こる条件など。たとえば、
    \warning Invalid arguments cause undefined behaviour. は無効な引数に対して動作保証がないことを示している。

    Windowsにdoxygen+doxywizardをインストール

    最適な解

    Windowsにdoxygenをインストールします。結論を言うと、以下が自分の中で最適。

    1. 公式からインストーラをダウンロード
    2. ダウンロードしたインストーラをUniversal Extractor 2で展開
    3. 中のexeファイルを適切な場所にコピー

    ダウンロード

    http://www.doxygen.nl/download.html

    からダウンロードできるのだけれど、

    doxygen-1.8.15-setup.exe

    と、

    32-bit doxygen binary in a zip (18.2MB) or the 64-bit version

    があって、ここでは、doxygen-1.8.15-setup.exeをダウンロードします。

    なぜかというと、zip版にはdoxywizardが入っていないからです。

    展開

    普通にインストーラからインストールしてもいいのだけれど、勝手にPATH通されたりレジストリをいじられたりとかしたらたまったものではないのでインストーラを手動で展開して中身をほじくり出します。Universal Extractor 2を使います。

    UniExtract.exeを実行したら、 doxygen-1.8.15-setup.exe のパスと展開先を入力してOKします。

    展開された中にあるbinフォルダを適当な場所にコピーします

    doxywizardが起動できたら成功。


    Visual Studio 2019のタイトルバーを復活する

    Visual Studio2019をインストールしたはいいがタイトルバーがメニューバーと一体化してしまった。

    ウィンドウを移動するのにものすごく不便なので元に戻す。

    https://stackoverflow.com/questions/53636350/re-enable-title-bar-in-visual-studio-2019

    1. %LOCALAPPDATA%\Microsoft\VisualStudio\16.0_xxxxxxxx\Settings\CurrentSettings.vssettings
      を開く
    2. <PropertyValue name="IsMinimalVsEnabled">True</PropertyValue>
      という個所を見つける
    3. <PropertyValue name="IsMinimalVsEnabled">False</PropertyValue>
      に変更する

    GL_LUMINANCEの使い方復習

    巷の例がGL_RGBかGL_RGBAばかりなのでGL_LUMINACEを使った例を置いておく。

    データ準備

    typedef GLubyte gray_t;    //テクスチャ用
    typedef GLfloat points_t[3]; //モデルの座標用
    typedef GLfloat texcoord_t[2];//テクスチャ座標用
    
    const int P_COUNT = 4;
    
    //頂点データ
    GLuint vertexbuffer;
    points_t position[P_COUNT];
    
    //テクスチャ座標データ
    texcoord_t texcoord[P_COUNT];
    GLuint texcoordbuffer;
    
    //テクスチャデータ
    gray_t texdata[P_COUNT];
    GLuint textureID;
    
    //////////////////////////////////////////////////
    void prepare_buffers() {
    
      //テクスチャ(画像)作成
      // 2*2の画像
      texdata[0] = 255;
      texdata[1] = 128;
      texdata[2] = 50;
      texdata[3] = 0;
    
      //////////////////////////////////////////
      //////////////////////////////////////////
    
      //頂点座標の定義 (四角形)
      position[0][0] = -0.7;
      position[0][1] = 0.7;
      position[0][2] = 0;
    
      position[1][0] = -0.7;
      position[1][1] = -0.7;
      position[1][2] = 0;
    
      position[2][0] = 0.7;
      position[2][1] = -0.7;
      position[2][2] = 0;
    
      position[3][0] = +0.7;
      position[3][1] = +0.7;
      position[3][2] = 0;
    
      //////////////////////////////////////////
      //////////////////////////////////////////
    
      //テクスチャ座標の定義
      texcoord[0][0] = 0;
      texcoord[0][1] = 1;
    
      texcoord[1][0] = 0;
      texcoord[1][1] = 0;
    
      texcoord[2][0] = 1;
      texcoord[2][1] = 0;
    
      texcoord[3][0] = 1;
      texcoord[3][1] = 1;
    
      //////////////////////////////////////////
      //////////////////////////////////////////
    
      //テクスチャの作成
      // 普通のテクスチャ作成
      glGenTextures(1, &textureID);
      glBindTexture(GL_TEXTURE_2D, textureID);
    
      int TEXWIDTH = 2;  // 2*2の画素数
      int TEXHEIGHT = 2;
    
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    
    
      // テクスチャの割り当て
      glTexImage2D(
    GL_TEXTURE_2D,
    0,
    GL_LUMINANCE,
    TEXWIDTH,
    TEXHEIGHT,
    0, GL_LUMINANCE,
    GL_UNSIGNED_BYTE,
    texdata
    );
    // テクスチャを拡大・縮小する方法の指定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); }

    描画

    void display(void)
    {
      glClearColor(0, 0, 0, 1);
      glClear(GL_COLOR_BUFFER_BIT);
      glDisable(GL_CULL_FACE);//カリングを無効にする
    
    
      ///////////////////////////////////
      // 行列の設定
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(65, 1, 0.1, 10);
    
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslated(0.0, 0.0, -3);
    
    
      ///////////////////////////////////
      // 四角形の描画
    
      glEnable(GL_TEXTURE_2D);
      glBegin(GL_TRIANGLE_FAN);
    
      glTexCoord2fv(texcoord[0]);
      glVertex3fv(position[0]);
    
      glTexCoord2fv(texcoord[1]);
      glVertex3fv(position[1]);
    
      glTexCoord2fv(texcoord[2]);
      glVertex3fv(position[2]);
    
      glTexCoord2fv(texcoord[3]);
      glVertex3fv(position[3]);
    
      glEnd();
    
    
    
    
      glFlush();
    }
    

    描画結果


    GLSLを試す (4) グレイスケールテクスチャを着色する

    グレイスケールデータの定義

    グレイスケール(1画素が輝度値で表現されている)データをテクスチャとして使用することを考える。RGB(A)に変換しないでできれば何かと便利になる。

    グレイスケールデータの定義

    typedef GLshort gray_t;
    const int P_COUNT = 4;
    gray_t texdata[P_COUNT];
    
    //テクスチャ(画像)作成
    // 2*2のグレイスケール画像
    texdata[0] = 255;
    texdata[1] = 128;
    texdata[2] = 50;
    texdata[3] = 0;
    

    GL_R8UI等を使う

    GL_LUMINANCEなどを指定すればよいのだが、これは最近では非推奨らしい。

    代わりに、GL_R8I,GL_R8UI,GL_R16I,GL_R16UI,GL_R32I,GL_R32UI等を使えば、RGBではなくグレイスケールとしてテクスチャを転送できる。

    例1 テクスチャがunsigned charの場合

    glTexImage2D(
      GL_TEXTURE_2D,
      0,
      GL_R8UI,          //8bitのunsinged int
      TEXWIDTH,     //テクスチャ画素数
      TEXHEIGHT,    //テクスチャ画素数
      0,
      GL_RED_INTEGER,   //整数
      GL_UNSIGNED_BYTE, //unsigned の 1byte
    texdata
    );

    例2 テクスチャがsigned shortの場合

    glTexImage2D(
      GL_TEXTURE_2D,
      0,
      GL_R16I,           //16bitのsigned int
      TEXWIDTH,    //テクスチャ画素数
      TEXHEIGHT,   //テクスチャ画素数
      0,
      GL_RED_INTEGER,    //整数
      GL_SHORT,          //signed の 2byte
      texdata
    );
    

    フラグメントシェーダ

    sampler2Dを使うと、データ範囲が0.0~1.0の間で正規化されて取得できる。それでいい時も多いと思うのだが、グレースケールデータの値を正確に参照したい場合は不便というか、元の値を正確に得られる保証がない。そこでisampler2Dを使うと、テクスチャのデータをもとのままで参照できる。

    #version 460 core
    
    out vec4 FragColor; //色の出力はfloatでいい
    
    uniform isampler2D uTex; //データをint型で受け取る。符号なしintのときはusampler2D
      
    in vec2 vTexCoord; //テクスチャ座標
    
    void main()
    {
      int c = texture(uTex,vTexCoord).x;
    
      //分岐はどうのとか今はいい。本題ではない。
      if( c == 255)
          FragColor =vec4( 1.0,0,0,1);
      else if( c == 128)
          FragColor =vec4( 0.0,1.0,0,1);
      else if( c == 50)
          FragColor =vec4( 0.0,0.0,1.0,1);
      else
          FragColor =vec4( float(c)/255.0,float(c)/255.0,float(c)/255.0,1.0);
    }
    
    unsigned byteをそのまま輝度として表示
    (上記 例1)
    unsinged byteに着色して表示
    (上記 例1+上記フラグメントシェーダ)