順序が大幅にずれた感があるが点の表示について。
typedef GLfloat point_t[3]; //モデルの座標用 x y z typedef GLfloat color_t[4];//テクスチャ座標用 r g b a ///////////////////////////////// //バッファとデータ GLuint vertexbufferName; point_t vertex[5]; GLuint colorbufferName; color_t color[5];
////////////////////////////////////////// ////////////////////////////////////////// vertex[0][0] = -0.7; vertex[0][1] = 0.7; vertex[0][2] = 0; vertex[1][0] = -0.7; vertex[1][1] = -0.7; vertex[1][2] = 0; vertex[2][0] = 0.7; vertex[2][1] = -0.7; vertex[2][2] = 0; vertex[3][0] = +0.7; vertex[3][1] = +0.7; vertex[3][2] = 0; vertex[4][0] = 0; vertex[4][1] = 0; vertex[4][2] = 0; ////////////////////////////////////////// ////////////////////////////////////////// color[0][0] = 1.0; color[0][1] = 0.0; color[0][2] = 0.0; color[0][3] = 1.0;//α color[1][0] = 0.0; color[1][1] = 1.0; color[1][2] = 0.0; color[1][3] = 1.0;//α color[2][0] = 0.0; color[2][1] = 0.0; color[2][2] = 1.0; color[2][3] = 1.0;//α color[3][0] = 1.0; color[3][1] = 0.0; color[3][2] = 1.0; color[3][3] = 1.0;//α color[4][0] = 1.0; color[4][1] = 1.0; color[4][2] = 1.0; color[4][3] = 1.0;//α ////////////////////////////////////////// ////////////////////////////////////////// glGenBuffers(1, &vertexbufferName); glBindBuffer(GL_ARRAY_BUFFER, vertexbufferName); glBufferData(GL_ARRAY_BUFFER, 3 * 5 * sizeof(GLfloat), vertex, GL_STATIC_DRAW); glGenBuffers(1, &colorbufferName); glBindBuffer(GL_ARRAY_BUFFER, colorbufferName); glBufferData(GL_ARRAY_BUFFER, 4 * 5 * sizeof(GLfloat), color, GL_STATIC_DRAW);
glUseProgram(ProgramID); //gl_PointSizeを有効にする glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); // 頂点バッファ glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbufferName); glVertexAttribPointer( 0, // 属性0 3, // 1要素の要素数 x y z GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファ glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbufferName); glVertexAttribPointer( 1, // 属性1 4, // 1要素の要素数 r g b a GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 5頂点を描く glDrawArrays(GL_POINTS, 0, 5); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); //////////////////////////////////////// ////////////////////////////////////////
#version 460 core layout (location = 0) in vec3 vtx; layout (location = 1) in vec4 color; out vec4 vColor; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(vtx, 1.0); vColor = color; gl_PointSize=30.0; // 頂点のサイズ(ピクセル) }
#version 460 core out vec4 FragColor; in vec4 vColor; void main() { FragColor = vColor; }

以下を先頭に追加
using namespace System::Xml::Linq; int main(array<System::String^>^ args) { // ② 追加する要素を作成 XElement ^man1; { XElement^ ext; ext = gcnew XElement("その他"); ext->Add(gcnew XElement("特技", L"昼寝")); man1 = gcnew XElement("個人データ", gcnew XElement("名前", "山田太郎"), gcnew XElement("年齢", 45), gcnew XElement("住所", "愛媛県松山市"), ext ); } // ② 追加する要素を作成 XElement^ man2; { XElement^ ext; ext = gcnew XElement("その他"); ext->Add(gcnew XElement("特技", L"懸垂")); man2 = gcnew XElement("個人データ", gcnew XElement("名前", "西田花子"), gcnew XElement("年齢", 15), gcnew XElement("住所", "北海道札幌市"), ext ); } // ② 追加する要素を作成 XElement^ man3; { XElement^ ext; ext = gcnew XElement("その他"); ext->Add(gcnew XElement("特技", L"読書")); man3 = gcnew XElement("個人データ", gcnew XElement("名前", "岡田広美"), gcnew XElement("年齢", 35), gcnew XElement("住所", "沖縄県中城村"), ext ); } XElement^ root = gcnew XElement("root"); // ① XDocumentオブジェクトを作成 XDocument^ alldata = gcnew XDocument( gcnew XComment("利用者の全情報"), root ); // ③ XDocumentにXElementを追加 root->Add(man1); root->Add(man2); root->Add(man3); // ④ ファイル保存 alldata->Save("C:\\mydata\\others\\個人データ1.xml"); }
<?xml version="1.0" encoding="utf-8"?> <!--利用者の全情報--> <root> <個人データ> <名前>山田太郎</名前> <年齢>45</年齢> <住所>愛媛県松山市</住所> <その他> <特技>昼寝</特技> </その他> </個人データ> <個人データ> <名前>西田花子</名前> <年齢>15</年齢> <住所>北海道札幌市</住所> <その他> <特技>懸垂</特技> </その他> </個人データ> <個人データ> <名前>岡田広美</名前> <年齢>35</年齢> <住所>沖縄県中城村</住所> <その他> <特技>読書</特技> </その他> </個人データ> </root>
using namespace System::Xml::Linq; int main(array<System::String ^> ^args) { // XMLファイルを開く XDocument^ xml = XDocument::Load("C:\\mydata\\others\\個人データ1.xml"); XElement^ root = xml->Element("root"); //イテレータの取得 System::Collections::Generic::IEnumerable<XElement^>^ xelements = root->Elements(); for each (XElement ^ k in xelements) { // k には<個人データ>の内容が入っている System::String^ name = k->Element("名前")->Value; int age = int::Parse(k->Element("年齢")->Value); System::String^ addr = k->Element("住所")->Value; System::String^ adv = k->Element("その他")->Element("特技")->Value; //読み取った内容表示 System::Console::WriteLine(name); System::Console::WriteLine(age); System::Console::WriteLine(addr); System::Console::WriteLine(adv); System::Console::WriteLine("--------------"); } return 0; }

CSharpの情報はたくさん出てくる。そしてそれを真似ればうまくいく。99.9%うまくいく。しかしC++CLIから使う場合CSharpのコードからは必要な情報が読み取りにくい。具体的には型情報と名前空間あたりがさっぱりわからない。そもそもC++CLIなんて積極的に使う言語じゃないから自分の中に技術が蓄積しない。加えて情報が少ない。公式にすらろくに無い。その上CSharpの情報で大抵事足りる。故に逆に一度詰まると基本的なことがわからなくて彷徨うことになる。というか、彷徨った。
@warningと@attentionの違いが今ひとつわからない。英語を母国語とするものにとっては明確に違うのかもしれない。意味が全然違うとか言われそうだ。しかし私にはわからないので調べてみる。
ちょうど手元にあったPCLのソースコードでwarningとattentionを検索してみた。
boost/process/async.hpp to be included and a reference to boost::asio::io_service to be passed to the launching function.@attention ... 使う上で考慮しておくべき項目など。たとえば、 @attention untested code などは使ってはいけないとも、使うと問題が起こるとも限らないが、考慮必須の項目である。
@warning ... やってはいけない使い方・問題が起こる条件など。たとえば、
\warning Invalid arguments cause undefined behaviour. は無効な引数に対して動作保証がないことを示している。
Windowsにdoxygenをインストールします。結論を言うと、以下が自分の中で最適。
http://www.doxygen.nl/download.html
からダウンロードできるのだけれど、
と、
があって、ここでは、doxygen-1.8.15-setup.exeをダウンロードします。
なぜかというと、zip版にはdoxywizardが入っていないからです。
普通にインストーラからインストールしてもいいのだけれど、勝手にPATH通されたりレジストリをいじられたりとかしたらたまったものではないのでインストーラを手動で展開して中身をほじくり出します。Universal Extractor 2を使います。
UniExtract.exeを実行したら、 doxygen-1.8.15-setup.exe のパスと展開先を入力してOKします。

展開された中にあるbinフォルダを適当な場所にコピーします

doxywizardが起動できたら成功。

Visual Studio2019をインストールしたはいいがタイトルバーがメニューバーと一体化してしまった。
ウィンドウを移動するのにものすごく不便なので元に戻す。
https://stackoverflow.com/questions/53636350/re-enable-title-bar-in-visual-studio-2019
%LOCALAPPDATA%\Microsoft\VisualStudio\16.0_xxxxxxxx\Settings\CurrentSettings.vssettings<PropertyValue name="IsMinimalVsEnabled">True</PropertyValue><PropertyValue name="IsMinimalVsEnabled">False</PropertyValue>
巷の例がGL_RGBかGL_RGBAばかりなのでGL_LUMINACEを使った例を置いておく。
typedef GLubyte gray_t; //テクスチャ用 typedef GLfloat points_t[3]; //モデルの座標用 typedef GLfloat texcoord_t[2];//テクスチャ座標用 const int P_COUNT = 4; //頂点データ GLuint vertexbuffer; points_t position[P_COUNT]; //テクスチャ座標データ texcoord_t texcoord[P_COUNT]; GLuint texcoordbuffer; //テクスチャデータ gray_t texdata[P_COUNT]; GLuint textureID; ////////////////////////////////////////////////// void prepare_buffers() { //テクスチャ(画像)作成 // 2*2の画像 texdata[0] = 255; texdata[1] = 128; texdata[2] = 50; texdata[3] = 0; ////////////////////////////////////////// ////////////////////////////////////////// //頂点座標の定義 (四角形) position[0][0] = -0.7; position[0][1] = 0.7; position[0][2] = 0; position[1][0] = -0.7; position[1][1] = -0.7; position[1][2] = 0; position[2][0] = 0.7; position[2][1] = -0.7; position[2][2] = 0; position[3][0] = +0.7; position[3][1] = +0.7; position[3][2] = 0; ////////////////////////////////////////// ////////////////////////////////////////// //テクスチャ座標の定義 texcoord[0][0] = 0; texcoord[0][1] = 1; texcoord[1][0] = 0; texcoord[1][1] = 0; texcoord[2][0] = 1; texcoord[2][1] = 0; texcoord[3][0] = 1; texcoord[3][1] = 1; ////////////////////////////////////////// ////////////////////////////////////////// //テクスチャの作成 // 普通のテクスチャ作成 glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); int TEXWIDTH = 2; // 2*2の画素数 int TEXHEIGHT = 2; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // テクスチャの割り当て glTexImage2D(
GL_TEXTURE_2D,
0,
GL_LUMINANCE,
TEXWIDTH,
TEXHEIGHT,
0, GL_LUMINANCE,
GL_UNSIGNED_BYTE,
texdata
); // テクスチャを拡大・縮小する方法の指定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); }
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_CULL_FACE);//カリングを無効にする /////////////////////////////////// // 行列の設定 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(65, 1, 0.1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0.0, 0.0, -3); /////////////////////////////////// // 四角形の描画 glEnable(GL_TEXTURE_2D); glBegin(GL_TRIANGLE_FAN); glTexCoord2fv(texcoord[0]); glVertex3fv(position[0]); glTexCoord2fv(texcoord[1]); glVertex3fv(position[1]); glTexCoord2fv(texcoord[2]); glVertex3fv(position[2]); glTexCoord2fv(texcoord[3]); glVertex3fv(position[3]); glEnd(); glFlush(); }

グレイスケール(1画素が輝度値で表現されている)データをテクスチャとして使用することを考える。RGB(A)に変換しないでできれば何かと便利になる。
typedef GLshort gray_t; const int P_COUNT = 4; gray_t texdata[P_COUNT]; //テクスチャ(画像)作成 // 2*2のグレイスケール画像 texdata[0] = 255; texdata[1] = 128; texdata[2] = 50; texdata[3] = 0;
GL_LUMINANCEなどを指定すればよいのだが、これは最近では非推奨らしい。
代わりに、GL_R8I,GL_R8UI,GL_R16I,GL_R16UI,GL_R32I,GL_R32UI等を使えば、RGBではなくグレイスケールとしてテクスチャを転送できる。
glTexImage2D( GL_TEXTURE_2D, 0, GL_R8UI, //8bitのunsinged int TEXWIDTH, //テクスチャ画素数 TEXHEIGHT, //テクスチャ画素数 0, GL_RED_INTEGER, //整数 GL_UNSIGNED_BYTE, //unsigned の 1byte
texdata
);
glTexImage2D( GL_TEXTURE_2D, 0, GL_R16I, //16bitのsigned int TEXWIDTH, //テクスチャ画素数 TEXHEIGHT, //テクスチャ画素数 0, GL_RED_INTEGER, //整数 GL_SHORT, //signed の 2byte texdata );
sampler2Dを使うと、データ範囲が0.0~1.0の間で正規化されて取得できる。それでいい時も多いと思うのだが、グレースケールデータの値を正確に参照したい場合は不便というか、元の値を正確に得られる保証がない。そこでisampler2Dを使うと、テクスチャのデータをもとのままで参照できる。
#version 460 core out vec4 FragColor; //色の出力はfloatでいい uniform isampler2D uTex; //データをint型で受け取る。符号なしintのときはusampler2D in vec2 vTexCoord; //テクスチャ座標 void main() { int c = texture(uTex,vTexCoord).x; //分岐はどうのとか今はいい。本題ではない。 if( c == 255) FragColor =vec4( 1.0,0,0,1); else if( c == 128) FragColor =vec4( 0.0,1.0,0,1); else if( c == 50) FragColor =vec4( 0.0,0.0,1.0,1); else FragColor =vec4( float(c)/255.0,float(c)/255.0,float(c)/255.0,1.0); }


typedef GLubyte rgb_t[3]; //テクスチャ用 typedef GLfloat points_t[3]; //モデルの座標用 typedef GLfloat texcoord_t[2];//テクスチャ座標用 const int P_COUNT = 4; //頂点データ GLuint vertexbuffer; points_t position[P_COUNT]; //テクスチャ座標データ texcoord_t texcoord[P_COUNT]; GLuint texcoordbuffer; //テクスチャデータ rgb_t texdata[P_COUNT]; GLuint textureID;
void prepare_buffers() { //テクスチャ(画像)作成 // 2*2の画像 texdata[0][0] = 255; texdata[0][1] = 0; texdata[0][2] = 0; texdata[1][0] = 0; texdata[1][1] = 255; texdata[1][2] = 0; texdata[2][0] = 0; texdata[2][1] = 0; texdata[2][2] = 255; texdata[3][0] = 255; texdata[3][1] = 255; texdata[3][2] = 255; ////////////////////////////////////////// ////////////////////////////////////////// //頂点座標の定義 (四角形) // いつもなら glVertex3fv等て指定するもの position[0][0] = -0.7; position[0][1] = 0.7; position[0][2] = 0; position[1][0] = -0.7; position[1][1] = -0.7; position[1][2] = 0; position[2][0] = 0.7; position[2][1] = -0.7; position[2][2] = 0; position[3][0] = +0.7; position[3][1] = +0.7; position[3][2] = 0; ////////////////////////////////////////// ////////////////////////////////////////// //テクスチャ座標の定義 //いつもならglTexCoord2f等で指定するもの texcoord[0][0] = 0; texcoord[0][1] = 1; texcoord[1][0] = 0; texcoord[1][1] = 0; texcoord[2][0] = 1; texcoord[2][1] = 0; texcoord[3][0] = 1; texcoord[3][1] = 1; ////////////////////////////////////////// ////////////////////////////////////////// //テクスチャの作成 // 普通のテクスチャ作成 glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); int TEXWIDTH = 2; // 2*2の画素数 int TEXHEIGHT = 2; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // テクスチャの割り当て glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXWIDTH, TEXHEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, texdata); // テクスチャを拡大・縮小する方法の指定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ////////////////////////////////////////// ////////////////////////////////////////// //頂点バッファの作成 glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, 3 * P_COUNT * sizeof(GLfloat), position, GL_STATIC_DRAW); //テクスチャ座標バッファの作成 glGenBuffers(1, &texcoordbuffer); glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer); glBufferData(GL_ARRAY_BUFFER, 2 * P_COUNT * sizeof(GLfloat), texcoord, GL_STATIC_DRAW); }
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_CULL_FACE);//カリングを無効にする /////////////////////////////////// // 行列の設定 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(65, 1, 0.1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0.0, 0.0, -3); /////////////////////////////////// // シェーダを使う glUseProgram(ProgramID); /////////////////////////////////// // 頂点バッファを有効化 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // 属性0 3, // 1要素の個数。GLfloatのx,y,zなので3 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); /////////////////////////////////// //テクスチャ座標バッファの有効化 glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer); glVertexAttribPointer( 1, // 属性1 2, // 1要素の個数。GLfloatのu,vなので2 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); /////////////////////////////////// // 四角形の描画 glDrawArrays(GL_TRIANGLE_FAN, 0, P_COUNT); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glFlush(); }
#version 460 core layout (location = 0) in vec3 aPos;//ポリゴンの頂点座標 layout (location = 1) in vec2 texcd;//座標に対応するテクスチャ座標 out vec2 vTexCoord;//テクスチャ座標の出力先 uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); vTexCoord = texcd;//フラグメントシェーダへテクスチャ座標を渡す }
#version 460 core out vec4 FragColor;//色の出力先 uniform sampler2D uTex;//テクスチャデータ(自動でセットされている) in vec2 vTexCoord;//頂点シェーダから渡されたテクスチャ座標 void main() {
//テクスチャデータとテクスチャ座標から色を決定 FragColor = texture(uTex,vTexCoord); }

頂点シェーダへの変換行列の受け渡しの方法は二つ。
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(65, 1, 0.1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0.0, 0.0, -0.8); // シェーダを使う glUseProgram(ProgramID); // 最初の属性バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 3, // サイズ GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // シェーダ内のlayoutとあわせる 3, // サイズ GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 3); // 頂点0から始まります。合計3つの頂点です。→1つの三角形です。 glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glFlush(); }
uniform変数 gl_ModelViewMatrixやgl_ProjectionMatrixでOpenGLの行列にアクセス出来る。これらはglUniformMatrix4fvで設定する必要が無い。
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 incolor; out vec4 vertexColor; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); vertexColor = vec4(incolor, 1.0); }
この他のBuilt-In-Matrixは以下を参照
https://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations
自分のプログラム内で行列を用意してglUniformMatrix4fvでGPUへ転送する。Projection Matrixを計算するコードを自前で書くのも間抜けなので
https://www.khronos.org/opengl/wiki/GluPerspective_code
などをコピペすると良い。
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); // シェーダを使う glUseProgram(ProgramID); //変換行列を定義 // uniform mat4がfloatのため、こちらもfloatでないといけない GLfloat mfproj[16]; GLfloat mftran[16]; mfproj[ 0] = 2.26961231; mfproj[ 1] = 0.0; mfproj[ 2] = 0.0; mfproj[ 3] = 0.0; mfproj[ 4] = 0.0; mfproj[ 5] = 2.41421366; mfproj[ 6] = 0.0; mfproj[ 7] = 0.0; mfproj[ 8] = 0.0; mfproj[ 9] = 0.0; mfproj[10] = -1.00020003; mfproj[11] = -1.00000000; mfproj[12] = 0.0; mfproj[13] = 0.0; mfproj[14] = -0.0200020000; mfproj[15] = 0.0; mftran[ 0] = 1.0; mftran[ 1] = 0.0; mftran[ 2] = 0.0; mftran[ 3] = 0.0; mftran[ 4] = 0.0; mftran[ 5] = 1.0; mftran[ 6] = 0.0; mftran[ 7] = 0.0; mftran[ 8] = 0.0; mftran[ 9] = 0.0; mftran[10] = 1.0; mftran[11] = 0.0; mftran[12] = 0.2; mftran[13] = 0.0; mftran[14] = 0.0; mftran[15] = 1.0; GLint proj = glGetUniformLocation(ProgramID, "m_projection"); GLint tran = glGetUniformLocation(ProgramID, "m_transform"); glUniformMatrix4fv(proj, 1, GL_FALSE, mfproj); glUniformMatrix4fv(tran, 1, GL_FALSE, mftran); // 最初の属性バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // 属性0 3, // サイズ GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 2nd attribute buffer : colors glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // 属性1 3, // サイズ GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glFlush(); }
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 incolor; out vec4 vertexColor; uniform mat4 m_transform; uniform mat4 m_projection; void main() { gl_Position = m_projection * m_transform * vec4(aPos, 1.0); vertexColor = vec4(incolor, 1.0); }
glBegin - glEndが大好きなのだけれどそろそろモダンOpenGLにも触っておかないとまずいということでVBOと頂点シェーダとフラグメントシェーダの基礎を触っておく。
ややこしいのは、VBO(=頂点バッファ)のコードと頂点シェーダ関連コードが、直接的な関連性が低いのに密接に絡み合っているところ。
glutを使わないのなら勿論必要ない。ただしglewを使うのでその初期化が必要。
余談だけれどもgl.hを使うのならinclude順はglew.h→gl.hとなる。さらにwindowsではgl.hの前にwindows.hを入れなければならない。つまりwgl等でウィンドウを作成する場合、
#include <windows.h>
#include <gl/glew.h>
#include <gl/GL.h>
のような順番になる。この例ではglutだけなのでgl.hは自分でincludeしない。ただしglut.hの中でgl.hがincludeされているので、順番はglew.h→glut.hでなければならない。さもなくば
fatal error C1189: #error: gl.h included before glew.h
と言われる。
#pragma warning(disable:4996) #pragma comment(lib,"glew32.lib") #include <gl/glew.h> #include <GL/glut.h> #include <fstream> #include <sstream> #include <vector> #include <algorithm> void init(void); void display(void); int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display);
glewInit(); // glewの初期化 init(); glutMainLoop(); return 0; }
void init(void) { //頂点データと色情報の作成 prepare_buffers(); //頂点シェーダの準備 prepare_vertex_shader(); //フラグメントシェーダの準備 prepare_fragment_shader(); //プログラムのリンク link_program(); }
今までglBegin~glEndで囲んでいたデータを配列として作成して先にGPUへ転送しておく。
//バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 points_t position[3]; points_t color[3]; ////////////////////////////////////////////////// void prepare_buffers() { //頂点座標 position[0][0] = 0; position[0][1] = 0.5; position[0][2] = 0; position[1][0] = 0.5; position[1][1] = -0.5; position[1][2] = 0; position[2][0] = -0.5; position[2][1] = -0.5; position[2][2] = 0; //色 color[0][0] = 1.0; color[0][1] = 0.0; color[0][2] = 0.0; color[1][0] = 0.0; color[1][1] = 1.0; color[1][2] = 0.0; color[2][0] = 0.0; color[2][1] = 0.0; color[2][2] = 1.0; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(
GL_ARRAY_BUFFER,
3 * 3 * sizeof(GLfloat),
position,
GL_STATIC_DRAW); glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData(
GL_ARRAY_BUFFER,
3 * 3 * sizeof(GLfloat),
color,
GL_STATIC_DRAW); }
クソ長く見えるがやっていることは
①glCreateShaderでシェーダのIDを作成
②glShaderSourceでシェーダのソースコードをシェーダに教える
③glCompileShaderでシェーダをコンパイル
④glGetShaderivでシェーダのコンパイルに成功したかを確認
⑤glGetShaderInfoLogでエラー内容を確認
だけで本質的には十行程度。ファイル読み込み部がコードの長さを異常に長くみせている。本質とは直接関係ないのに。
GLuint VertexShaderID;
void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります // (作るといっても宣言みたいなもの) VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。
// 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、
// OpenGL命令は一つも無い。 const char * vertex_file_path = "C:\\test\\verts.sh"; std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } //////////////////////////////////////////// // 頂点シェーダをコンパイルします。 printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //////////////////////////////////////////// // エラーチェック GLint Result = GL_FALSE; int InfoLogLength; // 頂点シェーダをチェックします。 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]); } }
あとエラー処理が行数を嵩張らせている。普通(?)OpenGLで描画とかするときに、エラーを無視してもなんとなく上手く動いているように見えることも多いけれど、シェーダのコンパイルをする以上、コンパイルエラーをちゃんと見ないとデバッグ出来ないのでエラー処理はちゃんと入れないとまずい。
これはエラーを見る癖をつけましょうとかの精神論ではなく、見ないと何故動かないのかが全くわからないから省きようがない。
頂点シェーダとの違いは、読み込むファイルと、glCreateShaderに渡す定数がGL_FRAGMENT_SHADERになっているところぐらいで、ほぼ同じ。
GLuint FragmentShaderID;
void prepare_fragment_shader() { ///////////////////////////////////////////// // シェーダを作ります。 FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 const char * fragment_file_path = "C:\\test\\frags.sh"; std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } ///////////////////////////////////////////// // フラグメントシェーダをコンパイルします。 printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); GLint Result = GL_FALSE; int InfoLogLength; /////////////////////////////////////////////
// フラグメントシェーダをチェックします。 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]); } }
頂点シェーダとフラグメントシェーダのセットをProgramとして一つに束ねる。
ここもやっていることは、
①glCreateProgram でプログラムIDを取得
②glAttachShader でシェーダを登録
③glLinkProgram プログラムをリンク
④glGetProgramiv でプログラムのエラーをチェック
⑤glGetProgramInfoLog でプログラムのエラーの内容をチェックする
GLuint ProgramID;
void link_program() { GLint Result = GL_FALSE; int InfoLogLength; //////////////////////////////////////// // プログラムをリンクします。 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]); }
拡張子は何でもいい。shだとシェルスクリプトと勘違いしそうなら.verts、.fragsなどでいい。
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 incolor; out vec4 vertexColor; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); vertexColor = vec4(incolor, 1.0); }
#version 460 core out vec4 FragColor; in vec4 vertexColor; void main() { FragColor = vertexColor; }
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslated(0.5, 0.0, 0.0);//平行移動 // シェーダを使う glUseProgram(ProgramID); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(x,y,z)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(r,g,b)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glFlush(); }

後半へ続く・・・