sitemap
このサイトのプログラミングは、基本的にArduino/Processing上で動かすものを掲載していく予定です。所詮メモですし、専門性よりも動かしやすさ重視で。
このサイトのプログラミングは、基本的にArduino/Processing上で動かすものを掲載していく予定です。所詮メモですし、専門性よりも動かしやすさ重視で。
コンピュータ上における画像処理のためのソフトウェア処理。
モデリングデータ上の座標からスクリーン座標への変換、ラスタライズ(スクリーン座標からピクセル配列への変換)を行ない、以下のシェーダへデータを渡し、実際の描画処理を行なわせる。
このとき、モデリングデータは小図形(ポリゴン)として扱われるため、頂点の集合として扱われている。
ピクセル単位で色指定といった処理を行なう。
OpenGLではフラグメント(断片)シェーダという。
ピクセル、ライン、トライアングルといった基本図形(プリミティブ)から、複雑な新しい図形を生成し、ピクセルシェーダへデータを渡す。
OpenGLではプリミティブシェーダという。
“OpenGL Shading Language”の略。C言語ベースの高レベルシェーディング言語。
直接描画をすることはできないが、GLSLファイル(.glsl)を読込むことで、ハードウェア・ソフトウェアの互換性を問わずレンダリングすることができる(描画方法の指定のみをする言語。描画は別ソフトが担当する)。
//***.glsl //変数を記述 void main(){ //処理を記述 }
データ型 | 意味 | 備考 |
---|---|---|
void | 戻り値無し | 関数専用 |
bool | 論理型 | true/false |
int | 符号付き整数 | |
float | 符号付浮動小数点数 | |
vec* | *次元浮動小数型ベクトル | wikipedia記載は 2≦*≦4 範囲のみ |
bvec* | *次元論理型ベクトル | |
ivec* | *次元整数型ベクトル | |
mat* | *x*次元浮動小数型行列 | |
sampler*D | *次元テクスチャアクセスハンドル | wikipedia記載は 1≦*≦3 範囲のみ |
samplerCube | キューブマップテクスチャアクセスハンドル | |
sampler*DShadow | *次元デプステクスチャアクセスハンドル | wikipedia記載は 1≦*≦2 範囲のみ |
修飾詞 | 意味 |
---|---|
const | 定数 |
uniform | グローバル変数 |
in | 入力変数 |
out | 出力変数 |
inout | 入出力変数 |
要素の参照は、座標(x,y,z,w)、色(r,g,b,a)、テクスチャ(s,t,p,q)の用途によって自由に使い分けられる。
// ベクトル型配列の要素参照 vec4 v = vec4(0.0, 1.0, 2.0, 3.0); // 1要素のみ参照 v.x; // float 0.0 v.y; // float 1.0 v.z; // float 2.0 v.w; // float 3.0 v.r; // float 0.0 v.g; // float 1.0 v.b; // float 2.0 v.a; // float 3.0 // 複数要素の参照 v.xy; // vec2(0.0, 1.0) v.yx; // vec2(1.0, 0.0) … 順序を変えても良い v.xz; // vec2(0.0, 2.0) … 隣同士でなくても良い v.rgb; // vec3(0.0, 1.0, 2.0) … rgbaでも良い v.xyzw; // vec4 v … 全てでも良い
// エラー例 vec2 v2 = vec2(0.0, 1.0); v4.z; // 第3要素なし→error vec3 v3 = vec3(0.0, 1.0, 2.0); v3.w; // 第4要素なし→error
要素の参照は、多次元配列と同様に行なえる。
(GLSLでは、多次元配列使えませんけどね…)
// 行列の使用例 mat2 m = mat2(0.0, 1.0, 2.0, 3.0); /* m = | 0.0 1.0 | | 2.0 3.0 | */ // 各要素 m[0][0]; // float 0.0 m[0][1]; // float 1.0 m[1][0]; // float 2.0 m[1][1]; // float 3.0 // 行からベクトルを取得 m[0]; // vec2(0.0, 1.0)
1次元配列のみ使用可能(GLSL4.20まで)。(GLSL4.30よりok)配列の大きさは動的な変更は不可能。
// 配列の宣言例 float f0[5]; const int size = 5; float f1[size]; // 定数(const)使用可
struct [構造体型名]{ // メンバ変数の定義 int a; float b; vec3 c; } [構造体名]
C言語風ではあるが、キャストは使用不可なので、型変換の関数を用いる。
// int float boolの相互変換 // int型へ変換 int(true); // = 1 int(false); // = 0 int(float); // 小数以下切捨て // float型へ変換 float(true); // = 1.0 float(false); // = 0.0 float(int); // 型は変わるが同じ値のまま // bool型へ変換 bool(int); // ==0.0 → false / != 0.0 → true bool(float); // ==0 → false / != 0 → true
// ベクトル型の変換 vec*(float); // 全成分が同じ値 vec*(ivec*); // int型→float型 bvec*(int, float, …); // bool型変換に従いtrue/false vec2(vec3); // 3成分目切捨て→2次元ベクトル vec3(vec4); // 4成分目切捨て→3次元ベクトル vec3(vec2, float); // (vec2.x, vec2.y, float) vec3(float, vec2); // (float, vec2.x, vec2.y) vec4(vec2, vec2); // (vec2.x, vec2.y, vec2.x, vec2.y)
// 行列型の変換 mat*(a); // 対角要素 = a; 他要素 = 0.0 の対角行列 mat*(vec*, vec*, …); // "列"ベクトルを並べた行列
// キャストは使用不可 int a = 1 ; float b = (float) a ; // error
シェーダ | 入出力 | データ型 | クラス・変数 | 属性 | 意味 | 備考 |
---|---|---|---|---|---|---|
PS | 入力 | vec4 | gl_FragCoord | .x .y .z .w |
ウィンドウ座標 | |
出力 | vec4 | gl_FragColor | .r .g .b .a |
色取得・指定 | (r,g,b,a):赤、緑、青、不透明度(各0~1) (例) vec4(1.0):白色 |
GLSL自体には処理を実行する機能はない。
GLSLで記述された処理を、Processing(P5)で出力する例を紹介する。
スケッチフォルダ ├─***.pde └─data └─shader.glsl
// P5スケッチ:***.pde PShader sd; // シェーダクラス void setup() { size([width], [height], P2D); // GLSLファイル読込 sd = loadShader("shader.glsl"); } void draw() { // シェーダへ値を渡す sd.set("[GLSL内uniform変数名]",[値],…); // シェーダ描画 shader(sd); // ※これだけでは何も描画されない // 描画エリア指定 rect(0, 0, width, height); // ここで描画する図形は、stroke,fillと無関係 resetShader(); // これ以降は、通常の描画が行なわれる // 通常の描画処理を記述 }
// GLSLデータ:shader.glsl // ***.pdeのあるフォルダ内にある"data"フォルダ内に配置 void main(){ // 処理を記述 }
悪いこと言わん、コメントに日本語使うなら、“UTF-8 without BOM”にしとけ。
テクスチャハンドル … filter
エリア指定がなくとも、全体に処理
レンダラ | 座標系 | デフォルト原点 | 備考 |
---|---|---|---|
Processing | 左手(z軸:手前正方向) | 左上 | resetMatrix();の実行で原点中央 (軸方向はそのまま) |
GLSL | 左手 | 左下 | Processing上での座標変換は無関係 |
rect(10, 10, 100, 100); filter(sd); // 四角形:filter有効 filter(sd); rect(10, 10, 100, 100); // 四角形:filter無効
GLSLは、かなり厳密に変数型を見ています。
レンダラに使用するソフトによってはエラーを吐いてくれないと思います(P5は状況によりけり?)ので、注意してコーディングしましょう。
float a = 1 ; // error( a = 0.0 ; となる) float a = 1.0 ; // ok
ピクセルシェーダは、その名の通り、各ピクセルごとに対して処理を行なっている。
すなわちmain()関数は次のようになっているため、自分で総当たりさせる繰返し文を書く必要はない。
(正確にはループではなくGPU上での分散処理なので、座標順に処理をする訳ではない(…たぶんそのはず…))
for(int y = 0 ; y < height ; y++){ for(int x = 0 ; x < width ; x++){ main(); } }
また、「何も書かない処理」を避ける。
「GPUの描画処理自体をしない」ということになり、「上書きしない」という意味にはならない。
処理しないピクセルには、透明を指定すればよい。
if( *** ) gl_FragColor = vec4(1.0); // これだけでは、条件falseのピクセルは黒になる(暗黙的に以下の処理が追加される)。 else gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); // 黒 if( *** ) gl_FragColor = vec4(1.0); else gl_FragColor = vec4(0.0); // 透明
規格 | 横 | 縦 | アス比 | 備考 |
---|---|---|---|---|
QVGA | 320 | 240 | 4:3 | |
VGA | 640 | 480 | 4:3 | |
XGA | 1024 | 768 | 4:3 | |
SXGA | 1280 | 1024 | 4:3 | |
HDTV720 | 1280 | 720 | 16:9 | |
HDTV1080 | 1920 | 1080 | 16:9 | |
WVGA | 800 | 480 | 5:3 | Galaxy SⅡ(縦横逆比) |