Shaderプログラミング勉強 1日目
Shaderを身につけたかったので色々勉強することにしました。 元々少しかじってましたが、実践につかったことなかったので全く身についてませんでした。 ブログにアウトプットすることによってもう少しに身につけていきたい。 記載している内容はThe book of Shadersに記載されていることと変わりないので、そちらを参照していただいたほうがいいです。
Shaderとは
画像処理において全てのピクセルに対して並列に計算を実行してくれるもの。GLSLという言語で記述する。高速にきれいな絵が描ける。 Fragment ShaderとVertex Shaderの2種類のファイルを記述する。 Fragment Shaderは色情報の記述。 Vertex Shaderは頂点情報の記述。
Fragment Shader初歩
まずはサンプルコード。
#ifdef GL_ES precision mediump float; #endif void main() { gl_FragColor = vec4(1.0,0.0,1.0,1.0); }
main関数内に色情報に関する記載をする。gl_FragColorは色情報を保持する予約語(*)。このmain関数内の意味はR, B, A情報を1にした色情報にするという意味。 * gl_FragColorは1.31から非推奨になったとのこと。開発者が自由に変数名を決めれるっぽい。
また、GLSLでは浮動小数点の精度が結構重要になってくる。このため、浮動小数点型の精度を指定することができる。精度が高ければ品質が上がるけど速度が下がる。精度が低ければ品質は下がるけど速度が上がる。
precision lowp float; // 低精度 precision mediump float; // 中精度 precision highp float; // 高精度
一番最初の例ではopenGLESでは中精度のfloat値を使用するということを宣言している。
uniform変数
Shaderでは並列処理をするため、CPUから各ピクセルごとに独立した変数を渡すことはできないけど、一様に変数を渡すことはできる。それがuniform変数。 型としてはfloat、vec2、vec3、vec4、mat2、mat3、mat4、sampler2D、samplerCubeなどがあるとのこと。 浮動小数点精度の宣言の後に記載すれば良い。
#ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Canvas size (width,height) uniform vec2 u_mouse; // mouse position in screen pixels uniform float u_time; // Time in seconds since load
例えばu_timeに経過時間を送ってあげるとこんな感じで時間経過ごとに色変化を行うことができる。
#ifdef GL_ES precision mediump float; #endif uniform float u_time; void main() { float freq = 6.0; gl_FragColor = vec4(abs(sin(u_time*freq) - 0.3),abs(sin(u_time*freq) - 0.7),abs(sin(u_time*freq)),1.0); }
gl_FragCoord
gl_FragCoordはピクセルの位置を保持してる。これはスレッドごとに異なる値を持つため、varying変数と呼ぶ。ここでいう"スレッド"とは1ピクセルごとみたいな理解を僕はしてる。
openFrameworksで使用する場合
こんな感じ
void ofApp::setup(){ ofShader shader; shader.load("", "フラグメントシェーダを記述したファイル"); } void ofApp::draw(){ shader.begin(); shader.setUniform1f("u_time", ofGetElaplsedTimef()); // ここでuniform変数を渡してる ofRect(0, 0, ofGetWidth(), ofGetHeight()); // この領域にShaderで記述した部分が記載される shader.end(); }