在学习 http://xiaopengyou.fun/public/2019/09/20/20_Material/ 的时候遇到的一些问题
初始化
初始化的时候 VkWriteDescriptorSet 把 ring buffer 绑定到 descriptor set
在每帧的最后,提交完 uniform buffer 的数据之后,vkCmdBindDescriptorSets 把 descriptor set 绑定到 command buffer
dynamicOffsetCount
其实他一开始是用 dynamicOffsetCount
来暂存计数值,他只是一个过程量,为了根据 set 和 binding 的顺序来设置 uniform buffer 的 offset 的索引的顺序
比如现在一个 shader 有四个 uniform buffer,那么
set = 0 binding = 0
set = 1 binding = 1
set = 0 binding = 1
set = 0 binding = 2
那么对应的 offset 的 index 为 0 3 1 2
但是之后他就拿 dynamicOffsetCount
当作 uniform buffer 的数量了
如果从一个独立的函数来看,突兀的出现这么一个量就让人困惑
其实最合适的就是在其他地方把他替换成 uniformBuffers.size()
有一个令我疑惑的问题
他有一个 vk_demo::DVKMaterial::BuffersMap vk_demo::DVKMaterial::uniformBuffers
SetLocalUniform 与 SetGlobalUniform
然后有三个函数 SetLocalUniform
SetGlobalUniform
SetStorageBuffer
都要从这个 map 中找对应的 buffer
SetLocalUniform
拿到数据指针之后,直接把数据存到 ring buffer,并且把存储到 ring buffer 的首地址存在 dynOffsets
中
SetGlobalUniform
拿到数据指针之后,却会把数据存在 uniformBuffers
这个 map 的 buffer 中
然后在 BeginFrame()
中,再把 SetGlobalUniform
在 uniformBuffers
中存储的数据拿出来,存到 ring buffer
为什么是在 BeginFrame()
中拷贝 global uniform?为什么 global 暂存而非 global 的不暂存?
一开始我还觉得是不是多此一举,后来才明白不是
因为其实你每帧都在往 ring buffer 中写数据,而 global 的数据,不是在渲染主循环中提供的,而是只在初始化的时候提供一次
所以你需要暂存 global uniform buffer 的数据,而不用存 local 的
具体的可以看 BeginObject()
void DVKMaterial::BeginObject()
{
int32 index = (int32)perObjectIndexes.size();
perObjectIndexes.push_back(index);
int32 offsetStart = index * dynamicOffsetCount;
// 扩充dynamicOffsets尺寸以便能够保持每个Object的参数
if (offsetStart + dynamicOffsetCount > dynamicOffsets.size())
{
// 因为每一次都是当前长度 + dynamicOffsetCount 来判断
// 所以每一次增长的长度也是 dynamicOffsetCount
// 就是实现了每次增加元素都是增加 dynamicOffsetCount 个元素
for (uint32 i = 0; i < dynamicOffsetCount; ++i)
{
dynamicOffsets.push_back(0);
}
}
// 拷贝GlobalOffsets
// 但是 offsetIndex < dynamicOffsetCount 这里的终点是 dynamicOffsetCount
// 那么其实只有 index = 0 的情况下这里才会被执行
// 那么其实这里相当于 dynamicOffsets[0...dynamicOffsetCount-1] = globalOffsets[0...dynamicOffsetCount-1]
// 应该改为 offsetIndex < offsetStart + dynamicOffsetCount?
// 这个 globalOffsets 是只有一个 dynamicOffsetCount 的长度,因为全局的 uniform buffer 只需要一份数据,所以只需要一份 offset
// 在不存储更多信息的情况下,你不知道全局的 uniform buffer 是否存在,即使它存在,你也不知道全局的 uniform buffer 的 offset 的 index 是什么
// 因此这里直接把整个 globalOffsets 拷贝到这一个物体所对应的整个 offset 区间中
// 假设当前使用的 shader 没有全局的 uniform buffer,那么 dynamicOffsets 这一段区间最终也会赋为被非全局的 uniform buffer 的 offset
// 假设当前使用的 shader 有全局的 uniform buffer,那么 dynamicOffsets 这一段区间上,某一个位置会是全局的 uniform buffer 的 offset,
// 剩下的位置会被非全局的 uniform buffer 的 offset 填充
for (uint32 offsetIndex = offsetStart; offsetIndex < offsetStart + dynamicOffsetCount; ++offsetIndex)
{
dynamicOffsets[offsetIndex] = globalOffsets[offsetIndex - offsetStart];
}
}
最终做出来的 dynamicOffsets 会被提供给 vkCmdBindDescriptorSets
vkCmdBindDescriptorSets 是逐物体的,因为绘制命令是逐物体的
perObjectIndexes
这里用一个 perObjectIndexes
来存储这一帧的物体的数量
看上去不必要用 vector,直接用一个 int 就好了
类似他有一个 int32 offsetStart = objIndex * dynamicOffsetCount;
就很精炼
提取出了第 i 个物体的