*注意 originをオブジェクトの根元にする
*注意 originをオブジェクトの根元にする
[Shift]+右クリックで head,bodyの順に選択し、[Ctrl+P]→"Object"でheadをbodyの子に設定する
書籍 C++テンプレートテクニック 第2版 (επιστημη, 高橋 晶 著)
P130、is_assignable関数の挙動。文章だけだとわかりづらいので図にしてみた。
書籍 C++テンプレートテクニック 第2版 (επιστημη, 高橋 晶 著)
P125、has_iterator関数の挙動(C++11版)。文章だけだとわかりづらいので図にしてみた。
前回は書き出す方をやったので、今回は読み込む方をやる。
#include "pch.h" using namespace System; int main(array<::System::String ^> ^args) { Microsoft::Office::Interop::Word::Application^ word = gcnew Microsoft::Office::Interop::Word::Application(); word->Visible = false; Object^ oMissing = ::System::Reflection::Missing::Value; Object^ oTrue = true; Object^ oFalse = false; // Word文書を開く System::String^ fname = "C:\\test\\out.docx"; Microsoft::Office::Interop::Word::Document^ document = word->Documents->Open(fname, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing); for each(Microsoft::Office::Interop::Word::Paragraph^ par in document->Paragraphs) { Microsoft::Office::Interop::Word::Range^ ran = par->Range; System::String^ str = ran->Text; System::Console::WriteLine(str); } // 文書を閉じる ((Microsoft::Office::Interop::Word::_Document^)(document))->Close(oFalse, oMissing, oMissing); ((Microsoft::Office::Interop::Word::_Application^)word)->Quit(oMissing, oMissing, oMissing); return 0; }
https://gist.github.com/meki/7e8b462a8d36919d778f
https://www.c-sharpcorner.com/article/word-automation-using-C-Sharp/
ざっくり言うと上記なのだけれど、C++CLIの場合はコピペでは到底動かない。
Object^ oMissing = ::System::Reflection::Missing::Value;
Object^ oTrue = true; Object^ oFalse = false;
Object^ filename = ::System::IO::Directory::GetCurrentDirectory() + "\\out.docx";
https://gist.github.com/meki/7e8b462a8d36919d778f
ではSaveAs2の引数はファイル名のみだが、C++CLIでは以下のように全て指定する。
Object^ filename = ::System::IO::Directory::GetCurrentDirectory() + "\\out.docx"; document->SaveAs2( filename, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing );
using namespace Microsoft::Office::Interop::Word;
これはやらない方がいい。
Microsoft::Office::Interop::Word::Systemというのがあり、using namespaceをするとそれと衝突してコンパイルが通らなくなる。
#include "pch.h" using namespace System; /// <summary> /// 文書の末尾位置を取得する. /// </summary> /// <returns></returns> int getLastPosition(Microsoft::Office::Interop::Word::Document^ document) { return document->Content->End - 1; } /// <summary> /// 文書の末尾にテキストを追加する. /// </summary> void addTextSample( Microsoft::Office::Interop::Word::Document^ document, Microsoft::Office::Interop::Word::WdColorIndex color, System::String^ text) { Object^ before = getLastPosition(document); Object^ dce = document->Content->End - 1; Microsoft::Office::Interop::Word::Range^ rng = document->Range(dce, dce); rng->Text += text; Object^ after = getLastPosition(document); document->Range(before, after)->Font->ColorIndex = color; } int main(array<::System::String ^> ^args) { Microsoft::Office::Interop::Word::Application^ word = gcnew Microsoft::Office::Interop::Word::Application(); word->Visible = false; Object^ oMissing = ::System::Reflection::Missing::Value; Microsoft::Office::Interop::Word::Document^ document = word->Documents->Add(oMissing, oMissing, oMissing, oMissing); Object^ oTrue = true; Object^ oFalse = false; //////////////////////////////////////// // テキストを追加 addTextSample(document, Microsoft::Office::Interop::Word::WdColorIndex::wdGreen, "Hello, "); addTextSample(document, Microsoft::Office::Interop::Word::WdColorIndex::wdRed, "World"); //////////////////////////////////////// // 名前を付けて保存 Object^ filename = ::System::IO::Directory::GetCurrentDirectory() + "\\out.docx"; document->SaveAs2( filename, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing ); // 文書を閉じる ((Microsoft::Office::Interop::Word::_Document^)(document))->Close(oFalse, oMissing, oMissing); ((Microsoft::Office::Interop::Word::_Application^)word)->Quit(oMissing, oMissing, oMissing); return 0; }
ざっくり言うとこのような事をしたい
Pixabayあたりから画像を持ってくる
Image by Gordon Johnson from Pixabay
[Shift+A]→[Mesh]→GridでGridを追加し、分割数を50x50等少し大きめにする。
画像をモディファイアで使うため、冒頭の猫の画像を読み込んでおく
場合によってはUVマップを[S]で少しだけ広げておくといい
[Shift+A]→[Armature]→Single Boneを追加
[Shift]+右クリック で、Grid→Boneの順番に選択し、[Ctrl+P]→[With Empty Groups]で親子関係を作る
この作業で、"Bone"という名前の、空のVertex Groupができる。
GridにVertex Weight Editモディファイアを追加
Vertex Weight Edit を以下のように変更する
Weight Paintモードへ行き、猫の形にPaintされていることを確認し、Vertex Weight EditモディファイアをApplyする
一度オブジェクトモードへ戻り、Armatureを選択して[Pose Mode]へ移行する。
ArmatureをZ方向に持ち上げると、頂点が猫の形に持ち上がる。
猫を適度に持ち上げたら、Gridを選択し、モディファイアへ行き、ArmatureをApplyする。
※作業が終わったら、Armatureは[X]で削除して良い
テンキーの[5][1]でXZ平面の平行投影に切り替え、Editモードで[B]の範囲選択などを使っていらない点を削除する。
また、カメラの向きを変えて[C]等を使ってRepeatしてしまったテクスチャの部分を削除する
Edit モードで必要な点を全て選択し、TransformでZをGlobal座標系で0にする
Editモードで[X] → Only Edges & Faces で面を全て消す
(必要なら)レイヤーを変えて、[Shift+A]→[Mesh]→UV Shpere で球を追加し、[S][Z]でつぶして碁石っぽいものを作る。
[Shift]キーを押しながら、
① 碁石
② 猫の頂点群
の順に右ボタンクリックで選択し
[Ctrl + P] → Object で 猫の腸点群(Grid)を親、碁石(Sphere)を子に設定する
続いて、猫(Grid)を選択し、Object→Duplicationで[Verts]を選択する
碁石が大きすぎるので、[S]で縮める
このままだと各オブジェクトは虚像なので、点群(Grid)を選択した状態で、
[Object]→[Apply]→Make Duplicates Real
を選択し、実体化する。
碁盤はめんどくさいので省略
前回の続き。
テンプレートメタプログラミングは何をやっているかさっぱりわからないので少しでも図解をしておきたい。
可変長引数テンプレートクラスのテスト。以下のテンプレートクラスは、
第一テンプレート引数で指定した型の派生型を
第二以降テンプレート引数から探して返す。
#include <iostream>
///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// // テスト用のクラス一覧 class AAA { public: void print() { std::cout << "AAA" << std::endl;} }; class BBB { public: void print() { std::cout << "BBB" << std::endl;} }; class CCC { public: void print() { std::cout << "CCC" << std::endl;} }; class AAADerived :public AAA { public: void print() { std::cout << "AAADerived" << std::endl; } }; class CCCDerived :public CCC { public: void print() { std::cout << "CCCDerived" << std::endl; } }; class DUMMY { public: void print() { std::cout << "指定されていません" << std::endl; } };///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// // クラス選択クラスの本体 template<class Base,class Head, class... Args> struct Search { using type_t = typename std::conditional < std::is_base_of<Base, Head>::value, //判断 Head, typename Search<Base, Args...>::type_t>::type; };// クラス選択クラスの本体(特殊化)
template<class Base, class Head> struct Search<Base,Head> { using type_t = typename std::conditional < std::is_base_of<Base, Head>::value, //判断 Head, DUMMY>::type; }; ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// // クラス選択クラス // 第一テンプレート引数に指定したクラスから派生したクラスを、 // 第二以降テンプレート引数から選択する template<class Base, class... Args> struct TypeDerived { using type_t = typename Search<Base,Args...>::type_t; };//////////////////////////////////////////////////////// //////////////////////////////////////////////////////// // 動作確認 int main() { using T = TypeDerived< AAA,//このクラスの派生クラスを探す BBB, CCCDerived, AAADerived >::type_t; T obj; obj.print(); int i; std::cin >> i; }
普通の感覚だとこんなもんどこに使い道があるのかわからないので使用例を置いておくと、以下のABCクラスでは、AAA,BBB,CCC(及びその派生クラス)をどんな順番で指定してもちゃんと動作する。普通テンプレートに指定する型の順番は(当たり前だが)決まっている。だから何だといわれると困るのでもう一つ、クラス指定が足りなかった場合も、自動的にDUMMYが指定されるのでエラーにならない。
template<class... T> class ABC { public: typename TypeDerived<AAA, T...>::type_t a; typename TypeDerived<BBB, T...>::type_t b; typename TypeDerived<CCC, T...>::type_t c; }; int main() { std::cout << "obj1 ------" << std::endl; ABC<AAA, CCCDerived,BBB> obj1; obj1.a.print(); obj1.b.print(); obj1.c.print(); std::cout << std::endl; std::cout << "obj2 ------" << std::endl; ABC<BBB, CCC, AAADerived> obj2; obj2.a.print(); obj2.b.print(); obj2.c.print(); std::cout << std::endl; std::cout << "obj3 ------" << std::endl; ABC<AAADerived, BBB> obj3; obj3.a.print(); obj3.b.print(); obj3.c.print(); std::cout << std::endl; int i; std::cin >> i; }
obj1 ------
AAA
BBB
CCCDerived
obj2 ------
AAADerived
BBB
CCC
obj3 ------
AAADerived
BBB
指定されていません
#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); }
流れぶった切ってフレームバッファやります。
#pragma warning(disable:4996) #pragma comment(lib,"glew32.lib") #include <gl/glew.h> #include <GL/glut.h> #include <vector> void init(void); void display(void); //フレームバッファへの描画サイズ int width; int height; GLuint ID_fbo; GLuint ID_texture_output; GLuint ID_depth; void prepare_framebuffer() {////////////////////////////////////////////////////// //フレームバッファの作成 // 削除はglDeleteFrameBuffersを使用する glGenFramebuffers(1, &ID_fbo); glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo);////////////////////////////////////////////////////// //テクスチャバッファの作成 // 削除はglDeleteTextures glGenTextures(1, &ID_texture_output); glBindTexture(GL_TEXTURE_2D, ID_texture_output); //テクスチャを転送する。 //ただし最後がnullptrなので実質転送しない glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 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);/////////////////////////////////////////////////// // フレームバッファのエラーチェック。 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return;/*エラーデータ*/ } /////////////////////////////////////////////////// // エントリポイント int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glewInit(); // glewの初期化 //フレームバッファで書き込む先の画像サイズを100x100にする width = 100; height = 100; //フレームバッファ準備 prepare_framebuffer(); glutMainLoop(); return 0; } //ファイル書き込み用の関数 void pnmP3_Write(const char* const fname, const int vmax, const int width, const int height, const unsigned char* const p); void display(void)
{//以後の描画はフレームバッファに対して行われる glBindFramebuffer(GL_FRAMEBUFFER, ID_fbo); glClearColor(1, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); glLoadIdentity(); //普通の描画処理 glBegin(GL_QUADS); glColor3d(1, 0, 0); glVertex2d(-0.7, -0.7); glColor3d(0, 1, 0); glVertex2d( 0.7, -0.7); glColor3d(0, 0, 1); glVertex2d( 0.7, 0.7); glColor3d(1, 1, 1); glVertex2d(-0.7, 0.7); glEnd(); //テクスチャ(ID_texture_output)に書き込んだデータを取り出す領域を用意 std::vector<GLubyte> texdata; texdata.resize(width * height * 3); //テクスチャのデータを取り出す glBindTexture(GL_TEXTURE_2D, ID_texture_output); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &texdata[0] ); glFlush(); //ファイル書き出し pnmP3_Write("C:\\test\\ret.ppm", 255, width, height, &texdata[0]);//ここから先は画面に出力する glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height);//ここのwidthとheightは別にこの値でなくてもいい。ウィンドウサイズに合わせるのが普通。 glLineWidth(5); glBegin(GL_LINES); glColor3d(1, 0, 0); glVertex2d(-0.7, -0.7); glColor3d(0, 0, 1); glVertex2d(0.7, 0.7); glColor3d(0, 1, 0); glVertex2d(0.7, -0.7); glColor3d(1, 1, 1); glVertex2d(-0.7, 0.7); glEnd(); glFlush();} //! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] vmax 全てのRGBの中の最大値 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む void pnmP3_Write(const char* const fname, const int vmax, const int width, const int height, const unsigned char* const p) { // PPM ASCII FILE* fp = fopen(fname, "wb"); fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]); k++; } fprintf(fp, "\n"); } fclose(fp); }
このプログラムは描画が走るたびにC:\test\ret.ppmを出力します。あまり長時間走らせていいことのあるプログラムではありません。出力が確認出来たらすぐに画面を閉じてください。