1頂点入力、1頂点出力のジオメトリシェーダを作って動作確認を行う。
シェーダのコンパイル等は依然作ったprepare_shader.hppを転用する。ただしサンプルとしてはlink_programを使うと読みにくくなるので、ジオメトリシェーダサンプル用に書き直す。
https://suzulang.com/glsl-shader-my-functions-on-cpp
#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; }
#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などを複数実行するときは複数回呼び出す }
#version 460 core in vec4 vColor; out vec4 FragColor; void main() { FragColor = vColor; }
#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; }