この章では深度バッファ(Zバッファ、デプスバッファ)という3DCGで必須の技術について学びます。
5章14節の内容の理解を前提とします。
3次元空間上にモノが沢山置いてあるとき、描画するときに問題になるのが前後関係です。 ひとつ例として、2つの立方体を回してみましょう。5章14節のコードの描画部を以下のようにします。
static std::chrono::system_clock::time_point prevTime;
static float rotation = 0.0f;
const auto nowTime = std::chrono::system_clock::now();
const auto delta = std::chrono::duration_cast<std::chrono::microseconds>(nowTime - prevTime).count();
rotation += delta * 2 * 3.14f / 1000000 * (0.2f);
rotation = fmod(rotation, 2 * 3.14159f);
prevTime = nowTime;
// 箱1
auto model1 = translationMatrix({cos(rotation), sin(rotation), 0.0f}) * rotationMatrix({0.0f, 0.0f, 1.0f}, rotation) * scaleMatrix(1.0f);
// 箱2
auto model2 = translationMatrix({-cos(rotation), -sin(rotation), 0.0f}) * rotationMatrix({0.0f, 0.0f, 1.0f}, rotation) * scaleMatrix(1.0f);
auto view = viewMatrix({0.0f, -3.0f, -2.0f}, {0.0f, +0.8f, +0.6f}, {0.0f, +0.6f, -0.8f});
auto proj = projectionMatrix(3.14f / 3, float(screenHeight) / float(screenWidth), 0.1f, 100.0f);
sceneData.mvpMatrix = proj * view * model1;
cmdBufs[0]->pushConstants(pipelineLayout.get(), vk::ShaderStageFlagBits::eVertex, 0, sizeof(SceneData), &sceneData);
cmdBufs[0]->drawIndexed(indices.size(), 1, 0, 0, 0);
sceneData.mvpMatrix = proj * view * model2;
cmdBufs[0]->pushConstants(pipelineLayout.get(), vk::ShaderStageFlagBits::eVertex, 0, sizeof(SceneData), &sceneData);
cmdBufs[0]->drawIndexed(indices.size(), 1, 0, 0, 0);
何かが変ですね。前後関係がおかしくなっています。 これはどういうことかというと、3次元的な位置とは無関係に後から描画されたものが前に出ているのです。 これをどうにかしないとまともな3D描画はできません。そこで出てくるのが深度バッファです。
深度バッファの概要
描画の際、画面に実際に出力する画像とは別に、「深度バッファ」と呼ばれるユーザーには直接見えない画像バッファを用意します。
そして、各ピクセルにZ軸の情報を書き込むようにします。
その上で描画する際、深度バッファを参照してすでに書き込まれているZ軸の情報を確認するのです。その結果今描画しようとしているピクセルよりも前に来るのであれば描画をスキップします。これによって描画順序に関わらず前後関係を正しく描画することができます。
今のGPUであれば基本的に組み込まれている機能なので、細かい中身について気にする必要はありません。しかしVulkanの場合、
- 深度バッファのためのメモリを確保する・イメージビューを作成する
- レンダーパス・パイプラインなどに設定を施す
などのことは自分で行う必要があります。これからその手順を確認していきます。