スポンサーリンク

GLSLを試す (9) Geometry Shader(1)

1頂点入力、1頂点出力のジオメトリシェーダを作って動作確認を行う。

シェーダのコンパイル等は依然作ったprepare_shader.hppを転用する。ただしサンプルとしてはlink_programを使うと読みにくくなるので、ジオメトリシェーダサンプル用に書き直す。

https://suzulang.com/glsl-shader-my-functions-on-cpp

各シェーダ

default.vert

#version 460 core

layout (location = 0) in vec3 coord;
layout (location = 1) in vec3 incolor;

out vec4 vertexColor;

uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;

void main()
{
  gl_Position = ProjectionMatrix * ModelViewMatrix * vec4(coord, 1.0);
  vertexColor = vec4(incolor, 1.0);
  gl_PointSize=30.0;
}

default.geom

#version 460

layout (points) in; //入力は頂点単位
layout (points) out; //出力も頂点単位
layout (max_vertices = 1) out; // 最大出力頂点数

//geometry shaderへの入力は配列で受け取らなければいけない
//ただし名前はvertex shader側のoutと一致させる
in vec4 vertexColor[]; 

// 出力は普通。名前はfragment shader側のinと一致させる
out vec4 vColor;

void main()
{
    // gl_inにデータが入っている。今回は頂点ごとの処理なので要素数1.
    // つまりgl_in[0]のみが有効
    
    gl_Position = gl_in[0].gl_Position;
    gl_PointSize=30.0;
    vColor = vertexColor[0];
    EmitVertex(); // ラスタライザに頂点を送る
    EndPrimitive();//プリミティブの区切り。GL_LINE_STRIPなどを複数実行するときは複数回呼び出す
}

default.frag

#version 460 core

in vec4 vColor;

out vec4 FragColor;

void main()
{
  FragColor = vColor;
} 

C++側

#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";
const char* geomfile = "default.geom";

//! @brief プログラムのリンクを行う(geometryシェーダ使用時)。
//! @details ジオメトリシェーダがある場合はglLinkProgramの前に設定を行わなければいけない。
//! 別に関数を用意した方がわかりやすいのでここではこれを使う
GLSLCompileCond link_program_with_geometry(
    GLuint* ProgramID,
    GLuint vertexShaderID,
    GLuint geometryShaderID,
    GLuint fragmentShaderID,
    std::string* error = nullptr) {

    GLint Result = GL_FALSE;
    int InfoLogLength;

    ////////////////////////////////////////
    // プログラムをリンクします。
    *ProgramID = glCreateProgram();

    glAttachShader(*ProgramID, vertexShaderID);
    glAttachShader(*ProgramID, geometryShaderID);
    glAttachShader(*ProgramID, fragmentShaderID);


    ////////////////////////////////////////
    // ジオメトリシェーダを使うときの設定をここでする
    // この作業は glAttachShaderとglLinkProgramの間に入れる
    glProgramParameteri(*ProgramID, GL_GEOMETRY_VERTICES_OUT, 3);//ジオメトリシェーダからの最大出力頂点数
    glProgramParameteri(*ProgramID, GL_GEOMETRY_INPUT_TYPE, GL_POINTS);//ジオメトリシェーダには頂点が入力される
    glProgramParameteri(*ProgramID, GL_GEOMETRY_OUTPUT_TYPE, GL_POINTS);//ジオメトリシェーダからは頂点が出力される

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

void init() {

    std::vector<GLfloat> colors;
    std::vector<GLfloat> points;

    GLfloat v = 0.5;

    push_3(colors, 1, 0, 0);
    push_3(points, v, 0, 0);

    push_3(colors, 0, 1, 0);
    push_3(points, 0, v, 0);

    push_3(colors, 0, 0, 1);
    push_3(points, 0, 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;
    GLuint geomShader;

    std::string verr;
    std::string ferr;
    std::string gerr;
    prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr);
    prepare_shader_byfile(&flagShader, GL_FRAGMENT_SHADER, fragfile, &ferr);
    prepare_shader_byfile(&geomShader, GL_GEOMETRY_SHADER, geomfile, &gerr);//ジオメトリシェーダのコンパイル

    std::cout << verr << std::endl;
    std::cout << ferr << std::endl;
    std::cout << gerr << std::endl;

    std::string linkerr;
    link_program_with_geometry(
        &programID,
        vtxShader,
        flagShader,
        geomShader,
        &linkerr
    );
    std::cout << linkerr << std::endl;



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

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: