微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我遵循了这个 vulkan 教程的大部分内容

https://vulkan-tutorial.com/

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

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

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

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

UpdateUniformBuffer 函数

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),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],sizeof(ubo),&data);
memcpy(data,&ubo,sizeof(ubo)); 
vkUnmapMemory(device,uniformBuffersMemory[currentimage]); }

UniformBufferObject 结构

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

解决方法

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

这可能看起来像这样:

vkCmdBindVertexBuffers(commandBuffer,1,&vertexBuffer,offsets);
vkCmdBindIndexBuffer(commandBuffer,indexBuffer,VK_INDEX_TYPE_UINT32);
for (Object object : objects) 
{
    vkCmdBindDescriptorSets(commandBuffer,VK_PIPELINE_BIND_POINT_GRAPHICS,pipelineLayout,&object.descriptorSet[currentImage],nullptr);
    vkCmdDrawIndexed(commandBuffer,object.indexCount,object.firstIndex,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 教程学到的知识的基础上,这是一个良好的开端。

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。