Search code examples
c++cameravulkan

Handle multiply cameras in Vulkan


I'm trying to implement rendering with different cameras. When I use only one camera, everything is ok. But when I have two cameras with different transformation, rendering doesn't work properly, first scene is rendered with second camera transformation.

void Setup() {
    ...
    // create uniform buffer (vmaCreateBuffer)
    global_uniform_buffer = ... 
    // allocate descriptor set 
    global_descriptor_set = ... 
    // write descriptor set
    ...
}

void SetCameraProperties(Camera* camera) {
    auto proj_view = camera->GetProjectionMatrix() * camera->GetViewMatrix();
    global_uniform_buffer->update(&proj_view, sizeof(glm::mat4));
}

void BindGlobalDescriptorSet(vk::CommandBuffer cmd, vk::PipelineLayout pipeline_layout) {
    cmd.bindDescriptorSets(
        vk::PipelineBindPoint::eGraphics, 
        pipeline_layout, 
        0, 
        { global_descriptor_set }, 
        {}
    );
}

void DrawScene() {
    ...
    cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
    BindGlobalDescriptorSet(cmd, pipeline_layout);
    cmd.bindVertexBuffers(0, vtx->handle, vk::DeviceSize{0});
    cmd.bindIndexBuffer(idx->handle, vk::DeviceSize{0}, vk::IndexType::eUint16);
    cmd.drawIndexed(3, 1, 0, 0, 0);
    ...
}

void Loop() {
    ... // begin render pass with scene framebuffer
    SetCameraProperties(Editor::Get()->GetEditorCamera()):
    DrawScene();
    ... // end previous render pass
    ... // begin render pass with game frame buffer
    SetCameraProperties(CameraSystem::Get()->GetMainCamera()):
    DrawScene();
    ... // end previous render pass
    ... // present
}

Solution

  • Looking at your code, you change the same uniform buffer between two draw calls at command buffer creation time. But the contents of the bound uniform buffer are consumed at submission time instead and not at creation time. So by the time you submit your command buffer, it uses the uniform buffer contents from your last update.

    So your current setup won't work in Vulkan that way. To make this work, you could use one UBO per camera or one dynamic UBO with separate ranges for the cameras.