はじめに
Three.jsの頃から、何となく Shader を触ってましたが、あたらめて学ぼうと入門講座をスタートしました。
全6回で、少しずつやってきます。
Unityにもシェーダーがあるようなので、出来るだけThree.jsとUnityの両方で役立つ講座にする予定です。
1. なぜシェーダーを学ぶのか?
ゲームでも Web でも、画面に映っているものはすべて「シェーダー」が描いている。 Three.js でも Unity でも例外はない。
- 光の反射
- 水のゆらぎ
- 影の落ち方
- 炎やオーロラのようなエフェクト
- 発光、透明、波、ノイズ
こういった“見た目の魔法”は、すべてシェーダーで作られる。
Three.js で GLSL を触ってから Unity に来ると、 「文法は違うのに仕組みは同じだ」 と気づく瞬間が必ずある。
理由はシンプルで、GPU が世界を描く仕組み自体は共通だから。
この連載では、Three.js(GLSL) と Unity(HLSL) の両方で、 同じテーマ・同じ考え方でシェーダーを学んでいく。
まず最初の本記事では、
“そもそもシェーダーって何なのか?”
この根本を、図解レベルでわかりやすく押さえる。
ここが理解できると、 どのゲームエンジンやライブラリに行っても迷わなくなる。
2. GPU がやっていること:三角形の加工工程
シェーダーを理解するうえで、まず知っておきたいのは次の事実です。
世界のあらゆる3Dモデルは、最終的に“三角形の集合体”として描かれている。
キャラクター、地形、木、建物、水面—— どれだけ複雑に見えても、レンダリングの瞬間には必ず「三角形のメッシュ」に分解されます。
では、この三角形たちを誰が画面に描いているのか?
それが GPU(グラフィックス専用プロセッサ) です。
GPU の本質的な仕事
GPU の役割は、とてもシンプルに言うと、
「大量の三角形を、爆速並列処理で塗りつぶす」
これだけです。
ただし、この処理量がとんでもない。
- 1フレームで数万〜数百万の三角形
- その1つ1つをピクセル単位で計算
- しかも毎秒60回(または90〜120回)
こんな処理、CPU では到底間に合いません。
だから GPU は“並列計算に特化した別脳みそ”になっている。
GPU が三角形を描くときの処理の流れ
GPU は次のような工程で画面を描きます。
- 頂点の位置を決める(Vertex Shader)
- 三角形に切り分ける
- 表面の色を決める(Fragment Shader)
- ピクセルに塗りつぶす
ここで出てきた Vertex Shader と Fragment Shader が、まさに今回学ぶ「シェーダー」。
つまりシェーダーとは、
GPU の三角形加工工程を“自分好みに書き換える”ための小さなプログラム
というわけです。
例:水面を揺らす場合(頂点シェーダーの仕事)
- 三角形の頂点を sin 波で上下させる
- 波の大きさを時間で変える
- 風の強さで揺らぎ方を変える
これは全部 Vertex Shader の担当。
例:炎や発光を作る場合(フラグメントシェーダーの仕事)
- 炎の色のゆらぎを noise で作る
- 発光の強さを中心からの距離で変える
- 深い水ほど青くする
これは Fragment Shader の仕事。
GPU の仕組みがわかると、シェーダーの“怖さ”が消える
「シェーダーって難しそう…」 と思いがちですが、正体はただのこれです。
三角形の形をいじるプログラム(頂点) 三角形の色をいじるプログラム(フラグメント)
たったこれだけ。
中身は Three.js(GLSL)でも Unity(HLSL)でも同じです。
3. Vertex / Fragment シェーダーとは何か?
— シェーダーの“2つの役割”を理解する
シェーダーは種類が多いように見えますが、 まず覚えるべきは たった2種類だけ です。
- Vertex Shader(頂点シェーダー)
- Fragment Shader(ピクセルシェーダー)
この2つが理解できれば、シェーダー全体の7割は理解できます。
Vertex Shader(頂点シェーダー)— 形を変える担当
頂点シェーダーは、名前の通り “頂点(Vertex)をどう動かすか” を決めます。
たとえば:
- 波でメッシュを上下に揺らす
- キャラクターを伸ばす/縮める
- ノイズで地形をデコボコにする
- モデルを回転・拡大・移動させる
三角形の“形そのもの”を変えたいときは、全部 Vertex Shader の仕事。
【例:波の頂点揺らぎ(GLSLイメージ)】
pos.y += sin(pos.x * 10.0 + time) * 0.1;
【例:Unity(HLSL)でも原理は同じ】
pos.y += sin(pos.x * 10 + _Time.y) * 0.1;
文法は違っても、 「頂点の位置を時間で動かす」 という原理は同じ。
Three.js で理解したことが Unity で活きる理由はここにある。
Fragment Shader(フラグメントシェーダー)— 色を塗る担当
fragment = “破片” つまり、画面を構成する 1ピクセル1ピクセルの色を決める ためのシェーダー。
担当する仕事は:
- 色の計算
- ライティング(光の当たり方)
- 影
- 発光(emission)
- 水の透明度・深度
- ノイズを使った炎
- グラデーション
見た目の美しさに関わる処理は、ほとんど Fragment Shader。
【例:光の色を変えるイメージ(GLSL)】
vec3 color = vec3(0.0, 0.2, 1.0);
gl_FragColor = vec4(color, 1.0);
【Unityでも本質は同じ(HLSL)】
return float4(color, 1);
Vertex と Fragment は“セットで1枚の絵”になる
- Vertex が 形を決める
- Fragment が 色を決める
- GPU が 三角形を画面に塗りつぶす
この3ステップで、初めてあなたの作った世界が画面に現れる。
形 × 色 = シェーダーの本質。
まず Vertex と Fragment だけ理解すればシェーダーは怖くない
- “頂点を動かすのが Vertex”
- “色を決めるのが Fragment”
この2つさえハッキリ理解できれば、 Three.js でも Unity でもシェーダーは闇ではなくなる。
次回の実装編(Three.js)で、 実際にこの2つがどう動くかを体験してもらう。
4. CPU と GPU の役割:なぜシェーダーが必要か?
シェーダーを理解する上で、 「CPU と GPU がどう役割分担しているか」 これは避けて通れない重要テーマです。
Three.js でも Unity でも、 この分業を理解すると「なぜシェーダーを書く必要があるのか」が一気にクリアになります。
CPU は“ゲームの頭脳”、GPU は“描画の筋肉”
ゲームやWebアプリ全体を管理しているのは CPU。 一方、画面のピクセルを爆速で処理しているのが GPU。
役割をざっくり分けるとこうなる:
◆ CPU の仕事(頭脳)
- ゲームロジック
- スクリプトの Update()
- 衝突判定
- AI
- プレイヤーの入力処理
- データ構造の管理
「ものを考える」「判断する」仕事は全部 CPU。
Three.js なら JavaScript Unity なら C#
ここが CPU の世界。
◆ GPU の仕事(筋肉)
- 三角形を並列処理で変形
- ピクセルを塗りつぶす
- 光と影の計算
- フラグメント単位で色の処理
- 法線による反射・屈折の計算
- 水・炎・発光などの視覚効果の生成
「とにかく膨大な量を高速で処理する」が GPU の仕事。
1フレームで数千万ピクセル 毎秒60〜120フレーム つまり一秒で数十億回の並列計算をする。
CPU には絶対に不可能な量。
じゃあ、CPU と GPU はどう対話しているのか?
CPU から GPUには、 “パラメータ” と “メッシュ情報” を渡すだけ。
GPU はそれを受け取って黙々と計算する。
ここで登場するのがシェーダー特有のデータ:
Uniform(ユニフォーム)とは?
CPU → GPU に渡す 一定の値
例:
- 時間(time)
- 光の強さ
- マテリアルの色
- 風の強さ
- テクスチャ
Three.js でも Unity でも必ず出てくる。
attribute / input(頂点データ)とは?
メッシュが持つ固定の値。
例:
- 頂点位置(position)
- UV座標
- 法線(normal)
どのエンジンでも同じ。
varying / 出力(補間値)とは?
頂点 → フラグメントに渡される値。
例:
- ライティング用のベクトル
- 波の高さ
- 色の補間情報
Three.js では varying Unity では interpolator と呼ばれるが役割は同じ。
CPU は命令するだけ。実際に描くのは GPU。
例として「水面」を作る場合:
CPU(JavaScript / C#)
- time を渡す
- 風の強さを渡す
- メッシュをセットする
- Draw() だけ呼ぶ
GPU(GLSL / HLSL)
- time を使って波を計算
- 法線で光の反射を計算
- 深さで色を変える
- すべてのピクセルを塗る
波そのものを計算してるのは GPU。 CPU はただの“司令塔”。
なぜシェーダーが必要なのか?
答えはシンプル:
GPU を使って好きな見た目を実現するには、 GPU で動く “シェーダーコード” が必要だから。
Unity のマテリアルや Three.js の MeshBasic… これらの便利機能は「既製品のシェーダー」の集合体。
だから、 自分だけの表現(水、炎、発光、変形)を作りたいなら 既製品ではなく“自前のシェーダー”が必要になる。
5. シェーダーは何が難しくて、何が簡単なのか?
多くの人がシェーダーに苦手意識を持つ理由は、 「何が難しくて、何が簡単なのか」 を最初に知らないまま飛び込むからです。
ここで“本当の難所”と“実は簡単な部分”を切り分けておきます。 この認識だけで、シェーダー学習のストレスが大幅に下がります。
難しいところ①:文法が C 言語っぽくて独特
GLSL(Three.js)も HLSL(Unity)も、 JavaScript や C# と書き方がかなり違います。
vec3やfloat4など独自の型- 行列計算(matrix multiply)
varying/uniformなど専門用語- 括弧が多くて読みにくい
「読んだ瞬間に拒否感が出る」 これは誰でも最初に経験する壁です。
難しいところ②:デバッグがしづらい
- コンソールログがない
- break point できない
- エラーメッセージが不親切
- 画面が真っ黒になったら何が起きたか分からない
“失敗した時に状況が分かりづらい” これが難しさを倍増させています。
難しいところ③:Unity は抽象レイヤーが厚い
Unity のシェーダーは “ShaderLab” という独自の記述形式で、 最初は構造がとても複雑に見えます。
- Properties
- SubShader
- Pass
- Tags
- URP / HDRP の違い
この構造に慣れるまでが地味にキツい。
逆に言うと、 Three.js → Unity の順に学ぶと理解がスムーズ (あなたがまさに経験した流れ)
でも安心してほしい。ここから下は“全部簡単”です。
簡単なところ①:やってることは単純
シェーダーの仕事は本質的にただこれだけ:
- 頂点を動かす(Vertex)
- 色を塗る(Fragment)
シンプルな2工程の繰り返しでしかない。
簡単なところ②:数学は中学レベルで十分#
必要な数学はこの程度:
- sin / cos(波)
- 0〜1 の補間(Lerp)
- 長さや正規化(normalize)
- ベクトルの向きと角度
- ノイズ(Perlin/Simplex)は概念だけ理解すればOK
Three.js をやってきた人なら すでに全部経験済み。
簡単なところ③:シェーダーは“パターン化”されている
水面、炎、発光、透明、ノイズ…… こういったエフェクトは 全部テンプレ化 されています。
- 水 → sin 波 + 法線
- 炎 → noise + time
- 発光 → 色の加算
- 地形 → noise + height map
つまり、一度理解すれば 別の表現も同じコードの応用で作れる。
簡単なところ④:Three.js と Unity はやることが同じ
文法は違っても、
- time を渡す
- 頂点を動かす
- UV を使う
- 法線で光を計算する
- color を返す
この“仕組み”は全く同じ。
だからこの連載は Three.js(GLSL)で学んで → Unity(HLSL)で理解が深まる という構成にしている。
結論:シェーダーは「最初の入口」だけが難しい。
その後は、 仕組みを理解すれば“作りたいものを作るだけ”の世界になる。
最初の壁を越えるための助走として、 第1回は「概念だけ」を丁寧に整理している。
次回から実際のコードに触れて、 「動く楽しさ」を体験してもらう。
6. まとめ:第2回から実装編へ
今回の第1回では、 シェーダーを学ぶための“土台となる概念”だけを整理しました。
- 世界は三角形でできている
- GPU が三角形を加工して画面を描く
- Vertex(形)と Fragment(色)がシェーダーの基本
- CPU と GPU には役割分担がある
- Three.js と Unity は仕組みが同じ
- 難しいのは入り口だけで、理解してしまえば楽しい
これらが腑に落ちると、 シェーダーは“ブラックボックス”ではなくなります。
次回(第2回)からいよいよ実装に入る
第2回では Three.js の RawShaderMaterial を使い、
- 頂点を sin 波で動かす
- 色を時間で変える
- GLSL の最小サンプルを動かす
という“最初の動くシェーダー”を作ります。
初心者が一番つまづきやすい 「どこに何を書けば動くのか?」 を明確にしつつ、実際の画面変化を体験します。
さらに、第3回では Unity(HLSL) 版として同じものを実装
- Unity の ShaderLab の構造
- HLSL の基本文法
- Three.js の GLSL とコード比較
- “両対応でシェーダーを書ける” 感覚をつかむ
この流れで Three.js → Unity の二刀流 を自然に身につけられます。
この連載の目的は“シェーダーの本質を恐れずに使えるようになること”
水・炎・発光・ノイズ・波—— どれも特別な才能が必要なわけではありません。
必要なのは「どんな仕組みで動いているか」の理解だけ。
そして第1回で、それを理解する準備は整いました。
それでは次回、実際に動くシェーダーを書いていきましょう。
💬 コメント