スポンサーリンク
#pragma comment(lib,"glew32.lib") #include <gl/glew.h> #include <GL/glut.h> #include <vector> #include <vector> #include <sstream> #include <fstream> #include <algorithm>//////////////////////////////////////////// //フレームバッファへの描画サイズ int width; int height; //フレームバッファ関連のバッファID GLuint ID_fbo; GLuint ID_texture_output; GLuint ID_depth; //////////////////////////////////////////// // 二次元の三角形を四個 GLfloat vtx[4 * 3 * 2]; // 各頂点に設定するID GLuint vID[4 * 3]; //描画するオブジェクト用のバッファのID GLuint ID_Triangles; GLuint ID_Triangle_Index; //////////////////////////////////////////// // シェーダのプログラムID GLuint ID_program_disp; GLuint ID_program_idrender;/////////////////////////////////////////// //テクスチャ(ID_texture_output)に書き込んだデータを取り出す領域を用意 std::vector<GLuint> texdata;void prepare_shaders(GLuint* programID,const char* fn_vertex, const char* fn_fragment); void prepare_databuffer(); void prepare_framebuffer(); void display(void); //マウスでクリックした位置のオブジェクトIDをコンソールに出力 void mouse(int button, int state, int x, int y) { if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) return; display(); unsigned int id = texdata[width * y + x]; printf("---- %d\n", id); } //ウィンドウサイズ固定用 void keepwindowsize(int w, int h) { glutReshapeWindow(width, height); } /////////////////////////////////////////////////// // エントリポイント int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutMouseFunc(mouse); //フレームバッファで書き込む先の画像サイズを500x500にする width = 500; height = 500; //IDの書き出し先 texdata.resize(width * height, 0); //ウィンドウサイズをフレームバッファの描画サイズと同じにする glutInitWindowSize(width, height); //ウィンドウサイズは固定にしておきたい glutReshapeFunc(keepwindowsize); // glewの初期化 glewInit(); // シェーダ準備 prepare_shaders(&ID_program_disp,"vertex_disp.shader","fragment_disp.shader"); prepare_shaders(&ID_program_idrender,"vertex_id.shader", "fragment_id.shader"); //フレームバッファ準備 prepare_framebuffer(); //データ準備 prepare_databuffer(); glutMainLoop(); return 0; }
void display(void) { {//以後の描画はフレームバッファに対して行われる glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); glUseProgram(ID_program_idrender); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width, height); glLoadIdentity(); // 頂点バッファを有効化 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 2, // 1要素の要素数(x,y)で2要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // IDバッファを有効化 glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangle_Index); glVertexAttribIPointer(//バッファが整数の時はglVertexAttribIPointerを使う 1, // シェーダ内のlayoutとあわせる 1, // 1要素の要素数 GLuintが一つで1要素 GL_UNSIGNED_INT, // タイプ 0, // ストライド (void*)0 // 配列バッファオフセット ); glDrawArrays(GL_TRIANGLES, 0, 12); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); ///////////////////////////////////////////テクスチャのデータを取り出すglBindTexture(GL_TEXTURE_2D, ID_texture_output); glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, &texdata[0]);} {//texdataはデータのIDが入ったwidht*height個のGLuint型配列
//上下反転 座標系がウィンドウズとOpenGLで上下逆になっている for (int ya = 0; ya < height / 2; ya++) { int yb = height - ya - 1; if (ya == yb)break; for (size_t x = 0; x < width; x++) { int pa = ya * width + x; int pb = yb * width + x; std::swap(texdata[pa], texdata[pb]); } } glFlush();//ここから先は画面に出力する glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(ID_program_disp); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, width, height);//ウィンドウサイズをこれに固定している // 頂点バッファ glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 2, // 1要素の要素数(x,y)で2要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); glDrawArrays(GL_TRIANGLES, 0, 12); glDisableVertexAttribArray(0); glFlush();} }void prepare_databuffer() {//////////////////////////////////////////////////////// // 頂点作成 { int ofs_obj = 3 * 2;//一つのオブジェクトのサイズは二次元3頂点 int ofs_vtx = 2;//一つの頂点のサイズは二次元 //三角形1 vtx[(0 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(0 * ofs_obj) + (0 * ofs_vtx) + (1)] = 1.0; vtx[(0 * ofs_obj) + (1 * ofs_vtx) + (0)] = 1.0; //頂点2 vtx[(0 * ofs_obj) + (1 * ofs_vtx) + (1)] = -1.0; vtx[(0 * ofs_obj) + (2 * ofs_vtx) + (0)] = -1.0; //頂点3 vtx[(0 * ofs_obj) + (2 * ofs_vtx) + (1)] = -1.0; //三角形2 vtx[(1 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(1 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.7; vtx[(1 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.7; //頂点2 vtx[(1 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.7; vtx[(1 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.7; //頂点3 vtx[(1 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.7; //三角形3 vtx[(2 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(2 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.4; vtx[(2 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.4; //頂点2 vtx[(2 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.4; vtx[(2 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.4; //頂点3 vtx[(2 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.4; //三角形4 vtx[(3 * ofs_obj) + (0 * ofs_vtx) + (0)] = 0.0; //頂点1 vtx[(3 * ofs_obj) + (0 * ofs_vtx) + (1)] = 0.2; vtx[(3 * ofs_obj) + (1 * ofs_vtx) + (0)] = 0.2; //頂点2 vtx[(3 * ofs_obj) + (1 * ofs_vtx) + (1)] = -0.2; vtx[(3 * ofs_obj) + (2 * ofs_vtx) + (0)] = -0.2; //頂点3 vtx[(3 * ofs_obj) + (2 * ofs_vtx) + (1)] = -0.2;}//////////////////////////////////////////////////////// //バッファ作成 glGenBuffers(1, &ID_Triangles); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangles); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * 2 * sizeof(GLfloat), vtx, GL_STATIC_DRAW); glGenBuffers(1, &ID_Triangle_Index); glBindBuffer(GL_ARRAY_BUFFER, ID_Triangle_Index); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * sizeof(GLuint), vID, GL_STATIC_DRAW); }////////////////////////////////////////////////////////// 頂点ID作成 { int ofs_obj = 3;//一つのオブジェクトのサイズは3頂点×1番号 //三角形1 vID[(0 * ofs_obj) + 0 ] = 1; //頂点1 vID[(0 * ofs_obj) + 1 ] = 1; //頂点2 vID[(0 * ofs_obj) + 2 ] = 1; //頂点3 //三角形2 vID[(1 * ofs_obj) + 0 ] = 2; //頂点1 vID[(1 * ofs_obj) + 1 ] = 2; //頂点2 vID[(1 * ofs_obj) + 2 ] = 2; //頂点3 //三角形3 vID[(2 * ofs_obj) + 0 ] = 3; //頂点1 vID[(2 * ofs_obj) + 1 ] = 3; //頂点2 vID[(2 * ofs_obj) + 2 ] = 3; //頂点3 //三角形4 vID[(3 * ofs_obj) + 0 ] = 4; //頂点1 vID[(3 * ofs_obj) + 1 ] = 4; //頂点2 vID[(3 * ofs_obj) + 2 ] = 4; //頂点3 }void prepare_framebuffer() { ////////////////////////////////////////////////////// //フレームバッファの作成 // 削除はglDeleteFrameBuffersを使用する glGenFramebuffers(1, &ID_fbo); glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); ////////////////////////////////////////////////////// { //テクスチャバッファの作成 (ID記録用) // 削除はglDeleteTextures glGenTextures(1, &ID_texture_output); glBindTexture(GL_TEXTURE_2D, ID_texture_output); //テクスチャを転送する。 //ただし最後がnullptrなので実質転送しない glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr); //テクスチャのフィルタリングの設定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } ////////////////////////////////////////////////////// // デプスバッファの作成 // レンダーバッファの一種なので、削除はglDeleteRenderbuffersを使用する glGenRenderbuffers(1, &ID_depth); glBindRenderbuffer(GL_RENDERBUFFER, ID_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ID_depth); ////////////////////////////////////////////////////// //描画先の設定 // 「GL_COLOR_ATTACHMENT0」 が ID_texture_outputのテクスチャを表すようにする glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ID_texture_output, 0); /////////////////////////////////////////////////// //描画バッファのリストをセットする //この作業によってフラグメントシェーダの(layout=0) out の出力先がテクスチャになる glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); // "1"はDrawBuffersのサイズです。 /////////////////////////////////////////////////// // フレームバッファのエラーチェック。 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return;/*エラーデータ*/ }//シェーダのコンパイルとリンクを行う関数 void prepare_shaders(GLuint* programID,const char* fn_vertex, const char* fn_fragment){ GLint Result = GL_FALSE; int InfoLogLength; ////////////////////////////////////////////// ////////////////////////////////////////////// //頂点シェーダ // シェーダを作ります // (作るといっても宣言みたいなもの) GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 std::string VertexShaderCode; std::ifstream VertexShaderStream(fn_vertex, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } //////////////////////////////////////////// // 頂点シェーダをコンパイルします。 printf("Compiling shader : %s\n", fn_vertex); char const* VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //////////////////////////////////////////// // エラーチェック // 頂点シェーダをチェックします。 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 = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fn_fragment, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } ///////////////////////////////////////////// // フラグメントシェーダをコンパイルします。 printf("Compiling shader : %s\n", fn_fragment); char const* FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); ///////////////////////////////////////////// // フラグメントシェーダをチェックします。 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]); } //////////////////////////////////////////// //////////////////////////////////////////// // プログラムのリンク //////////////////////////////////////// // プログラムをリンクします。 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]); }
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in uint aID; out flat uint index; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); index = aID; }
#version 460 core layout(location = 0) out uint UIntIndex; in flat uint index; void main() { UIntIndex = index; }
#version 460 core layout (location = 0) in vec2 aPos; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; out float c; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos,0.0, 1.0); c = abs(aPos.y); }
#version 460 core out vec4 FragColor; in float c; void main() { FragColor = vec4(c,c,c,1); }