ノーマルマップとタンジェント空間|DCCとエンジンで一致させる

ノーマルマップ(面の凹凸を擬似的に表現するテクスチャ)は「貼ったら凹凸が出るテクスチャ」と扱われがちですが、その背後には 接空間(タンジェント空間:面に沿った座標系のこと)と複数の規約 が隠れています。DCC(Maya / Blender / Substance Painter などの3D制作ソフト)で OK、エンジン(Unity や Unreal Engine などのゲーム実行環境)で NG──この古典的な事故を防ぐには、ノーマルがどう成立しているかを言語化し、整合のチェックリストを持っておく必要があります。
本記事では、PBR(CR-01)と基礎数学(CR-02)の続きとして、タンジェント空間の正体・緑チャンネル反転・MikkTSpace・スムージンググループとの関係を整理し、最後に DCC とエンジンを一致させるチェック手順までを通します。
夕宮たいだふぁ……みんな〜、ノーマルマップって地味だけど、ハマるときはとことんハマるんだぁ。「凹凸が逆」「面が暗い」って事故、一回やると忘れないよぉ。今回は、その仕組みをちゃんと言語化していこ〜。
1. ノーマルマップって何だっけ
ひとことで:面の細かな向きの変化をテクセル単位で記録した、方向ベクトルのテクスチャです。
CR-02 で扱った「法線(Normal)」は、面の向きを示すベクトルでした。3Dモデルでは通常、各頂点に1本ずつ法線を持たせ、面ごとにシェーダーで補間して使います。これが 頂点法線 です。
ノーマルマップは、この情報を テクセル単位 に細かくしたものです。テクスチャの各ピクセル(テクセル:Texture + Pixel の合成語で、テクスチャ上の1ピクセルを指す)に「この点での面の向き」を記録し、ローポリ(ポリゴン数を抑えた軽量モデル、ゲームのリアルタイム表示用)のモデルでもハイポリ(ポリゴン数を惜しまない高精細モデル、彫刻ソフトで作る原型)のような陰影が出るように見せかけます。
つまり、形状そのものは変えずに「面の向きだけ」を細かく差し替えて、光の当たり方(CR-02 のランバート反射)の結果を変える仕組みです。実ポリゴンを増やさずに陰影だけ「ハイポリ風」にできるため、リアルタイムレンダリングではほぼ必須の技術になっています。
注意点は、シルエット(輪郭線)は変わらないことです。あくまで面の向きを偽装しているだけなので、横から見ると凹凸はぺったんこに戻ります。シルエットも欲しい場合は、ジオメトリ(モデルの形状そのもの)自体を増やすか、ディスプレースメント(テクスチャの値で実際にメッシュを変形させる手法)/パララックスマッピング(ピクセルシェーダで擬似的に深い凹凸を見せる手法)など別技法を併用します。
2. タンジェント空間の正体:T・B・N の3軸
ひとことで:曲面の各点に立てる「面ローカル座標系」です。
ノーマルマップが記録する方向は、何の座標系で表されているのでしょうか。ワールド座標(CR-02 の座標空間の階段で出てきたあれ)で記録すると、そのテクスチャは「特定の場所・特定の角度でしか正しく使えない」ものになってしまいます。同じ煉瓦テクスチャを別の壁に貼り回すこともできません。
そこで タンジェント空間(接空間) という、面ごとのローカル座標系を使います。
T・B・N の3軸
タンジェント空間は3本の軸で構成されます。
- N(Normal):面の法線。面に対して垂直な方向
- T(Tangent):面に沿った方向。通常はUVのU方向に揃える
- B(Bitangent):T と N の両方に垂直な方向。UV の V方向に対応
ここで思い出してほしいのが、CR-02 で扱った 外積 です。「ふたつのベクトルの両方に垂直な、3本目のベクトル」を作る計算でした。B軸は、N と T が決まれば外積で B = N × T として求められます。
下図のように、曲面の各点に立つ T・B・N の3本の矢印は、その点での「面ローカル座標」を作り出しています。





ほよ? CR-02 で出てきた外積、ここで使うんだぁ。「両方に垂直な3本目を作る」って、こういうところで効いてくるんだねぇ。
ノーマルマップ RGB の読み方
タンジェント空間が決まると、ノーマルマップのRGB値は「タンジェント空間での方向ベクトルの成分」として読めます。
- R チャンネル → T方向の成分(X)
- G チャンネル → B方向の成分(Y)
- B チャンネル → N方向の成分(Z)
ノーマルマップが青〜紫っぽく見えるのは、ほとんどのテクセルで Z(N方向)成分が大きく正の値だからです。面に対して概ね垂直方向、つまり「面そのものの方向」が基本だからです。
ピクセル値(0〜255 整数)から方向ベクトル(-1〜+1 の浮動小数)への変換は、シェーダー内部で vec = (rgb / 255) × 2 - 1 のように行われます。ここで得られた方向ベクトルを、T・B・N軸を使ってワールド空間に展開し、ライティング計算に使います。
3. 緑チャンネル反転:DirectX系 vs OpenGL系
ひとことで:Y軸の向きの規約差で、緑チャンネルが逆になります。
ノーマルマップには、世界に2大規約があります。
- DirectX系:Y軸が下向き(緑が小さいほど「上方向」)
- OpenGL系:Y軸が上向き(緑が大きいほど「上方向」)
これを取り違えると、凹凸が逆になります。へこんで見えるべき場所が出っ張り、出っ張るべき場所がへこむ──ライティングと噛み合わなくなり、画面全体に違和感が出ます。下図に同じノーマルマップを2規約で貼った球の比較を示します。


主要環境のデフォルトは次のとおりです。
| 環境 | デフォルト規約 | 切り替え |
|---|---|---|
| Unreal Engine | DirectX系(Y下) | テクスチャ設定で変換可 |
| Unity | 両対応 | インポート設定で選択 |
| Substance Painter | 出力時に選択 | DirectX / OpenGL の出力テンプレート |
| Maya | ベイク設定で選択 | Transfer Maps / Bake 設定 |
「Painter で焼いて UE に持っていく」が前提なら、Painter のテンプレートを DirectX (Y-) に揃えるのが定石です。チームでは、プロジェクト初期に「うちは DirectX 系で統一」とドキュメント化し、ベイク済みアセットのファイル名にもサフィックス(例:_n_dx)を入れておくと事故が激減します。



これ、絶対に確認しないとダメだよ! 凹凸が逆になっちゃうの、ほんと事故るからね。エンジンの規約、最初に決めとくのがいちばん安全だよぉ。
4. MikkTSpace:規約統一の現代解
ひとことで:DCCとエンジンで「同じノーマル」を生むための、タンジェント計算規約です。
緑チャンネルの規約を揃えても、もう一段深い問題が残ります。T軸と B軸をどう計算するか という規約が、実装ごとに微妙に違うのです。
DCC でベイクしたノーマルをエンジンで貼ると「微妙に陰影が違う」「エッジ周辺で割れる」事故が起きるのは、この T・B計算アルゴリズムが揃っていないことが主因です。
MikkTSpace とは
Morten Mikkelsen が提唱した MikkTSpace(mikktspace 規約) は、このタンジェント計算を共通化するための仕様です。ベイカー側もエンジン側も同じアルゴリズムを使えば、計算結果が一致し、見え方が揃います。
対応状況(2026年時点)は次のとおりです。
- Unreal Engine 5:対応
- Unity:対応(バージョンによる)
- Substance Painter:対応(最新ベイカーで標準)
- 古い環境:未対応(古い UE4、独自エンジンの一部)
新規プロジェクトでは「MikkTSpace 対応の DCC で焼き、MikkTSpace 対応のエンジンで読む」を満たせば、タンジェント由来の事故はほぼ消えます。



みんなで同じ規約使えば、ちゃんと揃うんだよぉ。便利でしょ? 新しい環境ならだいたい対応してるから、まずそこを確認するといいねぇ。
5. スムージンググループと頂点法線の整合
ひとことで:ハードエッジの分割設定とノーマルベイクは、連動して結果が決まります。
ノーマルマップのベイク(ハイポリの細かい凹凸情報を、ローポリ用のテクスチャに「焼き込む」工程。料理のベイクと同じく「事前に作って固める」イメージ)は、ローポリの頂点法線からの相対方向 を記録する作業です。つまり「ローポリ側の頂点法線がどう設定されているか」を前提に、ハイポリとの差分を焼き込みます。
スムージンググループの役割
スムージンググループ(あるいはハードエッジ/ソフトエッジ)は、頂点法線をどこで分割するかの設定です。
- ソフトエッジ:頂点を共有し、隣接面の法線を平均化(なめらかな陰影)
- ハードエッジ:頂点を分割し、面ごとに別の法線を持たせる(はっきりした角)
ベイクとエンジンで設定を揃える
ベイク前と後、さらにエンジン側のインポート設定の3者で、スムージング設定が一致していないと、ノーマルの結果は大きく崩れます。具体的には、ハードエッジ周辺で陰影が割れたり、面が暗くなったりします。
「DCC ではきれいに見えていたのに、エンジンに持っていったら別物」のかなりの割合は、ここが原因です。
実務上の鉄則は、ハードエッジは UV シームと一致させる ことです。頂点が分割される位置と UV が分割される位置を揃えておけば、ベイク時のタンジェント計算が安定し、エンジンに持って行ったときの陰影も予測可能になります。詳細は MY-B09 スムージングと頂点法線(Maya)(公開準備中)で扱います。


6. DCC↔エンジン整合のチェック手順
ひとことで:同じノーマルマップを各環境で並べて、目視で差を取ります。
理屈を抑えたら、最後は 必ず実機で照合 します。チェック手順は次のとおりです。
1. 同一メッシュ・同一ノーマルマップを、Painter / Maya / Unreal の3環境にロード 2. できるだけ近いライティング条件で表示(強い指向性ライト1本がわかりやすい) 3. 凹凸の方向、陰影の出方、エッジの硬さを目視で比較 4. 違いがあれば、緑反転 / スムージング / MikkTSpace 対応の3点を順にチェック


具体的に何を見るかは、次の通りです。
- 凹凸が逆になっていないか → 緑チャンネル反転の規約差
- 平面が暗くなっていないか → タンジェント計算の不一致
- ハードエッジ周辺で陰影が割れていないか → スムージング設定不一致
- エッジ周辺で陰影が「縞模様」に出ていないか → タンジェント未エクスポート(エンジン側で再計算されている)



ぁぅ……目で見て比べるのだいじなんだよぉ。理屈で「合ってるはず」じゃなくて、ちゃんと並べて確認してねぇ。
7. ハンズオン演習
ひとことで:Painter から Y上下それぞれ書き出して、エンジンで比較しましょう。
「規約差で凹凸が逆になる」現象を、自分の手で再現します。
1. Substance Painter で適当なメッシュにノーマルを焼く 2. Output 設定で DirectX (Y-) と OpenGL (Y+) の2種類を書き出し 3. Unreal または Unity に両方インポートし、別マテリアルとして適用 4. 同じシーンに並べて表示 5. デフォルト設定でどちらが正しく見え、どちらが反転するかを観察
UE デフォルト(DirectX系)では、Y- 版が正常、Y+ 版は反転して見えるはずです。Unity でインポート時に「Y-反転」のチェックを操作すると、反転状態が切り替わるのが確認できます。
この体験を一度やっておくと、「ノーマルが変だな」と思ったときに 最初に緑チャンネル規約を疑う 反射神経が身につきます。
8. チェックリスト
ひとことで:書き出し前・インポート後のセルフチェック項目です。
- [ ] 出力規約(DirectX系/OpenGL系)が利用エンジンと一致している
- [ ] スムージンググループの設定が、ベイク前/エクスポート時/エンジンインポート時で一致している
- [ ] DCC とエンジンが MikkTSpace 対応かを確認した
- [ ] FBX エクスポート時に「タンジェント情報を含める」設定になっている
- [ ] 実機でノーマルを並べ、凹凸方向・陰影・エッジを目視確認した
- [ ] 「凹凸が逆」「面が暗い」「エッジが縞模様」が起きていない
9. よくある間違い・トラブルシュート
ひとことで:緑反転・スムージング不一致・MikkTSpace 未対応・タンジェント未エクスポートの4つが定番です。
緑チャンネル反転忘れ
症状:凹凸の向きが全体的に逆。 対処:書き出しテンプレートを切り替えて再生成、または GIMP / Photoshop で緑チャンネルだけ反転。エンジン側で「Flip Green Channel」設定がある場合はそちらでも可。
スムージンググループ不一致
症状:ハードエッジ位置にギザギザの陰影、面が部分的に暗い。 対処:DCC のスムージング設定、FBX エクスポート設定、エンジンのインポート設定の3者を揃える。一度ベイクしたデータは、設定が揃った状態で焼き直すのが確実。
MikkTSpace 未対応環境
症状:エッジ付近で陰影が「割れる」「縞模様になる」。 対処:DCC・エンジン双方が MikkTSpace 対応かを確認。古い環境を使い続ける場合は、エンジン側のタンジェント計算を MikkTSpace 互換実装に差し替えるか、ベイカー側を環境に合わせる。
FBX にタンジェント未出力
症状:エンジン側で再計算されたタンジェントが、ベイク時のものと一致せず陰影が崩れる。 対処:FBX エクスポート時の「タンジェントとバイノーマル」を必ず含める。Maya / 3ds Max / Blender いずれもエクスポート設定に該当チェックがある。



ふぁ……ノーマルまわり、ハマりやすい話を一通り押さえたかなぁ。次はチャンネルパッキングとベイクの全体論に進むよぉ。
10. 次に読む記事
ひとことで:ノーマルから派生する周辺トピックを攻めましょう。
- CR-05 チャンネルパッキング戦略:ノーマル以外のマップとの併用設計
- CR-06 ベイク全体論:ノーマル以外のベイク(AO=Ambient Occlusion、Curvature=曲率、Position=座標値 など)まで含めた全体像
- CR-12 DCC→エンジンの色合わせ:色空間の不一致が引き起こす絵の崩れの整理
- SP-I01 High to Low ベイクの実務:Substance Painter での実機ワークフロー(公開準備中)
- MY-B09 スムージングと頂点法線:Maya 視点でのスムージング運用詳細(公開準備中)
—








