固定機能との違い

固定機能とプログラマブルシェーダーでは何がどう違うのでしょう。
固定機能ではフラットシェーディングやグーローシェーディング(スムースシェーディング)、
ワイヤーフレーム表示程度しかありませんでした。
擬似的にトゥーンシェーディングっぽく表示する事もできますが、トゥーンシェーディング
とは全然品質が違います。

固定機能というのは、あらかじめ用意された範囲内で簡単手軽に機能を切り替えたり
描画に関する事を全て 『用意された中から選んで設定する』 という物でした。

簡単手軽ですが、グラフィックスで表現できる幅が文字通り固定されています。
そこで、より幅広いグラフィックスを表現するためにプログラマブルシェーダーが登場しました。
ここでは、シェーダー使用の描画とシェーダー未使用の描画をしてみました。
左が固定機能パイプラインで描画、右がシェーダーで色を反転させて描画した物です。
シェーダーファイルの
gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力
で、gl_ModelViewMatrix を掛け合わせてやらないとモデルビューに行った操作が一切、
反映されないので注意が必要です。

 

シェーダープログラム(vertex.shader)

void main(void)
{
 gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力
 gl_FrontColor = vec4(1.0)-gl_Color;//頂点カラーの出力(反転)
 //gl_FrontColor = gl_Color;//そのまま出力
}

メインプログラム(main.cpp)

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#pragma comment(lib, "glew32.lib")
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut/freeglut.h>

#define WIDTH 320
#define HEIGHT 240

GLuint shaderProg;

GLuint vertexShader, fragmentShader;
//shader fileを読み込みコンパイルする
void readShaderCompile(GLuint shader, const char *file){
  FILE *fp;
  char *buf;
  GLsizei size, len;
  GLint compiled;
  // ファイルを開く
  fopen_s(&fp,file, "rb");
  if(!fp) printf("ファイルを開くことができません %s\n", file);
  //ファイルの末尾に移動し現在位置を得る
  fseek(fp, 0, SEEK_END);
  size = ftell(fp);//ファイルサイズを取得
  // ファイルサイズのメモリを確保
  buf = (GLchar *)malloc(size);
  if(buf == NULL){
    printf("メモリが確保できませんでした \n");
  }
  // ファイルを先頭から読み込む
  fseek(fp, 0, SEEK_SET);
  fread(buf, 1, size, fp);
  //シェーダオブジェクトにプログラムをセット
  glShaderSource(shader, 1, (const GLchar **)&buf, &size);
  //シェーダ読み込み領域の解放
  free(buf);
  fclose(fp);
  // シェーダのコンパイル
  glCompileShader(shader);
  glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
  if( compiled == GL_FALSE ){
   printf( "コンパイルできませんでした!!: %s \n ", file);
   glGetProgramiv( shader, GL_INFO_LOG_LENGTH, &size );
   if( size > 0 ){
    buf = (char *)malloc(size);
    glGetShaderInfoLog( shader, size, &len, buf);
    printf(buf);
    free(buf);
   }
  }
}

//リンクする
void link( GLuint prog ){
  GLsizei size, len;
  GLint linked;
  char *infoLog ;
  glLinkProgram( prog );
  glGetProgramiv( prog, GL_LINK_STATUS, &linked );
  if( linked == GL_FALSE ){
  printf("リンクできませんでした!! \n");
  glGetProgramiv( prog, GL_INFO_LOG_LENGTH, &size );
  if( size > 0 ){
   infoLog = (char *)malloc(size);
   glGetProgramInfoLog( prog, size, &len, infoLog );
   printf(infoLog);
   free(infoLog);
  }
  }
}
//GLSLの初期化
void initGlsl(GLuint *program, const char *vertexFile){
  //glewの初期化
  GLenum err = glewInit();
  if (err != GLEW_OK){
   printf("Error: %s\n", glewGetErrorString(err));
  }
  // GPU,OpenGL情報
  printf("VENDOR= %s \n", glGetString(GL_VENDOR));
  printf("GPU= %s \n", glGetString(GL_RENDERER));
  printf("OpenGL= %s \n", glGetString(GL_VERSION));
  printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  //シェーダーオブジェクトの作成
  vertexShader = glCreateShader(GL_VERTEX_SHADER);
  //シェーダーの読み込みとコンパイル
  readShaderCompile(vertexShader, vertexFile);
  // シェーダプログラムの作成
  *program = glCreateProgram();
  // シェーダオブジェクトをシェーダプログラムに関連付ける
  glAttachShader(*program, vertexShader);
  // シェーダオブジェクトの削除
  glDeleteShader(vertexShader);
  // シェーダプログラムのリンク
  link(*program);
}


void initGlsl(GLuint *program, const char *vertexFile, const char *fragmentFile){
  //glewの初期化
  GLenum err = glewInit();
  if (err != GLEW_OK){
   printf("Error: %s\n", glewGetErrorString(err));
  }
  // GPU,OpenGL情報
  printf("VENDOR= %s \n", glGetString(GL_VENDOR));
  printf("GPU= %s \n", glGetString(GL_RENDERER));
  printf("OpenGL= %s \n", glGetString(GL_VERSION));
  printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  //シェーダーオブジェクトの作成
  vertexShader = glCreateShader(GL_VERTEX_SHADER);
  fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  //シェーダーの読み込みとコンパイル
  readShaderCompile(vertexShader, vertexFile);
  readShaderCompile(fragmentShader, fragmentFile);
  // プログラムオブジェクトの作成
  *program = glCreateProgram();
  // シェーダオブジェクトをシェーダプログラムに関連付ける
  glAttachShader(*program, vertexShader);
  glAttachShader(*program, fragmentShader);
  // シェーダオブジェクトの削除
  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);
  // シェーダプログラムのリンク
  link(*program);
}

void Triangle(int x,int y,int size,float linesize){
 glLineWidth(linesize);
 //モード
 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 glBegin(GL_TRIANGLES);
 glColor4f(1.0f,0.0f,0.0f,1.0f);glVertex2i(x-size/2,y+size/2);
 glColor4f(0.0f,1.0f,0.0f,1.0f);glVertex2i(x,y-size/2);
 glColor4f(0.0f,0.0f,1.0f,1.0f);glVertex2i(x+size/2,y+size/2);
 glEnd();
}
void display(void){
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 Triangle(90,100,100,10);//固定機能で描画
 glUseProgram(shaderProg);//シェーダー描画に切り替え
 Triangle(230,100,100,10);//シェーダーで描画
 glUseProgram(0);//シェーダー解除
 glutSwapBuffers();
}
void idle(void){
 glutPostRedisplay();
}
void Init(){
 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 glOrtho(0, WIDTH, HEIGHT, 0, -1, 1);
}
void main(int argc, char *argv[]){
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("固定機能とシェーダーで描画");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 initGlsl(&shaderProg, "vertex.shader");
 Init();
 glutMainLoop();
 glDeleteProgram(shaderProg);
 return;
}

 

 

 

 

 

 

 

最終更新:2014年04月30日 21:12
添付ファイル