2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

"【初心者向け】ゲーム開発における描画とレンダリングの違いをわかりやすく解説(Unity / C++ / DirectX 対応)"

Posted at

TL;DR

  • 描画 (Draw) = 「ジオメトリ(頂点データなど)を GPU に送り ポリゴンを塗る」フェーズ。いわゆる ドローコール を発行する段階。
  • レンダリング (Render) = ライティングやポストエフェクトを含め「最終的な画像を出力するまで」の全体プロセスの総称。
  • Unity では内部的に RenderLoop(レンダーループ)と呼ばれる処理で、DirectX なら Draw → Present(描画から表示)までの流れを押さえよう。
  • “画面に何も映らない”バグの 8 割は 描画順カメラ設定シェーダ のいずれかに原因がある。まずここを疑おう。

1️⃣ 描画とレンダリングはどこが違う?初心者向けに基礎説明

フェーズ キーワード例 何をしている? (簡単に)
描画
(Draw)
バーテックスバッファ / インデックスバッファ / Draw Call オブジェクトのジオメトリ情報(頂点座標・テクスチャ座標など)を CPU から GPU に送り、三角形ポリゴンを塗りつぶす。いわゆる ドローコール(「このオブジェクトを描画して」と命令)を発行する段階。
レンダリング
(Render)
ライティング / Zバッファ / ポストプロセス 描画された結果にライティング(照明)や深度テスト(Zバッファ)を適用し、さらにポストエフェクトで画面効果を加えて「最終的な1枚の画像 (フレームバッファ)」に仕上げる段階。

図: 「描画→レンダリング」の流れを示した簡易概念図(イメージ)
(各オブジェクトの頂点データをGPUに送り → ポリゴン描画 → ライティング適用 → ポストエフェクト処理 → 完成したフレームバッファを画面に表示)

◆ 用語補足: 「バーテックスバッファ」はモデルの頂点配列を格納したGPUメモリ、「インデックスバッファ」は頂点をつないでポリゴンを構成する順序(インデックス)を格納したものです。描画時、CPUはこれらをセットしてDraw Callを発行し、GPUに「〇〇を描け」と命令を送ります。一方「Zバッファ(深度バッファ)」とは各ピクセルの奥行き(カメラからの距離)情報を保持し、手前の物体だけを描画して隠れた部分を除去するための仕組みです。レンダリング工程ではこのZバッファを使った隠面消去や、光源に応じたライティング計算、画面全体へのポストプロセス効果(色調補正・Bloomなどのエフェクト)を行い、最終的な出力画像を生成します。

まとめると: 「描画 (Draw)」はレンダリング工程の一部であり、モデルを描いて下地を作る段階です。その後の「レンダリング (Render)」で照明やエフェクトを適用し、完成画像を出力するまでが一連の流れになります。普段「レンダリング」という言葉は広義に使われますが、本記事では便宜上、**狭義の「描画」広義の「レンダリング」**を分けて解説します。


2️⃣ Unity の場合:描画からレンダリング完了までの流れ

Unityのレンダリングループ概観: Unityエンジンでは1フレームごとに上記のような手順を踏みます。

  • ① CPU: ゲーム更新と描画準備 – まずメインスレッドで Update() 処理などゲームロジックを実行。その後、各カメラについてカリング処理(視界に入らないオブジェクトを除外する)を行い、描画すべきオブジェクトを決定します。必要な各オブジェクトについてドローコール(「このメッシュをこのマテリアル・シェーダで描いて」という命令)を順次キューに蓄積します。Unityではこの際、SRPバッチャーという仕組みで材質(マテリアル)ごとに描画命令をまとめ、DrawCall数削減による最適化も行われます。

  • ② CPU→GPU: DrawCall 発行 – 準備が整ったら、CPUは蓄積したドローコールをScriptable Render Pipeline (SRP) 経由で GPU に送信します。例えば URP/HDRP では内部で context.DrawRenderers(cullResults, ...) のように記述され、カリング結果に基づく描画命令が発行されます(SRP Batcher はこの間にステート変化を減らすよう働きます)。各ドローコールの前には必要に応じてSetPass Call(シェーダやマテリアルなど描画環境の切り替え命令)も挿入されます。GPUはセットパスコールで指定された描画ステートに切り替え、続くドローコールで渡された頂点データ(バッチ)をもとに実際の描画処理を開始します。

  • ③ GPU: 頂点シェーダ → ラスタライズ – GPU上ではまず頂点シェーダが動作し、各頂点をワールド座標からカメラ座標に変換し投影します(Unityでは UNITY_MATRIX_MVP などを用いてモデル座標→クリップ空間への変換を行います)。続いてプリミティブ(ポリゴン)をラスタライズし、画面上のピクセルに落とし込む処理が走ります。

  • ④ GPU: フラグメントシェーダ(ピクセル色決定) – ラスタライズされた各ピクセルについてフラグメントシェーダ(ピクセルシェーダ)が実行されます。ここでテクスチャを参照したりライティング計算を行い、最終的なピクセルの色が決まります。この過程でZバッファによる隠面処理も同時に行われ、手前の物体のピクセルだけがフレームバッファに描かれます。

  • ⑤ GPU: ライティング & ポストプロセス – Unityのレンダリングパイプラインでは、フラグメントシェーダ内で計算される前向きレンダリング (Forward)の場合は各光源の影響をその場で計算し色に反映します。一方、デferredレンダリングの場合は一旦アルベド色や法線などを書き出した後、別のパスでライト計算をまとめて行いますが、いずれにせよライティング処理もレンダリング工程の一部です。さらに全ジオメトリ描画が終わった後、ポストプロセス効果として Bloom(発光ぼかし)や被写界深度、カラーグレーディングなどの画面効果を適用します。UnityではScriptableRenderPipeline内でこれらをキュー処理し、例えば URP なら「Opaque→Skybox→Transparent→PostProcess」の順に実行されます。

  • ⑥ GPU→CPU: フレーム完了・表示 – GPUが全ての描画とエフェクト適用を終えると、完成したフレームはバックバッファに用意されています。Unity(というより基盤のGraphics API)はこのバックバッファをフロントバッファと入れ替えて表示する Present 処理を行います。SwapChain(スワップチェイン)と呼ばれる仕組みでバックバッファ→フロントバッファの交換(バッファスワップ)が行われ、最新のフレーム画像がモニタに映し出されるわけです。これで1フレームのレンダリングがすべて完了します。

// (参考)URP/HDRP の ScriptableRenderPipeline 内部での描画処理イメージ
context.DrawRenderers(cullResults, ref drawingSettings, ref filteringSettings);
context.Submit();  // DrawCallをGPUに送り出す

ワンポイント: 上記の Unity 処理全体を指して、エンジン内部では RenderLoop(レンダーループ)と呼んでいます。Profiler でCPU時間を見ると RenderPipelineManager.DoRenderLoop_Internal などと表示されるアレです。開発者がこれを直接触ることは通常ありませんが、Frame Debugger を使えば Unity が各フレームで実行した描画イベント(カメラのクリア→シャドウマップ描画→各オブジェクト描画→ポストエフェクト…といった順序)を確認することができます。デバッグに積極的に活用しましょう。


3️⃣ DirectX (C++) の場合:Draw から Present までの流れ

DirectXやOpenGLなど低レベルAPIでも、基本的な流れはUnityと同じです。ここでは DirectX11 相当の pseudo-code で描画~表示の流れを見てみます。

// 1. 描画準備: 頂点バッファとインデックスバッファをバインド
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
context->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0);

// 2. シェーダや定数バッファのセット(省略)
//    ここでワールド変換行列やライティング情報をGPUに渡す

// 3. 描画コール: インデックスを用いて描画実行
context->DrawIndexed(indexCount, 0, 0); // ← 描画 (Draw)

// (GPU側で頂点シェーダ→ピクセルシェーダ実行、レンダーターゲットに描画)

// 4. ポストエフェクト処理など(必要に応じて別レンダーターゲットに描画し直す)
//    ...(省略)...

// 5. フレームを画面に表示
swapChain->Present(1, 0);               // ← レンダリング完了 (表示)

解説:

  • ① バッファ設定IASetVertexBuffers で GPU のインプットアセンブラーに頂点バッファをセットし、IASetIndexBuffer でインデックスバッファをセットします。これにより GPU は描画すべき頂点リストと三角形のつながりを把握します。

  • ② シェーダ設定 – 上記コードでは省略していますが、通常この前に VSSetShaderPSSetShader で頂点シェーダ・ピクセルシェーダをバインドし、VSSetConstantBuffers などで変換行列やライト情報などの定数バッファを渡します。例えばモデルのワールド行列やビュー・射影行列(MVPマトリクス)、光源位置などです。

  • ③ DrawIndexed 呼び出しcontext->DrawIndexed(indexCount, 0, 0) を呼ぶことで、現在セットされた頂点/インデックスバッファやシェーダを使って描画せよ、とGPUに命令します。この関数を呼ぶと、GPU上で頂点シェーダラスタライズピクセルシェーダといった一連のパイプライン処理が実行されます。頂点シェーダでは各頂点を画面空間に変換し、ピクセルシェーダでテクスチャやライティングからピクセルの色を計算、**レンダーターゲット(バックバッファ)**に書き込みます。この DrawIndexed を呼んだ時点では、まだ描画結果は画面に表示されていない点に注意してください。あくまでバックバッファ上にピクセルが描き込まれただけで、“裏で描画が完了した”状態です。

  • ④ ポストエフェクト – 必要であれば、シェーダ内や追加の描画パスでポストプロセスを行います。例えばブルーム効果をかける場合、一度シーンをオフスクリーンのレンダーターゲットテクスチャに描画し、そのテクスチャにブラーを掛けてからバックバッファに合成するといった処理を挟みます。DirectX自体にはポストエフェクト用の特別な関数は無く、通常の描画処理をもう一度行うだけですが、エンジンが隠蔽しているUnityとは異なり、自前でこの手順を実装する必要があります。

  • ⑤ Present 呼び出し – 最後に swapChain->Present(1, 0) を呼ぶことで、バックバッファとフロントバッファを入れ替え表示します。DirectXでは描画用のフレームバッファをダブルバッファリングしており、Present を呼ぶと「今描いていた裏側のバッファ(backbuffer)」が「表の画面バッファ(screenbuffer)」に切り替わり、ユーザーの画面に映ります。この操作を一般にバッファスワップ (フリップ) と呼び、Swap Chainによって管理されています。DrawIndexedでポリゴンを塗っただけでは画面に何も変化がないのは、Present が呼ばれて初めて描いた内容が表に出るからです。

補足: DirectXアプリ開発では描画ループ内で「クリア→Draw(複数回)→Present」という順序を毎フレーム繰り返します。上記 DrawIndexed 以降のGPU処理は、Unityの場合と同様に入力アセンブラー頂点シェーダ→(テッセレーション/ジオメトリシェーダ)→ラスタライザピクセルシェーダ出力マージャというパイプラインで進みます。特に最後の出力マージャ (OM)ステージで深度バッファに基づく隠面処理ブレンディング(半透明の合成など)が行われ、最終的なピクセルがバックバッファに書き込まれます。このように低レベルAPIでは細かなステージを意識する必要がありますが、概ね「DrawCallで描画命令→GPUでシェーダ実行→Presentで表示」という大局はゲームエンジンでも共通です。

  • デバッグ: 自前のDirectX/C++レンダリングで「何も映らない」「一部がおかしい」という場合、原因切り分けには RenderDocVisual Studio Graphics Debugger(旧称 PIX)といったツールが強力な味方です。これらを使うとキャプチャしたフレーム内のDrawCall一覧や各ピクセルのシェーダ入力/出力を調べることができます。Unity開発でも同様に RenderDoc は利用可能で、より高度なデバッグが必要な際には FrameDebuggerと使い分けると良いでしょう。

4️⃣ あるある: “映らない”トラブル5連発 & 即チェックポイント

初心者がハマりがちな「シーンにオブジェクトを置いたのに何も表示されない / 一部おかしい」トラブルについて、原因と対処のヒントをまとめました。

症状 🐛 原因になりやすい箇所 (まず疑う) 確認すべき設定・機能
オブジェクトが完全に表示されない カメラのCulling設定
(レイヤー/タグの不一致)
Unity: Cameraの Culling Mask(カメラが写すレイヤーか?)
DX: ビュー行列の範囲やDepthStencil設定
特定の距離で消えてしまう クリッピング平面の設定ミス Cameraの Near/Far Clip Plane(近すぎ・遠すぎで切れてないか)
ライトの効果が全く出ない Shaderが Unlit(光対応していない)
または ライトの影響除外
Unity: マテリアルのシェーダが Lit か確認
Unity: Lightの Layer 適用範囲など確認
🔧 FrameDebugger で該当オブジェクト描画時にライト値が計算されているか見る
透過オブジェクトが前後おかしい Depth書き込みやQueue設定ミス マテリアルの RenderQueue(3000=Transparentか)
シェーダの ZWrite が適切か(透過ならOff)
画面全体が真っ黒/真っ白になる ポストエフェクトのバッファ設定ミス URP/HDRP の Render Feature 設定
カメラの RenderTexture 設定(意図せず黒_textureを参照してないか)

トラブルシュート解説:

  • 🕵️ レイヤー・カリングの確認: Unityではカメラごとに描画対象のLayerを指定できます。例えばオブジェクトがDefaultレイヤーなのにカメラのCullingMaskがDefaultを含んでいなければ映りません。同様にタグ指定の処理で非表示にしている場合もチェックしましょう。DirectX等低レベルでは明示的なレイヤーはありませんが、カメラの視錐台(View Frustum)外に出ていないかや、深度ステンシル設定で描画が抑制されていないかを疑います。まずはカメラが正しい位置・向きで対象を捉えているか、Clipping距離内に収まっているかを確認してください。

  • 🕵️ Near/Far Clipの確認: カメラのNear Clip Plane(近接クリップ面)より手前にある物体、およびFar Clip Plane(遠方クリップ面)より奥の物体は描画されません。シーンビューでカメラを選択すると青いワイヤーフレームの視錐台が表示されますが、オブジェクトがその範囲内に入っているか確認しましょう。遠近の値を極端に絞っていないかも要チェックです。

  • 🕵️ ライト・シェーダの確認: 「ライトを置いたのに明るくならない!」という場合、アサインしているマテリアルのシェーダが Unlit(ライティング無し)になっていないか確認します。Unlitシェーダは光源の影響を受けないため、どれだけライトを当てても見た目が変化しません。また、特定のライトだけ影響しない場合はLayerVolumeによる影響範囲も確認しましょう。Unityなら Frame Debugger でライトパスを確認したり、RenderDocで該当ピクセルのシェーダ計算を調べることで原因究明できます。

  • 🕵️ 透明オブジェクトの描画順: 透明オブジェクトの表示順がおかしい場合、深度バッファへの書き込み (ZWrite) を誤ってOnにしていないか、または **RenderQueue(描画順序タグ)**が不適切でないかを見直します。通常、透明物は後描きするため Queue=Transparent (3000) とし、かつ ZWrite は Off にします。これがズレていると、透明ポリゴン同士の奥行き判定ができず描画順が前後して見えることがあります。

  • 🕵️ ポストプロセス設定: シーン全体が真っ黒になる場合、ポストエフェクト周りのミスが疑われます。URP/HDRP で自作の Render Feature を追加したけど適切にブリット(blit)していない場合や、カメラの出力先をRenderTextureにしていてそのTextureに何も描画されていない場合などです。まずポストエフェクトを一旦OFFにして正常描画に戻るか確認し、各エフェクトの入力・出力先が正しく設定されているかチェックしましょう。場合によってはカメラのHDR設定Gamma/Linear設定の不一致で真っ白に飛ぶケースもあります。


5️⃣ シェーダ初心者向け: 最小限の HLSL 例

最後に、描画レンダリングの役割の違いを理解する助けとして、超シンプルな HLSLシェーダーの例を示します。頂点シェーダとピクセルシェーダに分かれていることに注目してください。

// 最も単純な頂点シェーダ & ピクセルシェーダの例
float4 mainVS(float3 pos : POSITION) : SV_POSITION {
    // Model-View-Projection行列で頂点を画面座標へ変換
    return mul(UNITY_MATRIX_MVP, float4(pos, 1.0));
}

float4 mainPS() : SV_Target {
    // 単純に固定のオレンジ色を返す
    return float4(1, 0.5, 0.1, 1);
}

解説: 上記はUnityの頂点定数UNITY_MATRIX_MVPを使って頂点位置posを画面に投影し、ピクセルシェーダでは常にオレンジ色(1,0.5,0.1,1)を返すだけの最小シェーダです。これでもシーンに適用すればオブジェクトはオレンジ色で描画されます。

  • 描画(頂点シェーダ): mainVS描画ステージに対応し、各頂点を現在のカメラ空間に変換しています。ここではライティングや質感は一切計算しておらず、「頂点をどこに描くか」だけを決めています。Draw とはまさにこの段階で、ポリゴンの形状がスクリーン上に配置される処理です。

  • レンダリング(ピクセルシェーダ): mainPSレンダリングステージの核心で、最終的なピクセルの色を決定しています。この例では一定のオレンジ色を塗るだけですが、通常はここでテクスチャをサンプリングしたり光の影響を計算します(例えば Lambert や Phong といったライティング計算)。ピクセルシェーダの出力はそのままフレームバッファ (SV_Target) に書き込まれます。言い換えれば、Render とはピクセルシェーダで色を確定しフレームバッファに出力し終えるまでの処理を指すのです。

補足: もちろん現実のシェーダはもっと複雑で、頂点シェーダで法線を変換したり、ピクセルシェーダで影計算や視差マッピングをしたりします。しかし根本的には「形を描く (頂点処理)」→「色を塗る (ピクセル処理)」という二段構えになっている点はどのシェーダでも同じです。これが描画とレンダリングの役割の違いとも対応しているわけです。


6️⃣ まとめ

  1. 描画 (Draw) = オブジェクトのジオメトリ情報を GPU に送り、ポリゴンを画面上に描く行為。実装的には Draw Call を発行するステージ。
  2. レンダリング (Render) = 最終的な画像を生成して表示するまでの一連の処理。ライティング計算やポストエフェクトも含めた包括的な概念。
  3. 「映らない!」ときのチェック順 📝 – まずカメラの設定(視野・レイヤー)、次にシェーダ/マテリアル、最後に描画順や深度処理を疑うと効率的です。不具合の大半はこのどれかに起因します。
  4. デバッグには Unityなら Frame Debuggerネイティブなら RenderDoc 等を活用しましょう。描画の流れを1フレーム単位で追うことで原因解明の糸口がつかめます。

以上、描画とレンダリングの違い、およびその内部処理について解説しました。ゲーム開発初学者の方のお役に立てれば幸いです!🎮✨


🎁 おまけ:個別サポートのご案内

MENTA にて描画・レンダリングに関する技術相談を受け付けています!
無料30分の体験プランもありますので、お気軽にどうぞ。Unity / C++ / DirectX / Shader の基礎から実装レビューまで対応可能です。
卒業制作やポートフォリオで「ここだけ凝りたい!」といった表現の相談も歓迎します 🕊
🔗 プロフィール & プラン一覧はこちら


参考リンク

この記事が参考になったら是非 LGTM 👍 やフォローをお願いします!質問等あればお気軽にコメントください。

2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?