ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • GLSLを試す (7) シェーディング

    この記事の概要

    モダン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)のソースコードが載っているのでほぼそのままコピペで使える。

    Implementing per-vertex ambient, diffuse, and specular (ADS) shading
    基本のADSシェーディングのコード
    Using functions in shaders
    基本のを関数化したもの
    Implementing two-sided shading
    裏面も表示できるようにしたもの
    Implementing flat shading
    フラットシェーディング。つまり面法線で反射計算するようなやつ。

    今回はこの中でUsing Functions in Shadersの項目にあるシェーダを使う。

    ただし以下私が書いたCのソースでは各面ごとに頂点を用意してそれぞれの頂点に同じ面法線を用意しているのでスムーズシェーディングのシェーダなんだけれどフラットシェーディングと同じ効果になっている。

    ソースコード

    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);
    }
    

    実行結果1

    色がついていないように見えるのは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);
    }