モダンOpenGLではシェーディングは光源の座標から何から全部自分でUniform変数として転送した上で、反射角から何から何まで全部自分で計算しなければならない。わかる。わかるがそれは3DCGライブラリとして見たときどうなんだと・・・。
以下の記事の中のシェーダをコピペしてシェーディングを行う。
The Basics of GLSL 4.0 Shaders
https://www.gamedev.net/articles/programming/graphics/the-basics-of-glsl-40-shaders-r2861
この記事はADS シェーディング(= Ambient Diffuse Specular Shading)のソースコードが載っているのでほぼそのままコピペで使える。
今回はこの中でUsing Functions in Shadersの項目にあるシェーダを使う。
ただし以下私が書いたCのソースでは各面ごとに頂点を用意してそれぞれの頂点に同じ面法線を用意しているのでスムーズシェーディングのシェーダなんだけれどフラットシェーディングと同じ効果になっている。
#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); void timer(int value) { glutPostRedisplay(); glutTimerFunc(20, timer, 0); } int width, height; void resize(int w, int h) { width = w; height = h; } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(resize); glutTimerFunc(20, timer, 0); glewInit(); // glewの初期化 init(); glutMainLoop(); return 0; } void prepare_buffers(); void prepare_vertex_shader(); void prepare_fragment_shader(); void link_program(); void init(void) { //頂点シェーダの準備 prepare_vertex_shader(); //フラグメントシェーダの準備 prepare_fragment_shader(); //プログラムのリンク link_program(); //頂点データと色情報の作成 prepare_buffers(); }GLuint VertexShaderID;
void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 const char* vertex_file_path = "..\\vertex.shader"; 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]); } } GLuint FragmentShaderID; void prepare_fragment_shader() { ///////////////////////////////////////////// // シェーダを作ります。 FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 const char* fragment_file_path = "..\\fragment.shader"; 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]); } } 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]); }/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// 頂点を作るための補助関数 /////////////////////// void set(std::vector<GLfloat>& v, GLfloat x, GLfloat y, GLfloat z) { v.push_back(x); v.push_back(y); v.push_back(z); }
////////////////////////////////////////////////// // バッファ名 /////////////////////////////////// GLuint buf_v_name; GLuint buf_c_name; GLuint buf_n_name;
/////////////////////////////////////////////////// // ライトのLocation /////////////////////////////// GLint m_loc_Light_Position; GLint m_loc_Light_La; GLint m_loc_Light_Ld; GLint m_loc_Light_Ls;
/////////////////////////////////////////////////// // マテリアルのLocation /////////////////////////// GLint m_loc_Material_Ka; GLint m_loc_Material_Kd; GLint m_loc_Material_Ks; GLint m_loc_Material_Shiniess;
/////////////////////////////////////////////////// // 変換行列のLocation ///////////////////////////// GLint m_loc_ModelViewMatrix; GLint m_loc_ProjectionMatrix;////////////////////////////////////////////////// // バッファ作成 ////////////////////////////////// void prepare_buffers() { std::vector<GLfloat> vtx; std::vector<GLfloat> col; std::vector<GLfloat> nrm;//法線 double size = 1; double m = -size / 2; double p = size / 2; double xp = p; double yp = p; double zp = p; double xm = m; double ym = m; double zm = m; //////////////////////////////////// 頂点 ////////////////////////////(A)
set(vtx, xp, yp, zm); set(vtx, xp, ym, zm); set(vtx, xm, yp, zm); set(vtx, xm, ym, zm); //(B) set(vtx, xp, yp, zp); set(vtx, xp, ym, zp); set(vtx, xp, yp, zm); set(vtx, xp, ym, zm); //(C) (Aの反対) set(vtx, xm, ym, zp); set(vtx, xp, ym, zp); set(vtx, xm, yp, zp); set(vtx, xp, yp, zp); //(D)(Bの反対) set(vtx, xm, ym, zm); set(vtx, xm, ym, zp); set(vtx, xm, yp, zm); set(vtx, xm, yp, zp); //上 set(vtx, xp, yp, zm); set(vtx, xm, yp, zm); set(vtx, xp, yp, zp); set(vtx, xm, yp, zp); //下 set(vtx, xp, ym, zp); set(vtx, xm, ym, zp); set(vtx, xp, ym, zm); set(vtx, xm, ym, zm); //////////////////////////////////// 頂点の色 //////////////////////
//(A) set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); set(col, 1.0, 0.0, 0.0); //(B) set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); //(C) (Aの反対) set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); set(col, 0.0, 0.0, 1.0); //(D)(Bの反対) set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); //上 set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 1.0); //下 set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); set(col, 1.0, 0.0, 1.0); ////////////////////////////////// // 頂点法線 ////////////////////// //(A) set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); set(nrm, 0, 0, -1); //(B) set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); set(nrm, 1, 0, 0); //(C) (Aの反対) set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); set(nrm, 0, 0, 1); //(D)(Bの反対) set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); set(nrm, -1, 0, 0); //上 set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); set(nrm, 0, 1, 0); //下 set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); set(nrm, 0, -1, 0); glGenBuffers(1, &buf_v_name); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &vtx[0], GL_STATIC_DRAW ); glGenBuffers(1, &buf_c_name); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &col[0], GL_STATIC_DRAW ); glGenBuffers(1, &buf_n_name); glBindBuffer(GL_ARRAY_BUFFER, buf_n_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &nrm[0], GL_STATIC_DRAW ); glUseProgram(ProgramID); m_loc_Light_Position = glGetUniformLocation(ProgramID, "Light.Position"); m_loc_Light_La = glGetUniformLocation(ProgramID, "Light.La"); m_loc_Light_Ld = glGetUniformLocation(ProgramID, "Light.Ld"); m_loc_Light_Ls = glGetUniformLocation(ProgramID, "Light.Ls"); m_loc_Material_Ka = glGetUniformLocation(ProgramID, "Material.Ka"); m_loc_Material_Kd = glGetUniformLocation(ProgramID, "Material.Kd"); m_loc_Material_Ks = glGetUniformLocation(ProgramID, "Material.Ks"); m_loc_Material_Shiniess = glGetUniformLocation(ProgramID, "Material.Shininess"); m_loc_ModelViewMatrix = glGetUniformLocation(ProgramID, "ModelViewMatrix"); m_loc_ProjectionMatrix = glGetUniformLocation(ProgramID, "ProjectionMatrix"); }////////////////////////////////////////////////////// //かなり強引に各種行列を求める //本当はこんなことをしてはいけないvoid calc_matrixes(GLfloat* proj, GLfloat* model) { double asp = width / (double)height; static int r1 = 0; static int r2 = 0; r1 += 1; r2 += 1; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0, 0, -5); glRotatef(r1, 1, 0, 0); glRotatef(r2, 0, 1, 0); glGetFloatv(GL_MODELVIEW_MATRIX, model); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, asp, 0.1, 10); glGetFloatv(GL_PROJECTION_MATRIX, proj); glLoadIdentity(); }void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // シェーダを使う glUseProgram(ProgramID); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); // 法線バッファを有効にする glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, buf_n_name); glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glViewport(0, 0, width, height); GLfloat mt_projection[16]; GLfloat mt_modelview[16]; //行列を作成 calc_matrixes(mt_projection, mt_modelview); glUniformMatrix4fv(m_loc_ProjectionMatrix, 1, GL_FALSE, mt_projection); glUniformMatrix4fv(m_loc_ModelViewMatrix, 1, GL_FALSE, mt_modelview); glUniform4f(m_loc_Light_Position, 1, 1, 2, 1); glUniform3f(m_loc_Light_La, 0.3, 0.3, 0.3); glUniform3f(m_loc_Light_Ld, 1.0, 1.0, 1.0); glUniform3f(m_loc_Light_Ls, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Ka, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Kd, 1.0, 1.0, 1.0); glUniform3f(m_loc_Material_Ks, 1.0, 1.0, 1.0); glUniform1f(m_loc_Material_Shiniess, 100.0); // 三角形を描きます! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glFlush(); }////////////////////////////////////////////////////// //表示
#version 460 core //Using functions in shaders layout (location = 0) in vec3 VertexPosition; layout (location = 1) in vec3 VertexColor; layout (location = 2) in vec3 VertexNormal; // CPU側から転送する uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; //この二つはコピペ元ではuniform変数になっているが、面倒なのでGPU側で計算する。 mat3 NormalMatrix; mat4 MVP; out vec3 LightIntensity; struct LightInfo { vec4 Position;// Light position in eye coords. vec3 La; // Ambient light intensity vec3 Ld; // Diffuse light intensity vec3 Ls; // Specular light intensity }; uniform LightInfo Light; struct MaterialInfo { vec3 Ka; // Ambient reflectivity vec3 Kd; // Diffuse reflectivity vec3 Ks; // Specular reflectivity float Shininess; // Specular shininess factor }; uniform MaterialInfo Material; void getEyeSpace( out vec3 norm, out vec4 position ) { norm = normalize( NormalMatrix * VertexNormal); position = ModelViewMatrix * vec4(VertexPosition,1.0); } vec3 phongModel( vec4 position, vec3 norm ) { vec3 s = normalize(vec3(Light.Position - position)); vec3 v = normalize(-position.xyz); vec3 r = reflect( -s, norm ); vec3 ambient = Light.La * Material.Ka; float sDotN = max( dot(s,norm), 0.0 ); vec3 diffuse = Light.Ld * Material.Kd * sDotN; vec3 spec = vec3(0.0); if( sDotN > 0.0 ) spec = Light.Ls * Material.Ks * pow( max( dot(r,v), 0.0 ), Material.Shininess ); return ambient + diffuse + spec; } void main() { //MVPは本来GPUにやらせるような作業じゃないけれど、 //CPU側のソースコードが無駄に膨れるのを避けるためここで計算する MVP = ProjectionMatrix * ModelViewMatrix; // モデルビュー行列の上3x3の逆行列の転置行列 // これも多分CPU側でやったほうがいい NormalMatrix = transpose(inverse(mat3(ModelViewMatrix))); vec3 eyeNorm; vec4 eyePosition; // Get the position and normal in eye space getEyeSpace(eyeNorm, eyePosition); // Evaluate the lighting equation. LightIntensity = phongModel( eyePosition, eyeNorm ); gl_Position = MVP * vec4(VertexPosition,1.0); }
#version 460 core out vec4 FragColor; in vec3 LightIntensity; void main() { FragColor = vec4(LightIntensity, 1.0); }
色がついていないように見えるのはMaterialで渡したのがグレイスケールなのでそれがそのまま反映されている。オブジェクト単位で同じ色を使うなら素直な方法だが頂点ごとに色指定したい場合はどうやってVertexColorを反映させるか・・・。
マテリアルに VertexColor をかけてみた。C++側から渡したMaterialはどれもグレースケールなのでそのまま重みとして使うことができる。
#version 460 core //Using functions in shaders layout (location = 0) in vec3 VertexPosition; layout (location = 1) in vec3 VertexColor; layout (location = 2) in vec3 VertexNormal; // CPU側から転送する uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; //この二つはコピペ元ではuniform変数になっているが、面倒なのでGPU側で計算する。 mat3 NormalMatrix; mat4 MVP; out vec3 LightIntensity; struct LightInfo { vec4 Position;// Light position in eye coords. vec3 La; // Ambient light intensity vec3 Ld; // Diffuse light intensity vec3 Ls; // Specular light intensity }; uniform LightInfo Light; struct MaterialInfo { vec3 Ka; // Ambient reflectivity vec3 Kd; // Diffuse reflectivity vec3 Ks; // Specular reflectivity float Shininess; // Specular shininess factor }; uniform MaterialInfo Material; void getEyeSpace( out vec3 norm, out vec4 position ) { norm = normalize( NormalMatrix * VertexNormal); position = ModelViewMatrix * vec4(VertexPosition,1.0); } vec3 phongModel( vec4 position, vec3 norm ) { vec3 s = normalize(vec3(Light.Position - position)); vec3 v = normalize(-position.xyz); vec3 r = reflect( -s, norm ); vec3 ambient = Light.La * Material.Ka * VertexColor; float sDotN = max( dot(s,norm), 0.0 ); vec3 diffuse = Light.Ld * Material.Kd * VertexColor * sDotN; vec3 spec = vec3(0.0); if( sDotN > 0.0 ) spec = Light.Ls * Material.Ks * pow( max( dot(r,v), 0.0 ), Material.Shininess ); return ambient + diffuse + spec; } void main() { //MVPは本来GPUにやらせるような作業じゃないけれど、 //CPU側のソースコードが無駄に膨れるのを避けるためここで計算する MVP = ProjectionMatrix * ModelViewMatrix; // モデルビュー行列の上3x3の逆行列の転置行列 // これも多分CPU側でやったほうがいい NormalMatrix = transpose(inverse(mat3(ModelViewMatrix))); vec3 eyeNorm; vec4 eyePosition; // Get the position and normal in eye space getEyeSpace(eyeNorm, eyePosition); // Evaluate the lighting equation. LightIntensity = phongModel( eyePosition, eyeNorm ); gl_Position = MVP * vec4(VertexPosition,1.0); }
GL_QUADが非推奨になったらしいので(知ってた)GL_TRIANGLE_STRIPで立方体を描きます。
これをやる理由はシェーディングをやりたいんだけどある程度まともな形をしてないと見ても評価ができないから。
インデクスバッファつかうのが正しいのだろうけれどまだできないので面ごとに描きます。
※矢印は別
void set(std::vector<GLfloat>& v, GLfloat x, GLfloat y, GLfloat z) { v.push_back(x); v.push_back(y); v.push_back(z); }
std::vector<GLfloat> vtx; std::vector<GLfloat> col; double width = 1; double m = -width / 2; double p = width / 2; double xp = p; double yp = p; double zp = p; double xm = m; double ym = m; double zm = m; //(A) set(vtx,xp, yp, zm); set(vtx,xp, ym, zm); set(vtx,xm, yp, zm); set(vtx,xm, ym, zm); //(B) set(vtx, xp, yp, zp); set(vtx, xp, ym, zp); set(vtx, xp, yp, zm); set(vtx, xp, ym, zm); //(C) (Aの反対) set(vtx, xm, ym, zp); set(vtx, xp, ym, zp); set(vtx, xm, yp, zp); set(vtx, xp, yp, zp); //(D)(Bの反対) set(vtx, xm, ym, zm); set(vtx, xm, ym, zp); set(vtx, xm, yp, zm); set(vtx, xm, yp, zp); //上 set(vtx, xp, yp, zm); set(vtx, xm, yp, zm); set(vtx, xp, yp, zp); set(vtx, xm, yp, zp); //下 set(vtx, xp, ym, zp); set(vtx, xm, ym, zp); set(vtx, xp, ym, zm); set(vtx, xm, ym, zm); //(A) set(col, 1.0, 0.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 0.0, 0.0, 1.0); set(col, 1.0, 1.0, 1.0); //(B) set(col, 1.0, 1.0, 0.0); set(col, 0.0, 1.0, 1.0); set(col, 1.0, 0.0, 0.0); set(col, 0.0, 1.0, 0.0); //(C) (Aの反対) set(col, 1.0, 0.0, 0.0); set(col, 0.0, 1.0, 1.0); set(col, 0.0, 1.0, 0.0); set(col, 1.0, 1.0, 0.0); //(D)(Bの反対) set(col, 1.0, 1.0, 1.0); set(col, 1.0, 0.0, 0.0); set(col, 0.0, 0.0, 1.0); set(col, 0.0, 1.0, 0.0); //上 set(col, 1.0, 0.0, 0.0); set(col, 0.0, 0.0, 1.0); set(col, 1.0, 1.0, 0.0); set(col, 0.0, 1.0, 0.0); //下 set(col, 0.0, 1.0, 1.0); set(col, 1.0, 0.0, 0.0); set(col, 0.0, 1.0, 0.0); set(col, 1.0, 1.0, 1.0); glGenBuffers(1, &buf_v_name); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &vtx[0], GL_STATIC_DRAW ); glGenBuffers(1, &buf_c_name); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glBufferData( GL_ARRAY_BUFFER, 4 * 6 * 3 * sizeof(GLfloat), &col[0], GL_STATIC_DRAW );
glUseProgram(m_shader.getProgramID()); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, buf_v_name); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(x,y,z)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, buf_c_name); glVertexAttribPointer( 1, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(r,g,b)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); glEnable(GL_CULL_FACE); // 三角形を描きます! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glUseProgram(0);
両方とも特に変わったことはしていない
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 color; //行列 uniform mat4 gl_ModelViewMatrix; //モデルビュー行列 uniform mat4 gl_ProjectionMatrix; //透視投影変換行列 out vec3 c; //色の出力先 void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); c = color; }
#version 460 core out vec4 FragColor; in vec3 c; void main() { FragColor = vec4( c , 1.0); }
シェーダを使ってワイヤーフレーム表示します。
●Vertex Shaderは各頂点ごとに呼び出される。
●Fragment Shaderはピクセルごとに呼び出される
つまり処理単位が違う。では、
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 2) in vec3 color;//頂点ごとの入力 out vec3 vColor; uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); vColor = color;//フラグメントシェーダに出力 }
というVertex Shaderがあったとき、頂点毎にoutされたvColorはFragment Shader側でどうなっているのか?
答えは、各頂点でoutされたvColor、つまり三つのvColorの値が、重心座標系で補間されて入力される。
描画したい三角形の各頂点にそれぞれ(1,0,0),(0,1,0),(0,0,1)のデータを付加し、それを頂点シェーダで読み取り、そのままフラグメントシェーダに渡すと、勝手に重心座標系で補間された座標値になる。
つまりフラグメントシェーダ側で、重心座標系で「( 0.01 , 0.0 , 0.0 )未満 or ( 0.0 , 0.01 , 0.0 ) 未満 or ( 0.0 , 0.0 , 0.01 ) 未満」 の領域を塗れば、ワイヤーフレーム表示と同じ状態になる。
//バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 GLuint barycentricbuffer; points_t position[9]; points_t color[9]; points_t barycentric[9]; void set(GLfloat* p, GLfloat a, GLfloat b, GLfloat c) { p[0] = a; p[1] = b; p[2] = c; } ////////////////////////////////////////////////// void prepare_buffers() { // position ... 頂点座標 // barycentric ... 重心座標系用 // color ... 色 //三角形1 set(position[0], 0.0, 0.5, 0);set(barycentric[0], 1, 0, 0);set(color[0], 1, 0, 0); set(position[1], 0.5, -0.5, 0);set(barycentric[1], 0, 1, 0);set(color[1], 0, 1, 0); set(position[2], -0.5, -0.5, 0);set(barycentric[2], 0, 0, 1);set(color[2], 0, 0, 1); //三角形2 set(position[3], 0.0, 0.5, 0);set(barycentric[3], 1, 0, 0);set(color[3], 1, 0, 0); set(position[4], -1.0, 0.5, 0);set(barycentric[4], 0, 1, 0);set(color[4], 1, 1, 0); set(position[5], -0.5, -0.5, 0);set(barycentric[5], 0, 0, 1);set(color[5], 0, 0, 1); //三角形3 set(position[6], -1.0, 0.5, 0); set(barycentric[6], 1, 0, 0); set(color[6], 1, 1, 0); set(position[7], -1.5, -0.5, 0); set(barycentric[7], 0, 1, 0); set(color[7], 0, 1, 1); set(position[8], -0.5, -0.5, 0); set(barycentric[8], 0, 0, 1); set(color[8], 0, 0, 1); glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), position, GL_STATIC_DRAW); glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), color, GL_STATIC_DRAW); glGenBuffers(1, &barycentricbuffer); glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), barycentric, GL_STATIC_DRAW); }
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 // 配列バッファオフセット ); //重心座標計算用バッファを有効にする glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer); glVertexAttribPointer( 2, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 9); glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glFlush(); }
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 incolor; layout (location = 2) in vec3 barycentric; out vec4 vertexColor; out vec3 baryxyz; 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); baryxyz = barycentric; }
#version 460 core out vec4 FragColor; in vec4 vertexColor; in vec3 baryxyz; void main() { if( baryxyz.x < 0.01 || baryxyz.y < 0.01 || baryxyz.z < 0.01 ){ FragColor= vec4(1,1,1,1); } else{ FragColor = vertexColor; } }
ところが重心座標系の座標値は三角形の形状に依存する。つまり、鋭角三角形などではエッジがちゃんと表示できない。
・https://tchayen.github.io/wireframes-with-barycentric-coordinates/
・http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
上記サイトではfwidthを使って解決している。(解説したいが自分自身がわかっていない)
#version 460 core out vec4 FragColor; in vec4 vertexColor; in vec3 baryxyz; const float lineWidth = 1.0; //エッジの太さ const vec3 lineColor = vec3(1.0, 1.0, 1.0); //エッジの色 float edgeFactor() { vec3 d = fwidth( baryxyz ); vec3 f = step( d * lineWidth, baryxyz ); return min( min( f.x, f.y ), f.z ); } void main() { FragColor.rgb = mix( lineColor, vertexColor.xyz, edgeFactor() ); }
・https://qiita.com/edo_m18/items/71f6064f3355be7e4f45
・https://qiita.com/gam0022/items/1342a91d0a6b16a3a9ba
上記フラグメントシェーダのedgeFactorは、そのピクセルがエッジ該当領域なら0.0を、そうでなければ1.0を返す。
0.0が帰ってきたらエッジ色で塗り、それ以外のケースではdiscardして着色を破棄するとワイヤーフレーム表示になる。
#version 460 core out vec4 FragColor; in vec4 vertexColor; in vec3 baryxyz; const float lineWidth = 3.0; //エッジの太さ const vec3 lineColor = vec3(1.0, 1.0, 1.0); //エッジの色 float edgeFactor() { vec3 d = fwidth(baryxyz); vec3 f = step(d * lineWidth, baryxyz); return min(min(f.x, f.y), f.z); } void main() { if( edgeFactor() < 0.1 ){ //0.0ならエッジ。シェーダは詳しくないが浮動小数点を==比較したくない FragColor.rgb = lineColor; } else{ discard; } }
#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 prepare_buffers(); void prepare_vertex_shader(); void prepare_fragment_shader(); void link_program(); void init(void) { //頂点データと色情報の作成 prepare_buffers(); //頂点シェーダの準備 prepare_vertex_shader(); //フラグメントシェーダの準備 prepare_fragment_shader(); //プログラムのリンク link_program(); } //バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 GLuint barycentricbuffer; points_t position[9]; points_t color[9]; points_t barycentric[9]; void set(GLfloat* p, GLfloat a, GLfloat b, GLfloat c) { p[0] = a; p[1] = b; p[2] = c; } ////////////////////////////////////////////////// void prepare_buffers() { // position ... 頂点座標 // barycentric ... 重心座標系用 // color ... 色 //三角形1 set(position[0], 0.0, 0.5, 0);set(barycentric[0], 1, 0, 0);set(color[0], 1, 0, 0); set(position[1], 0.5, -0.5, 0);set(barycentric[1], 0, 1, 0);set(color[1], 0, 1, 0); set(position[2], -0.5, -0.5, 0);set(barycentric[2], 0, 0, 1);set(color[2], 0, 0, 1); //三角形2 set(position[3], 0.0, 0.5, 0);set(barycentric[3], 1, 0, 0);set(color[3], 1, 0, 0); set(position[4], -1.0, 0.5, 0);set(barycentric[4], 0, 1, 0);set(color[4], 1, 1, 0); set(position[5], -0.5, -0.5, 0);set(barycentric[5], 0, 0, 1);set(color[5], 0, 0, 1); //三角形3 set(position[6], -1.0, 0.5, 0); set(barycentric[6], 1, 0, 0); set(color[6], 1, 1, 0); set(position[7], -1.5, -0.5, 0); set(barycentric[7], 0, 1, 0); set(color[7], 0, 1, 1); set(position[8], -0.5, -0.5, 0); set(barycentric[8], 0, 0, 1); set(color[8], 0, 0, 1); glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), position, GL_STATIC_DRAW); glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), color, GL_STATIC_DRAW); glGenBuffers(1, &barycentricbuffer); glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 9 * sizeof(GLfloat), barycentric, GL_STATIC_DRAW); } GLuint VertexShaderID; void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります // (作るといっても宣言みたいなもの) VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、 // OpenGL命令は一つも無い。 const char* vertex_file_path = ".\\vertex.shader"; 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]); } } GLuint FragmentShaderID; void prepare_fragment_shader() { ///////////////////////////////////////////// // シェーダを作ります。 FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 const char* fragment_file_path = ".\\fragment.shader"; 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]); } } 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]); } 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 // 配列バッファオフセット ); //重心座標計算用バッファを有効にする glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, barycentricbuffer); glVertexAttribPointer( 2, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 9); glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glFlush(); }
順序が大幅にずれた感があるが点の表示について。
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; }
System::XML::Linqをリンクする
以下を先頭に追加
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); }