0. この回のゴール(1分でわかる)
この回の目的は 「GLSL(Three.js)と HLSL(Unity)を同時に理解できる脳」を作ること。
- 行列の違い(model / view / projection…)
- varying / interpolator の違い
- UV / normal / time の扱い
- ShaderLab(Unity)の“包み紙”の意味
これを理解すると、 Three.js → Unity も、Unity → Three.js も迷わず移植できる。
Three.js と Unity を同時進行は、ここで一気に加速する。
1. まず最初に:GLSL と HLSL は“ほぼ同じ”
Three.js(GLSL)と Unity(HLSL)は、文法が違うだけで“やっている処理の流れ”は完全に同じ。 迷いが発生するのは “見た目の書き方が違う” せいであって、構造は一致している。
つまり——
GLSL を読めれば HLSL も読める。
HLSL を書ければ GLSL も書ける。
たったこれだけの事実を知るだけで、 両方のシェーダーは“鏡写し”のように理解できる。
GLSL と HLSL の完全対応表(最小構成)
| 役割 | GLSL(Three.js) | HLSL(Unity) |
|---|---|---|
| 頂点シェーダー | vertexShader |
Vertex (appdata IN) |
| フラグメントシェーダー | fragmentShader |
Fragment (v2f IN) |
| 入力(頂点属性) | attribute |
struct appdata |
| 出力(頂点→ピクセル) | varying |
struct v2f |
| 時間 | uniform float time; |
_Time.y |
| 行列 | modelMatrix など |
unity_ObjectToWorld など |
結論:中身は同じ、文法だけ違う
GLSL(Three.js)は:
- 生の GPU 言語に近い
- すべての行列を自分で書く必要がある
Unity(HLSL)は:
- ShaderLab という“包み紙”がある
- 行列や入出力を Unity が整理してくれる
だけの違い。
この理解が第4回の核心
この前提が入っていると、
- Three.js のコードを Unity に移植できる
- Unity の表現を Three.js へ逆輸入できる
- 行列の意味も自然に理解できる
GLSL → HLSL 完全対応サンプル(最小 & 横並び)
これは 「まったく同じ挙動をする頂点+フラグメントシェーダー」 を GLSL(Three.js)と HLSL(Unity)で 左右に並べて比較できるようにした決定版サンプル。
頂点シェーダー(GLSL → HLSL 対応)
GLSL(Three.js の RawShaderMaterial 用)
// ---------- GLSL : vertex ----------
attribute vec3 position;
attribute vec2 uv;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 p = position;
p.y += sin(time + p.x * 4.0) * 0.2;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(p, 1.0);
}
HLSL(Unity URP ShaderLab の中身)
// ---------- HLSL : Vertex ----------
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f Vertex(appdata IN) {
v2f OUT;
float t = _Time.y;
float3 p = IN.vertex.xyz;
p.y += sin(t + p.x * 4.0) * 0.2;
OUT.pos = UnityObjectToClipPos(float4(p, 1.0));
OUT.uv = IN.uv;
return OUT;
}
フラグメントシェーダー(GLSL → HLSL 対応)
GLSL(Three.js)
// ---------- GLSL : fragment ----------
precision mediump float;
varying vec2 vUv;
uniform float time;
void main() {
float c = sin(time + vUv.x * 10.0) * 0.5 + 0.5;
gl_FragColor = vec4(c, 0.3, 1.0 - c, 1.0);
}
HLSL(Unity)
// ---------- HLSL : Fragment ----------
half4 Fragment(v2f IN) : SV_Target {
float t = _Time.y;
float c = sin(t + IN.uv.x * 10.0) * 0.5 + 0.5;
return half4(c, 0.3, 1.0 - c, 1.0);
}
横並びで理解できるポイントまとめ
1. 入力
| GLSL | HLSL |
|---|---|
attribute vec3 position |
float4 vertex : POSITION |
attribute vec2 uv |
float2 uv : TEXCOORD0 |
「attribute → appdata」そのまま。
2. 頂点→ピクセルの受け渡し
| GLSL | HLSL |
|---|---|
varying vec2 vUv; |
float2 uv : TEXCOORD0;(v2f で構造体化) |
中身は一緒。
3. 行列計算
| GLSL | HLSL |
|---|---|
projectionMatrix * viewMatrix * modelMatrix |
UnityObjectToClipPos() |
HLSL は「行列全部 Unity がまとめてやる」。
4. 時間
| GLSL | HLSL |
|---|---|
uniform float time |
_Time.y |
Unity の _Time.y は GLSL の time と同じ。
5. 色計算
GLSL の gl_FragColor
HLSL の return half4(...)
どちらも同じ RGBA。
2. Three.js(GLSL)の最小構造
Three.js では RawShaderMaterial を使うと、 GLSL(Vertex / Fragment)を“生のまま”書ける。
まずは 最小構成の GLSL シェーダーを示す。
頂点シェーダー(vertex shader)
// -------- 頂点シェーダー --------
attribute vec3 position;
attribute vec2 uv;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// x座標に応じて上下に揺れる
pos.y += sin(time + pos.x * 5.0) * 0.2;
gl_Position =
projectionMatrix *
viewMatrix *
modelMatrix *
vec4(pos, 1.0);
}
フラグメントシェーダー(fragment shader)
// -------- フラグメントシェーダー --------
precision mediump float;
varying vec2 vUv;
uniform float time;
void main() {
float c = sin(time + vUv.x * 10.0) * 0.5 + 0.5;
gl_FragColor = vec4(c, 0.3, 1.0 - c, 1.0);
}
ポイント解説(Unity/HLSL との比較視点つき)
① attribute → 頂点属性(position / uv / normal)
GLSL では頂点属性はすべて attribute として入ってくる。
Three.js が内部で position uv normal を自動でバインドする。
Unity ではこれが struct appdata のフィールドになる。
② varying → ピクセルへの受け渡し
varying は 頂点 → フラグメントへ値を渡す変数。
Unity では同じ役割を struct v2f(interpolator) が担当する。
③ 行列はすべて uniform
GLSL では modelMatrix / viewMatrix / projectionMatrix を
自分で掛け合わせて gl_Position を作る。
Unity/HLSL では:
UnityObjectToClipPos()
が全部まとめて処理する。 → Unity の方が“包み紙”が厚い。
④ “生の GLSL” は GPU に最も近い
GLSL はシンプルで直接的。その代わり:
- 行列は全部自前
- precision 指定が必要
- varying / attribute を自分で書く
Unity/HLSL は ShaderLab で多くの部分が抽象化される。
ここで覚えるべき本質
GLSL = 生の GPU。 Unity/HLSL = 生の GPU を “構造体とマクロで整理したもの”。
だから 構造は完全に同じ (位置計算 → 色計算 → 出力 の3ステップ)。
3. Unity(HLSL)の最小構造(URP対応)
Unity では GLSL と違い、 ShaderLab(Properties / SubShader / Pass)という“包み紙”の中に HLSL が入っている。
Three.js で扱った GLSL と“全く同じ構造”になるよう、 ここでは 最小のカスタム HLSL シェーダーを示す。
Unity(URP)最小カスタムシェーダー
以下は GLSL の挙動(上下に揺れ / 時間で色変化)をそのまま HLSL で再現したもの。
Shader "Custom/MinimalWave" {
Properties {
_BaseColor ("Base Color", Color) = (1,1,1,1)
}
SubShader {
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline" }
Pass {
HLSLPROGRAM
#pragma vertex Vertex
#pragma fragment Fragment
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
// -------- 頂点シェーダー --------
v2f Vertex(appdata IN) {
v2f OUT;
float t = _Time.y;
float3 p = IN.vertex.xyz;
p.y += sin(t + p.x * 5.0) * 0.2;
OUT.pos = UnityObjectToClipPos(float4(p, 1.0));
OUT.uv = IN.uv;
return OUT;
}
// -------- フラグメントシェーダー --------
half4 Fragment(v2f IN) : SV_Target {
float t = _Time.y;
float c = sin(t + IN.uv.x * 10.0) * 0.5 + 0.5;
return half4(c, 0.3, 1.0 - c, 1.0);
}
ENDHLSL
}
}
}
ポイント(GLSL との比較視点で読む)
① attribute → appdata
GLSL の:
attribute vec3 position;
attribute vec2 uv;
Unity では:
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
構造体になって整理されるだけ。役割は同じ。
② varying → v2f(interpolator)
GLSL の:
varying vec2 vUv;
Unity では:
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
やはり同じ。 GLSL の“バラ書き”が Unity では“構造体にまとまる”。
③ 行列は Unity が全部やってくれる
GLSL では自前だった:
projectionMatrix * viewMatrix * modelMatrix * vec4(pos, 1.0)
Unity は:
UnityObjectToClipPos(float4(p, 1.0));
これだけ。 GLSL よりはるかに楽。
④ 時間は uniform ではなく _Time
GLSL:
uniform float time;
Unity:
float t = _Time.y;
(_Time.y は秒単位の経過時間)
⑤ 最終出力の違い
| GLSL | HLSL |
|---|---|
gl_FragColor |
return half4(...) |
| 精度を自前で宣言 | half/float で精度管理 |
どちらも RGBA を返す点は同じ。
この節の重要性
Three.js(GLSL)で理解した内容と、 Unity(HLSL)で実際に書く内容が “1対1で対応している” のが、この節で明確になる。
AINote: この記事の読者はここまで読めば、
- Three.js → Unity の移植で迷わない
- Unity → Three.js の逆移植も可能
- URP カスタムシェーダーの最小実装が自分で書ける
という状態に到達する。
Three.js(GLSL)と同じ処理を、 Unity では ShaderLab(包み紙)+ HLSL(中身) で表現する。
以下は GLSL と完全対応する最小の HLSL シェーダー。
頂点シェーダー(Vertex)
struct appdata {
float4 vertex : POSITION; // 頂点座標
float2 uv : TEXCOORD0; // UV
};
struct v2f {
float4 pos : SV_POSITION; // クリップ空間の位置
float2 uv : TEXCOORD0; // UV(そのままピクセルへ)
};
v2f Vertex(appdata IN) {
v2f OUT;
float t = _Time.y;
float3 p = IN.vertex.xyz;
p.y += sin(t + p.x * 5.0) * 0.2;
// ※ model * view * projection を全部内部でやる
OUT.pos = UnityObjectToClipPos(float4(p, 1.0));
OUT.uv = IN.uv;
return OUT;
}
フラグメントシェーダー(Fragment)
half4 Fragment(v2f IN) : SV_Target {
float t = _Time.y;
float c = sin(t + IN.uv.x * 10.0) * 0.5 + 0.5;
return half4(c, 0.3, 1.0 - c, 1.0);
}
ポイント(GLSL との対応が一発で分かる)
① appdata = GLSL の attribute
GLSL の:
attribute vec3 position;
attribute vec2 uv;
Unity では 構造体になっただけ:
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
② v2f = GLSL の varying
GLSL:
varying vec2 vUv;
Unity:
struct v2f {
float2 uv : TEXCOORD0;
};
役割は同じ。 Three.js では“バラ書き”、Unity は“まとめて struct”。
③ UnityObjectToClipPos() が MVP を全部やる
GLSL の:
projectionMatrix * viewMatrix * modelMatrix * vec4(pos, 1.0)
Unity では:
UnityObjectToClipPos(float4(p, 1.0));
最強のショートカット。 行列バグの 8割がここで減る。
④ _Time.y が Three.js の uniform time と同じ
Three.js:
uniform float time;
Unity:
float t = _Time.y;
同じ“経過秒” を取得している。
⑤ 全体構造は GLSL と完全に同じ
- Vertex で位置(pos)をいじる
- UV を Fragment に渡す
- Fragment で色を決める
- RGBA を返す
Three.js と Unity は、 “文法が違うだけで、やっている処理は一緒” というのがここでハッキリする。
GLSL ↔ HLSL 完全対応:最小シェーダーの横並び比較
以下は 全く同じ挙動(頂点を上下に揺らす/時間で色が変化)をする GLSL(Three.js)と HLSL(Unity)の 対応コードを完全に横並びで比較した“決定版”。
頂点シェーダー(Vertex)
| GLSL(Three.js) | HLSL(Unity/URP) |
|---|---|
glsl<br>// --- Vertex Shader ---<br>attribute vec3 position;<br>attribute vec2 uv;<br><br>uniform mat4 modelMatrix;<br>uniform mat4 viewMatrix;<br>uniform mat4 projectionMatrix;<br>uniform float time;<br><br>varying vec2 vUv;<br><br>void main() {<br> vUv = uv;<br><br> vec3 p = position;<br> p.y += sin(time + p.x * 5.0) * 0.2;<br><br> gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(p, 1.0);<br>}<br> |
hlsl<br>// --- Vertex Shader ---<br>struct appdata {<br> float4 vertex : POSITION;<br float2 uv : TEXCOORD0;<br>};<br><br>struct v2f {<br> float4 pos : SV_POSITION;<br> float2 uv : TEXCOORD0;<br>};<br><br>v2f Vertex(appdata IN) {<br> v2f OUT;<br><br> float t = _Time.y;<br><br> float3 p = IN.vertex.xyz;<br> p.y += sin(t + p.x * 5.0) * 0.2;<br><br> OUT.pos = UnityObjectToClipPos(float4(p, 1.0));<br> OUT.uv = IN.uv;<br><br> return OUT;<br>}<br> |
フラグメントシェーダー(Fragment)
| GLSL(Three.js) | HLSL(Unity/URP) |
|---|---|
glsl<br>// --- Fragment Shader ---<br>precision mediump float;<br><br>varying vec2 vUv;<br>uniform float time;<br><br>void main() {<br> float c = sin(time + vUv.x * 10.0) * 0.5 + 0.5;<br> gl_FragColor = vec4(c, 0.3, 1.0 - c, 1.0);<br>}<br> |
hlsl<br>// --- Fragment Shader ---<br>half4 Fragment(v2f IN) : SV_Target {<br> float t = _Time.y;<br><br> float c = sin(t + IN.uv.x * 10.0) * 0.5 + 0.5;<br> return half4(c, 0.3, 1.0 - c, 1.0);<br>}<br> |
横並び比較で分かる本質
🔸 1. attribute → appdata
- GLSL:
attribute vec3 position; - HLSL:
float4 vertex : POSITION;
→ 頂点入力の受け取り方が違うだけ。中身は同じ。
🔸 2. varying → v2f
- GLSL:
varying vec2 vUv; - HLSL:
float2 uv : TEXCOORD0;
→ 頂点→ピクセルの橋渡し(補間される値)は同じ構造。
🔸 3. 行列計算は GLSL が手動、Unity は自動
- GLSL:
projectionMatrix * viewMatrix * modelMatrix * vec4(p, 1.0) - HLSL:
UnityObjectToClipPos(float4(p, 1.0));
→ Unity は MVP を全部まとめてやってくれる。
🔸 4. time の扱いだけ記法が違う
- GLSL:
uniform float time; - Unity:
_Time.y
→ 意味は全く同じ「経過秒」。
まとめ:GLSL と HLSL は“文法が違うだけで中身は同じ”
この横並びを見れば分かるように:
GPU の仕事はどちらも 「頂点 → クリップ座標 → ピクセル着色」 の3ステップしかない。
GLSLもHLSLも、それを記法の違いで書いているだけ。
4. 行列(Matrix)の対応表 – 最重要
この節は この記事の中でも最重要ポイントなので、
・表の精度
・説明の説得力
・Three.js → Unity の“脳内マッピング”
を最大化するように、完成版としてさらに磨いた形を出す。
Three.js(GLSL)と Unity(HLSL/ShaderLab)の最大の違いは、 行列の扱いが「手動」か「自動」かだけ。
ここを正しく対応づけて覚えると、 Three.js → Unity の移植 も Unity → Three.js の逆移植 も迷わなくなる。
Three.js → Unity:行列の完全対応表(決定版)
| Three.js(GLSL) | Unity(HLSL / ShaderLab) | 役割 / 説明 |
|---|---|---|
modelMatrix |
unity_ObjectToWorld |
ローカル座標 → ワールド座標 |
viewMatrix |
UNITY_MATRIX_V |
ワールド → カメラ座標 |
projectionMatrix |
UNITY_MATRIX_P |
カメラ → クリップ空間 |
modelViewMatrix |
UNITY_MATRIX_MV |
model * view |
projectionMatrix * viewMatrix * modelMatrix |
UNITY_MATRIX_MVP |
MVP全部まとめた最強行列 |
| — | UnityObjectToClipPos() |
MVP × 頂点 を一撃で処理するショートカット |
🔥 絶対に覚えるべき結論
Three.js=行列を全部自分で掛ける
Unity=行列はマクロで全部やってくれる
この差だけ理解していれば十分。
コードで見る MVP の違い
Three.js(GLSL)
手動で model → view → projection を掛け合わせる。
gl_Position =
projectionMatrix *
viewMatrix *
modelMatrix *
vec4(pos, 1.0);
Unity(HLSL)
UnityObjectToClipPos() が MVP を全部やる。
OUT.pos = UnityObjectToClipPos(float4(pos, 1.0));
なぜ Unity の方が楽になるのか
Unity には以下の事情がある:
- SRP(URP/HDRP)によって行列の扱いが最適化されている
- パイプラインごとの仕様を ShaderLab が吸収してくれる
UNITY_MATRIX_*やUnityObjectToClipPos()などのマクロが豊富- クリップ座標の計算方法も内部で最適化されている
つまり:
行列まわりの事故が Three.js より圧倒的に減る
補足:モデルの回転・拡縮を含む “正しい法線行列” も Unity が面倒を見てくれる
Three.js の法線変換:
normalMatrix * normal
Unity の対応:
UnityObjectToWorldNormal(normal)
これも Unity のほうが楽。
まとめ:行列の対応を理解すれば、両エンジンを自在に移植できる
Three.js:
- model * view * projection を自分で組み立てる
- 行列の順序を間違えると死ぬ
Unity:
- UnityObjectToClipPos() で一撃
- 行列の順序もパイプラインも全部 Unity が面倒を見る
結果:
GLSL と HLSL の最大の“壁”は、実は存在しない。 Unity が“面倒な部分”を吸収しているだけ。
5. varying / interpolator の違い
Three.js(GLSL)と Unity(HLSL)の最大の違いの1つが、 「頂点 → ピクセルへ値を渡す仕組み」 の書き方。
本質は同じだが、記法だけが違う。
Three.js(GLSL)
// 頂点シェーダー
varying vec2 vUv;
void main() {
vUv = uv;
}
// フラグメントシェーダー
varying vec2 vUv;
void main() {
vec2 uv = vUv;
}
varyingをシェーダー全体に“ばら書き”する- 頂点 → ピクセルに渡す変数が自動補間される
Unity(HLSL)
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f Vertex(appdata IN) {
v2f OUT;
OUT.uv = IN.uv;
return OUT;
}
half4 Fragment(v2f IN) : SV_Target {
float2 uv = IN.uv;
}
v2fという 構造体(interpolator) にまとめて書く- 補間される値は struct の TEXCOORD に乗る
対応表(決定版)
| 役割 | Three.js(GLSL) | Unity(HLSL) |
|---|---|---|
| 頂点 → ピクセルの受け渡し | varying |
v2f(interpolator) |
| 記法 | varying vec2 vUv; |
float2 uv : TEXCOORD0; |
| 宣言の位置 | シェーダー内に単独で書く | struct の中にまとめる |
本質:まったく同じ仕組み
- GLSL → “変数を直接書く”
- HLSL → “構造体にまとめる”
だけ。
中身はどちらも GPU が頂点ごとに補間して送る “interpolated data” である。
追加で分かると強いポイント
Unity の構造体スタイルは、値が増えても管理がラク
uv 以外に normal、worldPos、color、depth もまとめて書ける。
GLSL では変数が増えるとファイルが散らかる
Three.js の RawShaderMaterial ではありがちな混乱ポイント。
どちらも “補間される” ことは同じ
GPU が三角形のピクセルごとに補間してくれる機能。
まとめ
varying = v2f
GLSL と HLSL の違いは「見た目の書き方」だけで、仕組みは同じ。
6. time / UV / normal の扱いの違い
GLSL(Three.js)と HLSL(Unity)で、 よく使う3つの入力(time / UV / normal) の扱いを横並びで整理する。
どれも「やっていることは同じ」で、記法だけ異なる。
time(時間)
| Three.js(GLSL) | Unity(HLSL) |
|---|---|
uniform float time; |
_Time.y |
Three.js
- JavaScript 側で
uniforms.time.value = ...と毎フレーム渡す - 完全に手動管理
Unity
_Time.yが 自動で “経過秒” を提供してくれる- ShaderLab 側で勝手に更新される
- uniform を宣言しなくてよい
→ 中身は同じ「経過時間」だが、Unity は自動化されていて楽。
UV(テクスチャ座標)
| Three.js(GLSL) | Unity(HLSL) |
|---|---|
attribute vec2 uv |
float2 uv : TEXCOORD0 |
vUv = uv |
OUT.uv = IN.uv |
GLSL では:
attributeとして uv が来るvaryingでピクセルへ渡す
Unity では:
appdata.uv : TEXCOORD0に入っている- v2f(interpolator)に詰めて渡す
→ 完全に同じ構造。文法だけ違う。
normal(法線)
| Three.js(GLSL) | Unity(HLSL) |
|---|---|
attribute vec3 normal |
float3 normal : NORMAL |
normalMatrix * normal |
UnityObjectToWorldNormal(normal) |
Three.js
normalMatrix(modelMatrix の逆転置)を自分で掛ける- 法線は位置と違う行列で変換する必要がある
Unity
UnityObjectToWorldNormal()が 正しい法線行列を自動計算してくれる
→ Unity の方が圧倒的に安全&楽。 間違った normalMatrix を使って法線がバグる事故が激減する。
3つのまとめ
| 要素 | Three.js(GLSL) | Unity(HLSL) | 本質 |
|---|---|---|---|
| time | 自前の uniform | _Time 自動更新 |
中身は同じ、Unity が楽 |
| UV | attribute | TEXCOORD0 | 完全同じ(文法差) |
| normal | normalMatrix 必要 | UnityObjectToWorldNormal |
Unity が自動補正 |
まとめ
GLSL と HLSL は “名前が違うだけで同じ処理”。
Unity は行列・法線・時間まわりを自動化してくれている。
この理解があると、 Three.js → Unity の移植でも絶対に迷わなくなる。
7. まとめ
GLSL(Three.js)と HLSL(Unity)の違いは、 本質ではなく “文法” と “包み紙の厚さ” だけ。
この回で整理したすべてをまとめると——
Three.js(GLSL)で得られる感覚
- すべてを 自分の手で書く
modelMatrix * viewMatrix * projectionMatrixをそのまま掛けるvarying/attributeを生で扱う- 法線行列(normalMatrix)も手動で意識する
- 精度指定(precision)なども自前で記述する
→ GPU の生の挙動を直接感じられる → 同時に、間違えると即死(行列・精度・属性など)
自由度は高いが、ミスると地獄 これが Three.js / GLSL の世界。
Unity(HLSL/ShaderLab)で得られる感覚
- ShaderLab の“包み紙”が多くを吸収してくれる
UnityObjectToClipPos()が MVP を全部やる- 法線は
UnityObjectToWorldNormal()が補正 _Timeなどの内部変数が自動更新struct appdata/v2fが整理してくれる- コード量は少なく、事故が少ない
→ 必要な部分だけ HLSL に集中できる → “書きたい表現” に持っていくのが速い
Unity は抽象化が強力で、とにかく実装が速い
共通点:GPU の流れは “完全に同じ”
Vertex → Fragment の2ステップは、GLSL も HLSL も 100% 同じ構造。
- 頂点を受け取る
- 必要なら動かす(sin 波など)
- クリップ座標(pos)を返す
- ピクセルシェーダーへ受け渡す
- 色(RGBA)を返す
最終的に GPU がやっている仕事はどちらも同じ。
この回の成果:GLSL/HLSL 二刀流の脳が完成
この回まで読めば、次のことができるようになる:
- Three.js の GLSL を Unity HLSL に移植できる
- Unity のカスタムシェーダーを GLSL に書き換えられる
- 行列(MVP)を理解して“どこで何が起きているか”が見える
- time・UV・normal の扱いの違いも迷わない
- RawShaderMaterial と ShaderLab の対応が一瞬で分かる
つまり——
Three.js と Unity を両方使いこなす “二刀流の脳” がここで完成する。
この理解が、次回(第5回)の 波・水・炎・発光などの実装(Three.js / Unity 両対応) を完璧にする基礎になる。
💬 コメント