ぬの部屋(仮)
nu-no-he-ya
  •   12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • GLSLのシェーダ関係の処理を関数化(C++)

    GLSLを使おうとすると何かとコードが長くなる。状況に合わせて細かい調整ができるところが魅力なのだが練習やテストで毎回書くのは大変なので使いまわせそうなところだけでも関数化しておきたい。

    prepare_shader.hpp

    #pragma once
    
    #include <string>
    #include <vector>
    #include <fstream>
    #include <sstream>
    #include <algorithm>
    #include <functional>
    
    #include <gl/glew.h>
    #pragma comment(lib,"glew32.lib")
    
    
    enum class GLSLCompileCond {
        SUCCESS = 0,
        FILE_OPEN_ERROR = 1,
        COMPILE_ERROR = 2,
        LINK_ERROR = 3
    };
    
    //! @brief シェーダをソースコードからコンパイルする
    //! @param [out] ShaderID 作成したシェーダのID
    //! @param [in] shader_type GL_VERTEX_SHADER , GL_FRAGMENT_SHADER , GL_GEOMETRY_SHADER のいずれか
    //! @param [in] sourcecode シェーダのソースコード
    //! @param [out] error エラー出力先。エラーの内容を確認しないならnullptrを指定
    GLSLCompileCond prepare_shader_bytext(
        GLuint* ShaderID,
        const GLenum shader_type, 
        const char* sourcecode,
        std::string* error = nullptr) {
    
        //////////////////////////////////////////////
          // シェーダを作ります
          // (作るといっても宣言みたいなもの)
        *ShaderID = glCreateShader(shader_type);
    
        glShaderSource(*ShaderID, 1, &sourcecode, NULL);
        glCompileShader(*ShaderID);
    
        ////////////////////////////////////////////
        // エラーチェック
        GLint Result = GL_FALSE;
        int InfoLogLength;
    
        // 頂点シェーダをチェックします。
        glGetShaderiv(*ShaderID, GL_COMPILE_STATUS, &Result);
        glGetShaderiv(*ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
        if (Result == GL_FALSE) {
            if (error) {
                std::vector<char> ShaderErrorMessage(InfoLogLength);
                glGetShaderInfoLog(*ShaderID, InfoLogLength, NULL, &ShaderErrorMessage[0]);
                *error = &ShaderErrorMessage[0];
            }
            return GLSLCompileCond::COMPILE_ERROR;
        }
    
        return GLSLCompileCond::SUCCESS;
    }
    //! @brief ファイルからシェーダを読み込む
    //! @param [out] ShaderID シェーダの出力先
    //! @param [in] shader_type GL_VERTEX_SHADER , GL_FRAGMENT_SHADER , GL_GEOMETRY_SHADERのいずれか
    //! @param [in] shader_file_path シェーダファイルのパス
    //! @param [out] エラーメッセージ出力先
    GLSLCompileCond prepare_shader_byfile(
        GLuint* ShaderID,
        const GLenum shader_type,
        const char* shader_file_path,
        std::string* error = nullptr) {
    
    
        ////////////////////////////////////////////
        // ファイルから頂点シェーダを読み込みます。
        // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、
        // OpenGL命令は一つも無い。
        std::string ShaderCodeText;
        std::ifstream fileinput(shader_file_path, std::ios::in);
        if (fileinput.is_open())
        {
            std::stringstream sstr;
            sstr << fileinput.rdbuf();
            ShaderCodeText = sstr.str();
            fileinput.close();
        }
        else {
            if(error)
                *error = "file open failed";
            return GLSLCompileCond::FILE_OPEN_ERROR;
        }
        ////////////////////////////////////////////
        // 頂点シェーダをコンパイルします。
        return prepare_shader_bytext(ShaderID,shader_type,ShaderCodeText.c_str(),error);
    
    }
    //! @brief シェーダをリンクする
    //! @param [out] ProgramID プログラムIDの保存先
    //! @param [in] ShaderIDs シェーダ一覧
    //! @param [in] geometryprogramparameter ジオメトリシェーダの設定をする関数
    //! @param [out] error エラーメッセージ出力先
    //! @return エラー状態
    GLSLCompileCond link_program(
        GLuint* ProgramID,
        const std::vector<GLuint> ShaderIDs,
        std::function<void(GLuint)> geometryprogramparameter,
        std::string* error = nullptr) {
    
        GLint Result = GL_FALSE;
        int InfoLogLength;
    
        ////////////////////////////////////////
        // プログラムをリンクします。
        *ProgramID = glCreateProgram();
    
        for (GLuint shader : ShaderIDs) {
            glAttachShader(*ProgramID, shader);
        }
    
        if(geometryprogramparameter)
            geometryprogramparameter(*ProgramID);
    
        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]);
    
        if (error) {
            *error = &ProgramErrorMessage[0];
    
            return GLSLCompileCond::LINK_ERROR;
        }
    
        return GLSLCompileCond::SUCCESS;
    }
    //! @brief データを転送
    //! @param [in,out] buffer_name バッファ名へのポインタ
    //! @param [in] data バッファの配列の先頭アドレス
    //! @param [in] databytes データの大きさ
    //! @param [in] usage GL_STATIC_DRAWまたはGL_DYNAMIC_DRAW
    bool prepare_buffer(
        GLuint *buffer_name,
        const void* data,
        const size_t databytes,
        const GLenum usage
        ) {
        
        if (*buffer_name == 0) {
            glGenBuffers(1, buffer_name);
        }
        else {
            glDeleteBuffers(1, buffer_name);
            *buffer_name = 0;
            glGenBuffers(1, buffer_name);
        }
        if (*buffer_name != 0) {
            glBindBuffer(GL_ARRAY_BUFFER, *buffer_name);
            glBufferData(
                GL_ARRAY_BUFFER,
                databytes,
                data,
                usage);
            return true;
        }
        return false;
    
    }
    class EnableAndBindFArrayBuffer {
        GLuint m_layout;
    public:
        //! @brief バッファを有効にする
        //! @param [in] layout
        //! @param [in] buffername
        //! @param [in] element_count
        //! @param [in] datatype
        //! @param [in] normalized
        //! @param [in] stride
        //! @param [in] offset 
        EnableAndBindFArrayBuffer(
            const GLuint layout,
            const GLuint buffername,
            const GLuint element_count,
            const GLenum datatype,
            const GLboolean normalized = false,
            const GLsizei stride = 0,
            const void* offset = nullptr
        ) {
            glEnableVertexAttribArray(layout);
            glBindBuffer(GL_ARRAY_BUFFER, buffername);
            glVertexAttribPointer(
                layout,
                element_count,
                datatype,
                normalized,
                stride,
                offset
            );
            m_layout = layout;
        }
    
        //! @brief デストラクタで終了処理
        ~EnableAndBindFArrayBuffer() {
            glDisableVertexAttribArray(m_layout);
        }
    };
    //! @brief コンテナにデータをpush_backする(4要素)
    template<typename Container>
    void push_4(
        Container& container,
        const typename Container::value_type a,
        const typename Container::value_type b,
        const typename Container::value_type c,
        const typename Container::value_type d) {
        container.push_back(a);
        container.push_back(b);
        container.push_back(c);
        container.push_back(d);
    }
    
    //! @brief コンテナにデータをpush_backする(3要素)
    template<typename Container>
    void push_3(
        Container& container, 
        const typename Container::value_type a, 
        const typename Container::value_type b, 
        const typename Container::value_type c) {
        container.push_back(a);
        container.push_back(b);
        container.push_back(c);
    }
    
    //! @brief コンテナにデータをpush_backする(2要素)
    template<typename Container>
    void push_2(
        Container& container, 
        const typename Container::value_type a,
        const typename Container::value_type b
        ) {
        container.push_back(a);
        container.push_back(b);
    }
    //! @brief 単位行列
    //! @param [out] p 4x4行列
    template<typename T>
    void loadidentity44(T& p) {
        p[0] = 1;
        p[1] = 0;
        p[2] = 0;
        p[3] = 0;
    
        p[4] = 0;
        p[5] = 1;
        p[6] = 0;
        p[7] = 0;
    
        p[8] = 0;
        p[9] = 0;
        p[10] = 1;
        p[11] = 0;
    
        p[12] = 0;
        p[13] = 0;
        p[14] = 0;
        p[15] = 1;
    }
    

    使い方

    main.cpp

    #include <iostream>
    
    #include <Windows.h>
    #include "prepare_shader.hpp"
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    #pragma comment(lib,"glew32.lib")
    
    //ウィンドウの幅と高さ
    int width, height;
    
    GLuint buf_points;
    GLuint buf_colors;
    
    GLfloat mproj[16];
    GLfloat mmodel[16];
    GLuint programID;
    const char* vtxfile = "default.vert";
    const char* fragfile = "default.frag";
    
    
    // シェーダとデータの設定
    void init() {
    
        std::vector<GLfloat> colors;
        std::vector<GLfloat> points;
    
        GLfloat v = 0.8;
    
        push_3(colors, 0, 0, 1);//色 RGB
        push_3(points, 0, 0, 0);//座標 XYZ
    
        push_3(colors, 0, 1, 0);
        push_3(points, 0, v, 0);
    
        push_3(colors, 1, 0, 0);
        push_3(points, v, 0, 0);
    
        prepare_buffer(&buf_points, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW);
        prepare_buffer(&buf_colors, colors.data(), colors.size() * sizeof(GLfloat), GL_STATIC_DRAW);
    
        GLuint vtxShader;
        GLuint flagShader;
    
        std::string verr;
        std::string ferr;
        prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr);
        prepare_shader_byfile(&flagShader, GL_FRAGMENT_SHADER, fragfile, &ferr);
    
        std::cout << verr << std::endl;
        std::cout << ferr << std::endl;
    
        std::string linkerr;
        link_program(&programID, { vtxShader ,flagShader }, nullptr, &linkerr);
    
        loadidentity44(mproj);
        loadidentity44(mmodel);
    }
    
    
    //描画関数
    void disp(void) {
    
        glViewport(0, 0, width, height);
    
        glClearColor(0.2, 0.2, 0.2, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glUseProgram(programID);
        GLuint loc_ModelViewMatrix = glGetUniformLocation(programID, "ModelViewMatrix");
        GLuint loc_ProjectionMatrix = glGetUniformLocation(programID, "ProjectionMatrix");
    
    
        glUniformMatrix4fv(loc_ModelViewMatrix, 1, GL_FALSE, mmodel);
        glUniformMatrix4fv(loc_ProjectionMatrix, 1, GL_FALSE, mproj);
    
        {
            glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
    
            auto bindbufP = EnableAndBindFArrayBuffer(0, buf_points, 3, GL_FLOAT);
            auto bindbufC = EnableAndBindFArrayBuffer(1, buf_colors, 3, GL_FLOAT);
    
            glDrawArrays(GL_POINTS, 0,3);
    
        }
        glFlush();
    }
    
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
        width = w; height = h;
    
        disp();
    }
    
    //エントリポイント
    int main(int argc, char** argv)
    {
        glutInit(&argc, argv);
        glutInitWindowPosition(100, 50);
        glutInitWindowSize(500, 500);
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    
        glutCreateWindow("sample");
        glutDisplayFunc(disp);
        glutReshapeFunc(reshape);
    
        glewInit();
    
        init();
    
        glutMainLoop();
    
        return 0;
    }
    

    default.vert

    #version 460 core
    
    layout (location = 0) in vec3 coord;
    layout (location = 1) in vec3 incolor;
    
    out vec4 vColor;
    
    uniform mat4 ModelViewMatrix;
    uniform mat4 ProjectionMatrix;
    
    void main()
    {
      gl_Position = ProjectionMatrix * ModelViewMatrix * vec4(coord, 1.0);
      vColor = vec4(incolor, 1.0);
      gl_PointSize=30.0;
    }
    

    default.frag

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