「固定機能との違い」の編集履歴(バックアップ)一覧はこちら
「固定機能との違い」(2014/04/30 (水) 21:12:40) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
<p><strong>固定機能とプログラマブルシェーダーでは何がどう違うのでしょう。<br />
固定機能ではフラットシェーディングやグーローシェーディング(スムースシェーディング)、<br />
ワイヤーフレーム表示程度しかありませんでした。<br />
擬似的にトゥーンシェーディングっぽく表示する事もできますが、トゥーンシェーディング<br />
とは全然品質が違います。</strong></p>
<p><strong>固定機能というのは、あらかじめ用意された範囲内で簡単手軽に機能を切り替えたり<br />
描画に関する事を全て 『用意された中から選んで設定する』 という物でした。</strong></p>
<p><strong>簡単手軽ですが、グラフィックスで表現できる幅が文字通り固定されています。<br />
そこで、より幅広いグラフィックスを表現するためにプログラマブルシェーダーが登場しました。<br />
ここでは、シェーダー使用の描画とシェーダー未使用の描画をしてみました。<br />
左が固定機能パイプラインで描画、右がシェーダーで色を反転させて描画した物です。<br />
シェーダーファイルの<br />
gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力<br />
で、gl_ModelViewMatrix を掛け合わせてやらないとモデルビューに行った操作が一切、<br />
反映されないので注意が必要です。</strong></p>
<p> <img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&act=open&pageid=38&file=shader.png" /></p>
<p>シェーダープログラム(vertex.shader)</p>
<table border="1" cellspacing="1" cellpadding="1" width="600"><tbody><tr><td><font size="2">void main(void)<br />
{<br />
gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力<br />
gl_FrontColor = vec4(1.0)-gl_Color;//頂点カラーの出力(反転)<br />
//gl_FrontColor = gl_Color;//そのまま出力<br />
}</font></td>
</tr></tbody></table><p>メインプログラム(main.cpp)</p>
<table border="1" cellspacing="1" cellpadding="1" width="600"><tbody><tr><td>
<p><font size="2">#pragma comment(linker, "/SUBSYSTEM:WINDOWS
/ENTRY:mainCRTStartup")<br />
#pragma comment(lib, "glew32.lib")<br />
#include <stdio.h><br />
#include <GL/glew.h><br />
#include <GL/freeglut/freeglut.h></font></p>
<p><font size="2">#define WIDTH 320<br />
#define HEIGHT 240</font></p>
<p><font size="2">GLuint shaderProg;</font></p>
<p><font size="2">GLuint vertexShader, fragmentShader;<br />
//shader fileを読み込みコンパイルする<br />
void readShaderCompile(GLuint shader, const char *file)<br />
{<br />
FILE *fp;<br />
char *buf;<br />
GLsizei size, len;<br />
GLint compiled;<br />
<br />
// ファイルを開く<br />
fopen_s(&fp,file, "rb");<br />
if(!fp) printf("ファイルを開くことができません %s\n", file);<br />
<br />
//ファイルの末尾に移動し現在位置を得る<br />
fseek(fp, 0, SEEK_END);<br />
size = ftell(fp);//ファイルサイズを取得<br />
<br />
// ファイルサイズのメモリを確保<br />
buf = (GLchar *)malloc(size);<br />
if (buf == NULL) {<br />
printf("メモリが確保できませんでした \n");<br />
}<br />
<br />
// ファイルを先頭から読み込む<br />
fseek(fp, 0, SEEK_SET);<br />
fread(buf, 1, size, fp);<br />
//シェーダオブジェクトにプログラムをセット<br />
glShaderSource(shader, 1, (const GLchar **)&buf, &size);<br />
//シェーダ読み込み領域の解放<br />
free(buf);<br />
fclose(fp);</font></p>
<p><font size="2"> // シェーダのコンパイル<br />
glCompileShader(shader);<br />
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );</font></p>
<p><font size="2"> if ( compiled == GL_FALSE )<br />
{<br />
printf( "コンパイルできませんでした!!: %s \n ", file);<br />
glGetProgramiv( shader, GL_INFO_LOG_LENGTH, &size );<br />
if ( size > 0 )<br />
{<br />
buf = (char *)malloc(size);<br />
glGetShaderInfoLog( shader, size, &len, buf);<br />
printf(buf);<br />
free(buf);<br />
}<br />
}<br />
}</font></p>
<p><font size="2">//リンクする<br />
void link( GLuint prog )<br />
{<br />
GLsizei size, len;<br />
GLint linked;<br />
char *infoLog ;</font></p>
<p><font size="2"> glLinkProgram( prog );</font></p>
<p><font size="2"> glGetProgramiv( prog, GL_LINK_STATUS, &linked
);</font></p>
<p><font size="2"> if ( linked == GL_FALSE )<br />
{<br />
printf("リンクできませんでした!! \n");<br />
<br />
glGetProgramiv( prog, GL_INFO_LOG_LENGTH, &size );<br />
if ( size > 0 )<br />
{<br />
infoLog = (char *)malloc(size);<br />
glGetProgramInfoLog( prog, size, &len, infoLog );<br />
printf(infoLog);<br />
free(infoLog);<br />
}<br />
}<br />
}<br />
//GLSLの初期化<br />
void initGlsl(GLuint *program, const char *vertexFile)<br />
{<br />
//glewの初期化<br />
GLenum err = glewInit();<br />
if (err != GLEW_OK)<br />
{<br />
printf("Error: %s\n", glewGetErrorString(err));<br />
}<br />
// GPU,OpenGL情報<br />
printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />
printf("GPU= %s \n", glGetString(GL_RENDERER));<br />
printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />
printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />
//シェーダーオブジェクトの作成<br />
vertexShader = glCreateShader(GL_VERTEX_SHADER);<br />
//シェーダーの読み込みとコンパイル<br />
readShaderCompile(vertexShader, vertexFile);</font></p>
<p><font size="2"> // シェーダプログラムの作成<br />
*program = glCreateProgram();</font></p>
<p><font size="2"> // シェーダオブジェクトをシェーダプログラムに関連付ける<br />
glAttachShader(*program, vertexShader);</font></p>
<p><font size="2"> // シェーダオブジェクトの削除<br />
glDeleteShader(vertexShader);</font></p>
<p><font size="2"> // シェーダプログラムのリンク<br />
link(*program);<br />
}</font></p>
<p><br /><font size="2">void initGlsl(GLuint *program, const char *vertexFile, const
char *fragmentFile)<br />
{<br />
//glewの初期化<br />
GLenum err = glewInit();<br />
if (err != GLEW_OK)<br />
{<br />
printf("Error: %s\n", glewGetErrorString(err));<br />
}<br />
// GPU,OpenGL情報<br />
printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />
printf("GPU= %s \n", glGetString(GL_RENDERER));<br />
printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />
printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />
//シェーダーオブジェクトの作成<br />
vertexShader = glCreateShader(GL_VERTEX_SHADER);<br />
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);<br />
//シェーダーの読み込みとコンパイル<br />
readShaderCompile(vertexShader, vertexFile);<br />
readShaderCompile(fragmentShader, fragmentFile);</font></p>
<p><font size="2"> // プログラムオブジェクトの作成<br />
*program = glCreateProgram();</font></p>
<p><font size="2"> // シェーダオブジェクトをシェーダプログラムに関連付ける<br />
glAttachShader(*program, vertexShader);<br />
glAttachShader(*program, fragmentShader);</font></p>
<p><font size="2"> // シェーダオブジェクトの削除<br />
glDeleteShader(vertexShader);<br />
glDeleteShader(fragmentShader);<br />
// シェーダプログラムのリンク<br />
link(*program);<br />
}</font></p>
<p><br /><font size="2">void Triangle(int x,int y,int size,float linesize){<br />
glLineWidth(linesize);<br />
//モード<br />
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);<br />
glBegin(GL_TRIANGLES);<br />
glColor4f(1.0f,0.0f,0.0f,1.0f);glVertex2i(x-size/2,y+size/2);<br />
glColor4f(0.0f,1.0f,0.0f,1.0f);glVertex2i(x,y-size/2);<br />
glColor4f(0.0f,0.0f,1.0f,1.0f);glVertex2i(x+size/2,y+size/2);<br />
glEnd();<br />
}<br />
void display(void)<br />
{<br />
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />
Triangle(90,100,100,10);//固定機能で描画<br />
glUseProgram(shaderProg);//シェーダー描画に切り替え<br />
Triangle(230,100,100,10);//シェーダーで描画<br />
glUseProgram(0);//シェーダー解除</font></p>
<p><font size="2"> glutSwapBuffers();<br />
}<br />
void idle(void)<br />
{<br />
glutPostRedisplay();<br />
}<br />
void Init(){<br />
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);<br />
glOrtho(0, WIDTH, HEIGHT, 0, -1, 1);<br />
}<br />
int main(int argc, char *argv[])<br />
{<br />
glutInitWindowPosition(100, 100);<br />
glutInitWindowSize(WIDTH, HEIGHT);<br />
glutInit(&argc, argv);<br />
glutCreateWindow("固定機能とシェーダーで描画");<br />
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />
glutDisplayFunc(display);<br />
glutIdleFunc(idle);<br />
initGlsl(&shaderProg, "vertex.shader");<br />
Init();<br />
glutMainLoop();<br />
glDeleteProgram(shaderProg);<br />
return 0;<br />
}</font></p>
</td>
</tr></tbody></table><p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p><strong>固定機能とプログラマブルシェーダーでは何がどう違うのでしょう。<br />
固定機能ではフラットシェーディングやグーローシェーディング(スムースシェーディング)、<br />
ワイヤーフレーム表示程度しかありませんでした。<br />
擬似的にトゥーンシェーディングっぽく表示する事もできますが、トゥーンシェーディング<br />
とは全然品質が違います。</strong></p>
<p><strong>固定機能というのは、あらかじめ用意された範囲内で簡単手軽に機能を切り替えたり<br />
描画に関する事を全て 『用意された中から選んで設定する』 という物でした。</strong></p>
<p><strong>簡単手軽ですが、グラフィックスで表現できる幅が文字通り固定されています。<br />
そこで、より幅広いグラフィックスを表現するためにプログラマブルシェーダーが登場しました。<br />
ここでは、シェーダー使用の描画とシェーダー未使用の描画をしてみました。<br />
左が固定機能パイプラインで描画、右がシェーダーで色を反転させて描画した物です。<br />
シェーダーファイルの<br />
gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力<br />
で、gl_ModelViewMatrix を掛け合わせてやらないとモデルビューに行った操作が一切、<br />
反映されないので注意が必要です。</strong></p>
<p> <img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&act=open&pageid=38&file=shader.png" /></p>
<p>シェーダープログラム(vertex.shader)</p>
<table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td><font size="2">void main(void)<br />
{<br />
gl_Position = gl_ModelViewMatrix * gl_Vertex;//頂点座標の出力<br />
gl_FrontColor = vec4(1.0)-gl_Color;//頂点カラーの出力(反転)<br />
//gl_FrontColor = gl_Color;//そのまま出力<br />
}</font></td>
</tr></tbody></table><p>メインプログラム(main.cpp)</p>
<table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td>
<p>#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br />
#pragma comment(lib, "glew32.lib")<br />
#include <stdio.h><br />
#include <GL/glew.h><br />
#include <GL/freeglut/freeglut.h></p>
<p>#define WIDTH 320<br />
#define HEIGHT 240</p>
<p>GLuint shaderProg;</p>
<p>GLuint vertexShader, fragmentShader;<br />
//shader fileを読み込みコンパイルする<br />
void readShaderCompile(GLuint shader, const char *file){<br />
FILE *fp;<br />
char *buf;<br />
GLsizei size, len;<br />
GLint compiled;<br />
// ファイルを開く<br />
fopen_s(&fp,file, "rb");<br />
if(!fp) printf("ファイルを開くことができません %s\n", file);<br />
//ファイルの末尾に移動し現在位置を得る<br />
fseek(fp, 0, SEEK_END);<br />
size = ftell(fp);//ファイルサイズを取得<br />
// ファイルサイズのメモリを確保<br />
buf = (GLchar *)malloc(size);<br />
if(buf == NULL){<br />
printf("メモリが確保できませんでした \n");<br />
}<br />
// ファイルを先頭から読み込む<br />
fseek(fp, 0, SEEK_SET);<br />
fread(buf, 1, size, fp);<br />
//シェーダオブジェクトにプログラムをセット<br />
glShaderSource(shader, 1, (const GLchar **)&buf, &size);<br />
//シェーダ読み込み領域の解放<br />
free(buf);<br />
fclose(fp);<br />
// シェーダのコンパイル<br />
glCompileShader(shader);<br />
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );<br />
if( compiled == GL_FALSE ){<br />
printf( "コンパイルできませんでした!!: %s \n ", file);<br />
glGetProgramiv( shader, GL_INFO_LOG_LENGTH, &size );<br />
if( size > 0 ){<br />
buf = (char *)malloc(size);<br />
glGetShaderInfoLog( shader, size, &len, buf);<br />
printf(buf);<br />
free(buf);<br />
}<br />
}<br />
}</p>
<p>//リンクする<br />
void link( GLuint prog ){<br />
GLsizei size, len;<br />
GLint linked;<br />
char *infoLog ;<br />
glLinkProgram( prog );<br />
glGetProgramiv( prog, GL_LINK_STATUS, &linked );<br />
if( linked == GL_FALSE ){<br />
printf("リンクできませんでした!! \n");<br />
glGetProgramiv( prog, GL_INFO_LOG_LENGTH, &size );<br />
if( size > 0 ){<br />
infoLog = (char *)malloc(size);<br />
glGetProgramInfoLog( prog, size, &len, infoLog );<br />
printf(infoLog);<br />
free(infoLog);<br />
}<br />
}<br />
}<br />
//GLSLの初期化<br />
void initGlsl(GLuint *program, const char *vertexFile){<br />
//glewの初期化<br />
GLenum err = glewInit();<br />
if (err != GLEW_OK){<br />
printf("Error: %s\n", glewGetErrorString(err));<br />
}<br />
// GPU,OpenGL情報<br />
printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />
printf("GPU= %s \n", glGetString(GL_RENDERER));<br />
printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />
printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />
//シェーダーオブジェクトの作成<br />
vertexShader = glCreateShader(GL_VERTEX_SHADER);<br />
//シェーダーの読み込みとコンパイル<br />
readShaderCompile(vertexShader, vertexFile);<br />
// シェーダプログラムの作成<br />
*program = glCreateProgram();<br />
// シェーダオブジェクトをシェーダプログラムに関連付ける<br />
glAttachShader(*program, vertexShader);<br />
// シェーダオブジェクトの削除<br />
glDeleteShader(vertexShader);<br />
// シェーダプログラムのリンク<br />
link(*program);<br />
}</p>
<p><br />
void initGlsl(GLuint *program, const char *vertexFile, const char
*fragmentFile){<br />
//glewの初期化<br />
GLenum err = glewInit();<br />
if (err != GLEW_OK){<br />
printf("Error: %s\n", glewGetErrorString(err));<br />
}<br />
// GPU,OpenGL情報<br />
printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />
printf("GPU= %s \n", glGetString(GL_RENDERER));<br />
printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />
printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />
//シェーダーオブジェクトの作成<br />
vertexShader = glCreateShader(GL_VERTEX_SHADER);<br />
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);<br />
//シェーダーの読み込みとコンパイル<br />
readShaderCompile(vertexShader, vertexFile);<br />
readShaderCompile(fragmentShader, fragmentFile);<br />
// プログラムオブジェクトの作成<br />
*program = glCreateProgram();<br />
// シェーダオブジェクトをシェーダプログラムに関連付ける<br />
glAttachShader(*program, vertexShader);<br />
glAttachShader(*program, fragmentShader);<br />
// シェーダオブジェクトの削除<br />
glDeleteShader(vertexShader);<br />
glDeleteShader(fragmentShader);<br />
// シェーダプログラムのリンク<br />
link(*program);<br />
}</p>
<p>void Triangle(int x,int y,int size,float linesize){<br />
glLineWidth(linesize);<br />
//モード<br />
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);<br />
glBegin(GL_TRIANGLES);<br />
glColor4f(1.0f,0.0f,0.0f,1.0f);glVertex2i(x-size/2,y+size/2);<br />
glColor4f(0.0f,1.0f,0.0f,1.0f);glVertex2i(x,y-size/2);<br />
glColor4f(0.0f,0.0f,1.0f,1.0f);glVertex2i(x+size/2,y+size/2);<br />
glEnd();<br />
}<br />
void display(void){<br />
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />
Triangle(90,100,100,10);//固定機能で描画<br />
glUseProgram(shaderProg);//シェーダー描画に切り替え<br />
Triangle(230,100,100,10);//シェーダーで描画<br />
glUseProgram(0);//シェーダー解除<br />
glutSwapBuffers();<br />
}<br />
void idle(void){<br />
glutPostRedisplay();<br />
}<br />
void Init(){<br />
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);<br />
glOrtho(0, WIDTH, HEIGHT, 0, -1, 1);<br />
}<br />
void main(int argc, char *argv[]){<br />
glutInitWindowPosition(100, 100);<br />
glutInitWindowSize(WIDTH, HEIGHT);<br />
glutInit(&argc, argv);<br />
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />
glutCreateWindow("固定機能とシェーダーで描画");<br />
glutDisplayFunc(display);<br />
glutIdleFunc(idle);<br />
initGlsl(&shaderProg, "vertex.shader");<br />
Init();<br />
glutMainLoop();<br />
glDeleteProgram(shaderProg);<br />
return;<br />
}</p>
</td>
</tr></tbody></table><p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>