型・演算・swizzling
GLSL のベクトル・行列の扱いと、独自記法の swizzling。 ここを使いこなせると、コードが一気に短く・速く書ける。
ベクトル型: vec2 / vec3 / vec4
作り方
vec2 a = vec2(1.0, 2.0);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(0.5); // 全成分 0.5(ブロードキャスト)
vec4 d = vec4(b, 1.0); // vec3 + float = vec4
vec4 e = vec4(a, a); // vec2 + vec2 = vec4
vec4 f = vec4(1.0); // (1,1,1,1)
要素アクセス
以下の3グループのどれを使ってもよい。意味で使い分けると読みやすい。
.x .y .z .w— 座標.r .g .b .a— 色.s .t .p .q— テクスチャ座標
vec3 v = vec3(1.0, 2.0, 3.0);
float x = v.x; // 1.0
float r = v.r; // 1.0(同じ)
float s = v.s; // 1.0(同じ)
v.x = 10.0; // 書き込みも可
v.xg や v.rt のように異なるグループを混ぜるとコンパイルエラー。
v.xy / v.rgb / v.st のように同じグループ内で揃える。
swizzling
ベクトルの成分を順序を変えて取り出したり、複数まとめたりする記法。 これが GLSL の最大の便利機能。
並べ替え
vec3 a = vec3(1.0, 2.0, 3.0);
vec3 b = a.xyz; // (1, 2, 3) — 同じ
vec3 c = a.zyx; // (3, 2, 1) — 逆順
vec3 d = a.bgr; // (3, 2, 1) — RGB → BGR
vec2 e = a.xy; // (1, 2)
vec4 f = a.xyzz; // (1, 2, 3, 3) — 重複OK
vec4 g = a.xxxx; // (1, 1, 1, 1) — 全部同じも OK
vec4 から RGB だけ取る
vec4 col = texture(tex, uv);
vec3 rgb = col.rgb;
float alpha = col.a;
2要素を組む
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec2 center = uv - 0.5;
書き込みも swizzle できる
vec3 v = vec3(0.0);
v.xy = vec2(1.0, 2.0); // (1, 2, 0)
v.xz = vec2(3.0, 4.0); // (3, 2, 4)
// ただし重複は不可: v.xx = vec2(...) はエラー
ベクトル演算
component-wise(要素ごと)
ほぼすべての算術演算は要素ごと。
vec3 a = vec3(1.0, 2.0, 3.0);
vec3 b = vec3(2.0, 0.5, 4.0);
a + b; // (3.0, 2.5, 7.0)
a - b; // (-1.0, 1.5, -1.0)
a * b; // (2.0, 1.0, 12.0)
a / b; // (0.5, 4.0, 0.75)
スカラとの演算
vec3 a = vec3(1.0, 2.0, 3.0);
a * 2.0; // (2.0, 4.0, 6.0)
a + 1.0; // (2.0, 3.0, 4.0)
1.0 / a; // (1.0, 0.5, 0.333)
内積(dot)
dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z。
2つの方向の同じ向きさを表す。法線とライト方向で明るさを出す時の基本。
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightDir);
float diffuse = max(dot(N, L), 0.0);
外積(cross)— 3次元のみ
cross(a, b) はa と b に直交するベクトル。法線計算に。
vec3 normal = normalize(cross(edge1, edge2));
長さ・正規化
length(v)— 長さ√(x² + y² + z²)distance(a, b)—length(a - b)normalize(v)— 長さを 1 に
vec2 p = vUv - 0.5;
float r = length(p); // 中心からの距離
vec2 dir = normalize(p); // 中心から外向きの単位ベクトル
整数とブール
int / uint
int i = 5;
uint u = 10u; // u サフィックス
int fromFloat = int(3.7); // 3(切り捨て)
float toFloat = float(i); // 5.0
bool 演算
bool a = true;
bool b = (x > 0.5);
if (a && b) { ... }
if (a || !b) { ... }
ベクトル全体の真偽
bvec の全要素が真かを判定:
bvec3 bv = greaterThan(v, vec3(0.5)); // 各要素を比較
bool all_pos = all(bv);
bool any_pos = any(bv);
行列型: mat2 / mat3 / mat4
作り方
// 単位行列
mat3 I = mat3(1.0);
// 列ベクトルから(列優先)
mat3 m = mat3(
vec3(1.0, 0.0, 0.0), // 1列目
vec3(0.0, 1.0, 0.0), // 2列目
vec3(0.0, 0.0, 1.0) // 3列目
);
// 各成分を直接
mat2 r = mat2(
cos(a), -sin(a),
sin(a), cos(a)
);
GLSL の行列は列優先(column-major)。m[0] は1列目のベクトル。
行列とベクトルの掛け算
vec3 v = vec3(1.0, 0.0, 0.0);
vec3 transformed = m * v; // 線形変換
// 4x4 行列で位置を変換
vec4 pos = vec4(position, 1.0);
vec4 worldPos = modelMatrix * pos;
行列同士の掛け算
mat4 mvp = projectionMatrix * viewMatrix * modelMatrix;
gl_Position = mvp * vec4(position, 1.0);
要素アクセス
mat3 m = mat3(1.0);
vec3 col0 = m[0]; // 1列目
float a = m[0][1]; // 1列目の y 成分
転置・逆行列
transpose(m)— 転置inverse(m)— 逆行列(GLSL ES 3.00+。重い)determinant(m)— 行列式
2D / 3D 回転行列
mat2 rot2(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
vec2 p = (vUv - 0.5) * rot2(uTime);
mat3 rotY(float a) {
float c = cos(a), s = sin(a);
return mat3(
c, 0.0, -s,
0.0, 1.0, 0.0,
s, 0.0, c
);
}
ベクトルから行列を作る(外積から TBN)
Tangent / Bitangent / Normal の TBN 行列。法線マップのときに使う。
vec3 N = normalize(vNormal);
vec3 T = normalize(vTangent);
vec3 B = normalize(cross(N, T));
mat3 TBN = mat3(T, B, N);
暗黙の型変換ルール
GLSL は暗黙の変換に厳しい。
int→floatは OK(自動)float→intは NG(明示的にint(x))- サイズの違うベクトル間(
vec3↔vec4)は NG。vec4(v, 1.0)等で明示 - 異なる成分型(
ivec3↔vec3)は NG。vec3(iv)で明示
定数と const
const float PI = 3.14159265358979;
const vec3 UP = vec3(0.0, 1.0, 0.0);
const int ITER = 8;
const はコンパイル時定数。配列の長さに使うなら必須:
const int N = 16;
float weights[N] = float[N](...);
典型パターン
距離フィールド(円までの距離)
float circleSDF(vec2 p, float r) {
return length(p) - r;
}
float d = circleSDF(vUv - 0.5, 0.3);
float c = smoothstep(0.005, -0.005, d); // エッジを滑らかに
2D 座標の正規化(アスペクト比補正)
vec2 uv = gl_FragCoord.xy / uResolution.xy;
uv -= 0.5;
uv.x *= uResolution.x / uResolution.y; // アスペクト補正
2D ベクトルの極座標
vec2 p = vUv - 0.5;
float r = length(p);
float a = atan(p.y, p.x); // -π..π
反射ベクトル
vec3 R = reflect(-V, N); // V を N で反射(ハイライト計算等)
2 色の補間
vec3 col = mix(
vec3(0.0, 0.5, 1.0), // a
vec3(1.0, 0.2, 0.5), // b
smoothstep(0.3, 0.7, vUv.x) // t
);
swizzle が効くケースの実例
RGB の 2 チャンネルだけ反転
vec3 c = vec3(0.2, 0.5, 0.8);
c.gb = 1.0 - c.gb; // (0.2, 0.5, 0.2)
UV を x だけスクロール
vec2 uv = vUv;
uv.x += uTime * 0.1;
Y を反転
vec2 uv = vUv;
uv.y = 1.0 - uv.y;
2D ベクトルから vec4(パディング)
vec2 p = vec2(1.0, 2.0);
vec4 v = p.xyyy; // (1, 2, 2, 2)
vec4 w = vec4(p, 0.0, 1.0); // 等価
スウィズルのよく使う組み合わせをパターンとして覚えると、コードがすっきり書ける:
- v.xy / v.xz / v.yz — 2D 平面の取り出し
- v.xyz — 3D 部分(vec4 から色だけ)
- v.rgb / v.a — 色と α の分離
- v.bgr — BGR 形式への並び替え