Vulkan,对象需要什么变量?就像在可以单独更新的单独网格中一样
Vulkan, what variables does an object need? As in a separate mesh that can be updated individually
所以我一直在试验,我可以通过将场景中的每个模型添加到同一个顶点缓冲区来添加一个新的“对象”,但这对体素游戏来说并不好,因为我不想每次玩家摧毁一个方块时,都必须重新组织整个世界的顶点。
看来我还可以通过为它创建一个新的顶点和索引缓冲区来添加一个新的“对象”,然后简单地将它和所有其他顶点缓冲区同时绑定到命令缓冲区数组,如下所示:
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
// mesh 1
VkBuffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
// mesh 2
VkBuffer vertexBuffers2[] = { vertexBuffer2 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers2, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer2, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffers[i]);
但是这需要我每次都将所有顶点缓冲区绑定到命令缓冲区数组,即使这些网格中只有一个被更新或 created/destroyed。那么我将如何“添加”一个新的“游戏对象”,它的顶点和索引可以更新而不必循环遍历场景中的其他所有内容?还是绑定到已经计算好的顶点和索引缓冲区相对较快,这是标准的?
而且我已经尝试对每个对象使用一个命令缓冲区:
VkSubmitInfo submits[] = { submitInfo, submitInfo2 };
if (vkQueueSubmit(graphicsQueue, 2, submits, inFlightFences[currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!");
}
但它只渲染队列中的最后一个对象(如果我说提交大小为 1,它将渲染第一个对象)。
我也尝试添加一个单独的描述符集、描述符池和管道,但它仍然只呈现队列中的最后一个命令缓冲区。我尝试为每个对象添加一个新的命令池,但是 commandPool
被许多其他函数使用,而且看起来应该只有其中一个。
你将你的世界分割成块,一次绘制一个块。所有块都在(单个)顶点缓冲区中为它们保留了一些 space ,并且当某些内容发生变化时,您只更新那个块。如果一个块变得太大......好吧,你可能需要某种内存分配系统。
不要为每一件小事创建单独的缓冲区。缓冲区只是保存数据。任何数据。您甚至可以将不同管道的不同顶点格式存储在同一个缓冲区中 - 只是在其中的不同位置并将其与偏移量绑定。如果您的所有顶点都整齐地打包到数组中(它们很可能是),请不要仅仅为了绘制不同的网格而重新绑定。如果您只想绘制缓冲区的一部分 - 只需使用绘制命令即可。
命令缓冲区只是 gpu 的指令块。您不需要每个对象一个。但是,一个不能同时使用和写入,因此在飞行中每帧至少需要一个,一个要写入。管道(描述符集,以及几乎所有你绑定的其他东西)只是你的 gpu 一旦你绑定它就开始使用的一堆状态。在命令缓冲区的开始,状态是未定义的——它不会以任何方式在命令缓冲区之间继承。
所以我一直在试验,我可以通过将场景中的每个模型添加到同一个顶点缓冲区来添加一个新的“对象”,但这对体素游戏来说并不好,因为我不想每次玩家摧毁一个方块时,都必须重新组织整个世界的顶点。
看来我还可以通过为它创建一个新的顶点和索引缓冲区来添加一个新的“对象”,然后简单地将它和所有其他顶点缓冲区同时绑定到命令缓冲区数组,如下所示:
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
// mesh 1
VkBuffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
// mesh 2
VkBuffer vertexBuffers2[] = { vertexBuffer2 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers2, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer2, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffers[i]);
但是这需要我每次都将所有顶点缓冲区绑定到命令缓冲区数组,即使这些网格中只有一个被更新或 created/destroyed。那么我将如何“添加”一个新的“游戏对象”,它的顶点和索引可以更新而不必循环遍历场景中的其他所有内容?还是绑定到已经计算好的顶点和索引缓冲区相对较快,这是标准的?
而且我已经尝试对每个对象使用一个命令缓冲区:
VkSubmitInfo submits[] = { submitInfo, submitInfo2 };
if (vkQueueSubmit(graphicsQueue, 2, submits, inFlightFences[currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!");
}
但它只渲染队列中的最后一个对象(如果我说提交大小为 1,它将渲染第一个对象)。
我也尝试添加一个单独的描述符集、描述符池和管道,但它仍然只呈现队列中的最后一个命令缓冲区。我尝试为每个对象添加一个新的命令池,但是 commandPool
被许多其他函数使用,而且看起来应该只有其中一个。
你将你的世界分割成块,一次绘制一个块。所有块都在(单个)顶点缓冲区中为它们保留了一些 space ,并且当某些内容发生变化时,您只更新那个块。如果一个块变得太大......好吧,你可能需要某种内存分配系统。
不要为每一件小事创建单独的缓冲区。缓冲区只是保存数据。任何数据。您甚至可以将不同管道的不同顶点格式存储在同一个缓冲区中 - 只是在其中的不同位置并将其与偏移量绑定。如果您的所有顶点都整齐地打包到数组中(它们很可能是),请不要仅仅为了绘制不同的网格而重新绑定。如果您只想绘制缓冲区的一部分 - 只需使用绘制命令即可。
命令缓冲区只是 gpu 的指令块。您不需要每个对象一个。但是,一个不能同时使用和写入,因此在飞行中每帧至少需要一个,一个要写入。管道(描述符集,以及几乎所有你绑定的其他东西)只是你的 gpu 一旦你绑定它就开始使用的一堆状态。在命令缓冲区的开始,状态是未定义的——它不会以任何方式在命令缓冲区之间继承。