Vulkan:在动态视口之间更新相机

我正在遵循Vulkan教程系列,并且正在使用此基本代码(https://vulkan-tutorial.com/code/21_descriptor_layout.cpp)并在draw调用中创建多个动态视口,如下所示。修改后的代码在反斜杠内。我已经设置了管道以启用视口动态状态。

void drawFrame() {


    vkWaitForFences(device,1,&inFlightFences[currentFrame],VK_TRUE,(std::numeric_limits<uint64_t>::max)());

    uint32_t imageIndex;
    VkResult result = vkAcquireNextImageKHR(device,swapChain,(std::numeric_limits<uint64_t>::max)(),imageAvailableSemaphores[currentFrame],VK_NULL_HANDLE,&imageIndex);

    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
        recreateSwapChain();
        return;
    }
    else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
        throw std::runtime_error("failed to acquire swap chain image!");
    }

    VkSubmitInfo submitInfo = {};
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

    VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
    VkPipelinestageflags waitStages[] = { VK_PIpelINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = waitSemaphores;
    submitInfo.pWaitDstStageMask = waitStages;

    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &commandBuffers[imageIndex];

    VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = signalSemaphores;

    vkResetfences(device,&inFlightFences[currentFrame]);

    //////////////BEGINNING OF SETTING VIEWPORTS//////////////////////////////////////////

    VkCommandBufferBeginInfo beginInfo = {};
    beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;

    if (vkBeginCommandBuffer(commandBuffers[imageIndex],&beginInfo) != VK_SUCCESS) {
        throw std::runtime_error("failed to begin recording command buffer!");
    }

    VkClearColorValue defaultClearColor = { { 1.025f,0.025f,1.0f } };
    VkClearValue clearValues[2];
    clearValues[0].color = defaultClearColor;
    clearValues[1].depthStencil = { 1.0f,0 };

    VkRenderPassBeginInfo renderPassInfo = {};
    renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    renderPassInfo.renderPass = renderPass;
    renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
    renderPassInfo.renderArea.offset = { 0,0 };
    renderPassInfo.renderArea.extent = swapChainExtent;
    renderPassInfo.pClearValues = clearValues;
    renderPassInfo.clearValueCount = 1;
    vkCmdBeginRenderPass(commandBuffers[imageIndex],&renderPassInfo,VK_SUBPASS_CONTENTS_INLINE);


    VkCommandBuffer command_buffer = commandBuffers[imageIndex];
    for (int i = 0; i < DisplayManager::win.size(); i++) {

            uint32_t first_viewport = 0;
            std::vector<VkViewport> viewports;
            VkViewport viewport = {};

            //also have to flip models y.
            viewport.width = (float)DisplayManager::win.at(i).viewWidth * (((float)DisplayManager::screenWidth/(float)DisplayManager::initialX));
            viewport.height = -(float)DisplayManager::win.at(i).viewHeight* (((float)DisplayManager::screenHeight / (float)DisplayManager::initialY));

            viewport.x = DisplayManager::win.at(i).viewPortPosX * (((float)DisplayManager::screenWidth / (float)DisplayManager::initialX)); 
            viewport.y = (DisplayManager::screenHeight - DisplayManager::win.at(i).viewPortPosY* (((float)DisplayManager::screenHeight / (float)DisplayManager::initialY)));

            viewport.minDepth = 0.0f;
            viewport.maxDepth = 1.0f;


            viewports.push_back(viewport);
            vkCmdSetViewport(command_buffer,first_viewport,static_cast<uint32_t>(viewports.size()),viewports.data());

            VkRect2D scissor = {};
            scissor.offset = { 0,0 };
            scissor.extent = swapChainExtent;
            vkCmdSetScissor(command_buffer,&scissor);

            vkCmdBindPipeline(commandBuffers[imageIndex],VK_PIpelINE_BIND_POINT_GRAPHICS,graphicsPipeline);
            vkCmdDraw(commandBuffers[imageIndex],3,0);

    }
    vkCmdEndRenderPass(commandBuffers[imageIndex]);

    if (vkEndCommandBuffer(commandBuffers[imageIndex]) != VK_SUCCESS) {
        throw std::runtime_error("failed to record command buffer!");
    }
    //////////////////////////////////////////////////////////////////////

    if (vkQueueSubmit(graphicsQueue,&submitInfo,inFlightFences[currentFrame]) != VK_SUCCESS) {
        throw std::runtime_error("failed to submit draw command buffer!");
    }

    VkPresentInfoKHR presentInfo = {};
    presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = signalSemaphores;

    VkSwapchainKHR swapChains[] = { swapChain };
    presentInfo.swapchainCount = 1;
    presentInfo.pSwapchains = swapChains;

    presentInfo.pImageIndices = &imageIndex;

    result = vkQueuePresentKHR(presentQueue,&presentInfo);

    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
        framebufferResized = false;
        recreateSwapChain();
    }
    else if (result != VK_SUCCESS) {
        throw std::runtime_error("failed to present swap chain image!");
    }
    currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}

我可以动态地调整和设置视口,但是我想做的是更新发送到着色器的摄影机转换,以便每个视口可以使用类似的东西独立地调整它的摄影机视矩阵。

for (int i = 0; i < DisplayManager::win.size(); i++) {
 //setViewport
 //update_camera_transform().
 //I've tried updating a single uniform butter object here and a dynamic uniform buffer object from
 //Sasha William's examples code. 
        vkCmdBindPipeline(commandBuffers[imageIndex],graphicsPipeline);
        vkCmdDraw(commandBuffers[imageIndex],0); 
}

我想知道基本代码提供的当前设置是否可行,或者有人是否可以将我指向正确的方向?

hrhhurunhong 回答:Vulkan:在动态视口之间更新相机

相机变换实际上与希望每帧传送到GPU的任何其他统一状态没有什么不同。除非您想浪费一堆推常量,否则您可能会使用UBO或只读SSBO。

典型的解决方案是为这些事情留出一些内存,然后从该内存中为您正在处理的当前帧分配一个分片。然后,您可以使用动态描述符选择单个绘图调用数据的位置,或者提供一个包含数据数组和提供该对象的数组索引的推送常量的描述符。对于您的情况,很多抽奖将获取相同的数据,我建议使用动态描述符。

主要是要确保您不会覆盖前一帧当前正在使用的数据。因此,内存存储至少需要双缓冲,并且您需要进行适当的同步以确保所有工作都可以进行。为此,您在篱笆上等待就足够了。

如何将数据传输到内存由您决定。如果可以将主机可写内存用于UBO,则可以在构建命令缓冲区时仅写入映射的指针。如果没有,那么您将需要一些传输命令。而且您不能在渲染过程中间进行该操作。因此,您需要同时构建两个命令缓冲区(一个用于传输数据,另一个用于呈现内容)。然后,您以正确的顺序提交两个命令缓冲区。

当然,无论如何将数据写入内存,都将需要适当的同步。同步发生在渲染过程实例之前或作为源外部子过程依赖项。

,

作为Vulkan的新手,我认为对本帖子的问题可能会更准确地描述为“如何在绘图调用中将不同的矩阵/数据发送到着色器”。 一种解决方案是使用动态统一缓冲区,因为摄影机视口的数量对于我来说也是动态的。 Sacha Williams在此处提供了有关如何使用Dynamic UBOS的示例。 https://github.com/SaschaWillems/Vulkan/tree/master/examples/dynamicuniformbuffer

我在此基础代码上进行了扩展,以在一个描述符集中包含2个动态UBO,并在另一个集中包含另一个动态UBO(这使我可以以独立于每个集合的不同速率更新制服)和推送常数。下面的代码基于Sacha William的Dynamic UBO示例,并且是概念证明,虽然最多可以认为它是鸡的抓手,但它提供了以下必要的设置:

在同一描述符集中有2个动态UBO。 另一个描述符集中有1个动态UBO。 1推常数。

修改了变量,设置所有动态ubo缓冲区/对齐方式,就像他的示例中使用的原始mat4一样。像他的示例一样,在Draw调用之外更新Dynamic Uniforms。

#define OBJECT_INSTANCES 125
#define CAM_INSTANCES 2

struct {
    vks::Buffer viewBuffer;
    vks::Buffer dynamicBuffer; 
    vks::Buffer Buffer_second;
    vks::Buffer dynamicBuffer_second;
} uniformBuffers;

struct {
    glm::mat4 projection_mat;
    glm::mat4 view_mat;
    glm::mat4 model_mat;
} uboVS;

struct { 
    glm::mat4 model_mat_secondary;
} uboVS_secondary; 

struct UboDataDynamic {
    glm::mat4 *model = nullptr;
} uboDataDynamic;
struct UboDataDynamic_second {
    glm::mat4 *model = nullptr;
} uboDataDynamic_second;

size_t dynamicAlignment;
size_t dynamicAlignment_second;

glm::mat4 pushConstants;



void setupDescriptorSetLayout()
    {
        /////////////////////////////set 0 layout///////////////////////////////////////////////////////////////////////////////////
        {
            std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
            {
                vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,VK_SHADER_STAGE_VERTEX_BIT,0),vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,1),2),vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,3),};

            VkDescriptorSetLayoutCreateInfo descriptorLayout =
                vks::initializers::descriptorSetLayoutCreateInfo(
                    setLayoutBindings.data(),static_cast<uint32_t>(setLayoutBindings.size()));

            VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device,&descriptorLayout,nullptr,&descriptorSetLayout[0]));
        }

        /////////////////////////////set 1 layout///////////////////////////////////////////////////////////////////////////////////
        {
            std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
            {

                vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,4),&descriptorSetLayout[1]));  
        }

        VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
            vks::initializers::pipelineLayoutCreateInfo(
                &descriptorSetLayout[0],2);

        VkPushConstantRange pushConstantRange =
            vks::initializers::pushConstantRange(
                VK_SHADER_STAGE_VERTEX_BIT,sizeof(pushConstants),0);

        // Push constant ranges are part of the pipeline layout
        pPipelineLayoutCreateInfo.pushConstantRangeCount = 1;
        pPipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;

        VK_CHECK_RESULT(vkCreatePipelineLayout(device,&pPipelineLayoutCreateInfo,&pipelineLayout));
    }

    void setupDescriptorPool()
    {

        std::vector<VkDescriptorPoolSize> poolSizes =
        {
            vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,1)
        };

        VkDescriptorPoolCreateInfo descriptorPoolInfo =
            vks::initializers::descriptorPoolCreateInfo(
                static_cast<uint32_t>(poolSizes.size()),poolSizes.data(),2);

        VK_CHECK_RESULT(vkCreateDescriptorPool(device,&descriptorPoolInfo,&descriptorPool));
    }

    void setupDescriptorSet()
    {
        {
            VkDescriptorSetAllocateInfo allocInfo =
                vks::initializers::descriptorSetAllocateInfo(
                    descriptorPool,&descriptorSetLayout[0],1);

            VK_CHECK_RESULT(vkAllocateDescriptorSets(device,&allocInfo,&descriptorSet));


            std::vector<VkWriteDescriptorSet> writeDescriptorSets = {   
                vks::initializers::writeDescriptorSet(descriptorSet,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,&uniformBuffers.viewBuffer.descriptor),vks::initializers::writeDescriptorSet(descriptorSet,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,1,&uniformBuffers.dynamicBuffer.descriptor),2,&uniformBuffers.dynamicBuffer_second.descriptor),3,&uniformBuffers.Buffer_second.descriptor),};

            vkUpdateDescriptorSets(device,static_cast<uint32_t>(writeDescriptorSets.size()),writeDescriptorSets.data(),nullptr);
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        {
            VkDescriptorSetAllocateInfo allocInfo =
                vks::initializers::descriptorSetAllocateInfo(
                    descriptorPool,&descriptorSetLayout[1],&descriptorSet_alt));
            std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
            vks::initializers::writeDescriptorSet(descriptorSet_alt,4,nullptr);
        }
    }


    void draw()
    {
        vkWaitForFences(device,&waitFences[currentFrame],VK_TRUE,UINT64_MAX);

        uint32_t imageIndex;
        vkAcquireNextImageKHR(device,swapChain.swapChain,UINT64_MAX,semaphores.presentComplete,VK_NULL_HANDLE,&imageIndex);

        if (waitFences[imageIndex] != VK_NULL_HANDLE) {
            vkWaitForFences(device,&waitFences[imageIndex],UINT64_MAX);
        }
        waitFences[imageIndex] = waitFences[currentFrame];

        VkSubmitInfo submitInfo = {};
        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

        VkSemaphore waitSemaphores[] = { semaphores.presentComplete };
        VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
        submitInfo.waitSemaphoreCount = 1;
        submitInfo.pWaitSemaphores = waitSemaphores;
        submitInfo.pWaitDstStageMask = waitStages;

        submitInfo.commandBufferCount = 1;
        submitInfo.pCommandBuffers = &drawCmdBuffers[imageIndex];

        VkSemaphore signalSemaphores[] = { semaphores.renderComplete };
        submitInfo.signalSemaphoreCount = 1;
        submitInfo.pSignalSemaphores = signalSemaphores;

        vkResetFences(device,&waitFences[currentFrame]);


        /////////////////////////////////////////////////////////
        VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();

        VkClearValue clearValues[2];
        clearValues[0].color = defaultClearColor;
        clearValues[1].depthStencil = { 1.0f,0 };

        VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
        renderPassBeginInfo.renderPass = renderPass;
        renderPassBeginInfo.renderArea.offset.x = 0;
        renderPassBeginInfo.renderArea.offset.y = 0;
        renderPassBeginInfo.renderArea.extent.width = width;
        renderPassBeginInfo.renderArea.extent.height = height;
        renderPassBeginInfo.clearValueCount = 2;
        renderPassBeginInfo.pClearValues = clearValues;


        // Set target frame buffer

        renderPassBeginInfo.framebuffer = frameBuffers[imageIndex];

        VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[imageIndex],&cmdBufInfo));
        vkCmdBeginRenderPass(drawCmdBuffers[imageIndex],&renderPassBeginInfo,VK_SUBPASS_CONTENTS_INLINE);

        for (int cam = 0; cam < CAM_INSTANCES ; cam ++) {

            glm::mat4 test;
            test = glm::scale(test,glm::vec3((cam+1) *2));
            pushConstants = test;


            vkCmdPushConstants(
                drawCmdBuffers[imageIndex],pipelineLayout,&pushConstants[0][0]);



            VkViewport viewport = vks::initializers::viewport((float)width / 2,(float)height,0.0f,1.0f);
            viewport.x = cam* 400;
            vkCmdSetViewport(drawCmdBuffers[imageIndex],&viewport);

            VkRect2D scissor = vks::initializers::rect2D(width,height,0);
            vkCmdSetScissor(drawCmdBuffers[imageIndex],&scissor);


            vkCmdBindPipeline(drawCmdBuffers[imageIndex],VK_PIPELINE_BIND_POINT_GRAPHICS,pipeline);

            VkDeviceSize offsets[1] = { 0 };
            vkCmdBindVertexBuffers(drawCmdBuffers[imageIndex],VERTEX_BUFFER_BIND_ID,&vertexBuffer.buffer,offsets);


            //Different set,can update at a different rate then other Dynamic UBOs in the 0th set. 

            //DynamicAlignments are all same size,mat4 in my implementation.
            uint32_t dynamicOffset  = cam * static_cast<uint32_t>(dynamicAlignment);

            int whichsetisthis = 1;
            int numberofdynamicbuffersinthisset = 1;
            vkCmdBindDescriptorSets(drawCmdBuffers[imageIndex],whichsetisthis,&descriptorSet_alt,numberofdynamicbuffersinthisset,&dynamicOffset );


            //Since these 2 dynamic ubos are in the same set,must update at the same rate.
            for (uint32_t j = 0; j < OBJECT_INSTANCES; j++)
            {

                uint32_t dynamicOffset = j * static_cast<uint32_t>(dynamicAlignment);
                uint32_t dynamicOffset1 = cam* static_cast<uint32_t>(dynamicAlignment);
                int whichsetisthis = 0;
                uint32_t d[2];
                d[0] = dynamicOffset;
                d[1] = dynamicOffset1;
                int numberofdynamicbuffersinthisset = 2;
                vkCmdBindDescriptorSets(drawCmdBuffers[imageIndex],&descriptorSet,d);

                vkCmdDraw(drawCmdBuffers[imageIndex],0);
            }



        }
        vkCmdEndRenderPass(drawCmdBuffers[imageIndex]);
        VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[imageIndex]));


        if (vkQueueSubmit(queue,&submitInfo,waitFences[currentFrame]) != VK_SUCCESS) {
            throw std::runtime_error("failed to submit draw command buffer!");
        }

        VkPresentInfoKHR presentInfo = {};
        presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

        presentInfo.waitSemaphoreCount = 1;
        presentInfo.pWaitSemaphores = signalSemaphores;

        VkSwapchainKHR swapChains[] = { swapChain.swapChain };
        presentInfo.swapchainCount = 1;
        presentInfo.pSwapchains = swapChains;

        presentInfo.pImageIndices = &imageIndex;

        vkQueuePresentKHR(queue,&presentInfo);

        currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
    }

顶点着色器:

#version 450

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor; 

layout (set = 0,binding = 0) uniform UboView 
{
    mat4 projection;
    mat4 view;
    mat4 model;
} uboView;

layout (set = 0,binding = 1) uniform UboInstance 
{
    mat4 model; 
} uboInstance;

layout (set = 0,binding = 2) uniform UboInstance_second 
{
    mat4 model; 
} uboInstance_second; 

layout (set = 0,binding = 3) uniform UboView_secondary 
{ 
    mat4 model_secondary;
} uboView_secondary; 

layout (set = 1,binding = 4) uniform UboView_third 
{ 
    mat4 model_third;
} uboView_third;

layout(push_constant) uniform PushConsts {
    mat4 camPos;
} pushConsts;


layout (location = 0) out vec3 outColor;

out gl_PerVertex 
{
    vec4 gl_Position;   
};

void main() 
{
    outColor = inColor;
    mat4 modelView = uboView.view * uboInstance.model *uboView.model*uboView_secondary.model_secondary*pushConsts.camPos*uboInstance_second.model*uboView_third.model_third ;
    vec3 worldPos = vec3(modelView * vec4(inPos,1.0));
    gl_Position = uboView.projection * modelView * vec4(inPos.xyz,1.0);
}
本文链接:https://www.f2er.com/3072393.html

大家都在问