如何为已渲染的多个3D模型拥有多个模型矩阵?

2024-03-30

我已经遵循了 vulkan 教程的大部分内容:

https://vulkan-tutorial.com/ https://vulkan-tutorial.com/

我目前有一个 vulkan 程序,可以使用 OBJ 文件加载多个 3D 模型,但是我只有一个模型矩阵来控制所有 3D 模型,例如,如果我加载 2 个立方体,然后将旋转矩阵应用于两个立方体的模型矩阵会旋转。

我想要每个 3D 模型都有一个模型矩阵,以便我可以单独旋转、平移和缩放。

在遵循教程时,我创建了以下函数,称为“UpdateUniformBuffer”。该函数包含每秒将旋转矩阵应用于模型矩阵的代码。

它还使用我创建的名为“UniformBufferObject”的结构。

更新UniformBuffer函数

void updateUniformBuffer(uint32_t currentImage) {

static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count(); 

UniformBufferObject ubo{}; 
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));   
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float) swapChainExtent.height, 0.1f, 10.0f);  
ubo.proj[1][1] *= -1;

void* data;
vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
memcpy(data, &ubo, sizeof(ubo)); 
vkUnmapMemory(device, uniformBuffersMemory[currentImage]); }

UniformBufferObject 结构

struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

有不同的方法,但最直接的方法只是您已经所做的事情的扩展,即为每个对象提供多个统一缓冲区,并为这些统一缓冲区提供单独的描述符。在绘制时,您可以为要绘制的对象绑定适当的描述符集,该描述符集指向它的统一缓冲区。

这可能看起来像这样:

vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT32);
for (Object object : objects) 
{
    vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &object.descriptorSet[currentImage], 0, nullptr);
    vkCmdDrawIndexed(commandBuffer, object.indexCount, 1, object.firstIndex, 0, 0);
}

你的对象定义可能如下所示:

struct Object {
    uint32_t indexCount;
    uint32_t firstIndex;
    VkBuffer buffer;
    VkDescriptorSet descriptorSet;
};
std::vector<Object> objects;

因此,您不是只有一个统一缓冲区和一个指向它的描述符集,而是为每个对象创建一组,然后更新彼此分开的缓冲区:

for (Object object : objects) {
    memcpy(bufferPtr[currentImage], &ubo, sizeof(ubo)); 
}

一个小注意事项:您不需要在每个帧上映射和取消映射缓冲区。您可以在创建后安全地映射缓冲区一次(“持久映射”)。

虽然这可能不是为每个对象提供统一缓冲区的完美方式,但它是基于您通过 vulkan 教程学到的知识的良好开端。

还有其他方法可以为每个对象传递数据,例如通过提到的推送常量(尽管需要在更改时重建命令缓冲区),但与往常一样,具体方法取决于您的用例。

另请注意,由于实现特定的限制,您希望将内存/缓冲区分配保持在最低限度。因此,如果您计划绘制大量对象,您应该查看动态统一缓冲区或子分配,而不是为每个对象分配单独的缓冲区。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何为已渲染的多个3D模型拥有多个模型矩阵? 的相关文章

随机推荐