gpt4 book ai didi

c++ - 使用几何着色器进行图层渲染似乎只输出图像数组的第一层

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:38:10 26 4
gpt4 key购买 nike

我正在尝试对图像阵列进行一些分层渲染,并在屏幕上显示其中一层。但无论我做什么,只有第一层被正确渲染和显示,每次我尝试显示第一层以外的另一层时,我除了黑屏什么也得不到。所以我尝试打包大部分必要的信息,希望有人能发现我的错误。

首先,我用这些参数创建了一个图像:

VkImageCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = VK_IMAGE_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.extent = { WindowWidth, WindowHeight, 1 };
info.mipLevels = 1;
info.arrayLayers = 6;
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

VkImage myImage = createImage(info);

我省略了整个内存分配和绑定(bind)体操,因为我认为它在这里不相关。

然后,我使用了两个 ImageView :- 具有整个 {0, 6} 层范围的一个,将用于几何着色器中的层渲染- 另一个只有一层,将用于在我选择的给定层获取数据

这是我创建它们的方式:

VkImageViewCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = myImage;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.components = Identity;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 6;

VkImageView imageView6Layers = createImageView(info);

VkImageViewCreateInfo info2 = info;
info2.subresourceRange.baseArrayLayer = 1; // Target the layer 1 for example
info2.subresourceRange.layerCount = 1;

VkImageView imageView1Layer = createImageView(info2);

至此,我已经构建了两个渲染 channel 来划分流程:

  • 首先使用第一个 ImageView ,使用几何着色器在一次绘制调用中渲染所有图像层

  • 第二个从第二个 ImageView 中获取数据,并将它们输出到交换链图像

这是第一个渲染 channel (用于分层渲染):

// 6 layers image view
VkAttachmentDescription attachment{};
attachment.format = VK_FORMAT_R8G8B8A8_UNORM;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;

VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;

VkRenderPass renderPass6Layers = createRenderPass(info);

这是第二个渲染过程(获取数据,并将其输出到交换链图像):

VkAttachmentDescription attachments[2]{};

// Swapchain image
attachments[0].format = swpachainImageFormat;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

// 1 layer image view
attachments[1].format = VK_FORMAT_R8G8B8A8_UNORM;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkAttachmentReference inputAttachment{};
inputAttachment.attachment = 1;
inputAttachment.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = &inputAttachment;

VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.subpassCount = 1;
info.pSubpasses = &subpass;

VkRenderPass renderPass1Layer = createRenderPass(info);

然后是第一个子 channel 中使用的着色器:

顶点着色器:

#version 450

layout (location = 0) in vec3 iModelPos;

void main()
{
gl_Position = vec4(iModelPos, 1);
}

几何着色器:

#version 450

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

void main()
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < gl_in.length(); j++)
{
gl_Layer = i;

// Assume I have everything necessary to compute the matrix
gl_Position = PVM * gl_in[j].gl_Position;

EmitVertex();
}

EndPrimitive();
}
}

片段着色器:

#version 450

layout (location = 0) out vec4 oColor;

void main()
{
oColor = vec4(1,1,1,1);
}

第二个子 channel 中使用的着色器:

顶点着色器(简单地在整个屏幕上输出一个四边形):

#version 450

layout (location = 0) in vec3 iModelPos;

void main()
{
gl_Position = vec4(iModelPos, 1);
}

片段着色器(在图像层中获取数据):

#version 450

// Assume it's bound here
layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput ImageLayer;

layout (location = 0) out vec4 oColor;

void main()
{
oColor = subpassLoad(ImageLayer);
}

最后是我的 main 的样子:

int main(void)
{
/* ... */

{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

vkBeginCommandBuffer(cmdBuffer, &info);
}

VkFramebuffer framebuffer6Layers{}
{
VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass6Layers;
info.attachmentCount = 1;
info.pAttachments = &imageView6Layers;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 6;

framebuffer6Layers = createFramebuffer(info);
}

{
VkClearValue clearValues = {0,0,0,1};

VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass6Layers;
info.framebuffer = framebuffer6Layers;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;

vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}

/* binds */

vkCmdDraw(cmdBuffer, objectVertices.count(), 1, 0, 0);

vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);

/* submit cmdBuffer and wait for rendering to finish */

{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

vkBeginCommandBuffer(cmdBuffer, &info);
}

{
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = myImage;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 6;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;

vkCmdPipelineBarrier(cmdBuffer,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
}

VkFramebuffer framebuffer1Layer{};
{
VkImageView attachments[2]{};
attachments[0] = swapchainImageView;
attachments[1] = imageView1Layer;

VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass1Layer;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 1;

framebuffer1Layer = createFramebuffer(info);
}

{
VkClearValue clearValues = {0,0,0,1};

VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass1Layer;
info.framebuffer = framebuffer1Layer;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;

vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}

/* binds */

vkCmdDraw(quadVertices.count(), 1, 0, 0);

vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);

/* submit cmdBuffer, wait for rendering to finish and present the swapchain image */

/* ... */
}

我没有包括一些信息,比如帧缓冲区的创建。感觉自己已经给出了很多信息,希望有人能指点一下哪里不对,或者给点提示。

编辑 1:

验证层正在运行,不会输出任何内容。

编辑 2:

我发现出于某些原因,我实际上总是只创建一个层的帧缓冲区,这解释了为什么验证层从不提示。

为了在帧缓冲区中使用正确的层数,我将过程分为两个渲染过程,并在两者之间添加了一个图像屏障(参见上面编辑的过程)。然而,这并没有解决问题,当我尝试显示另一个图像层而不是第一个图像层时,我仍然有黑屏,而在显示第一个层时,结果是正确的。

验证层现在也没有提示,我按要求添加了帧缓冲区创建细节。

编辑 3:

我尝试使用组合图像采样器统一代替输入附件,但没有成功。当我尝试显示第一层时它仍然有效,但我从其他层得到相同的黑屏。

我从第二个渲染过程中删除了附件并因此更新了内存屏障。

这是第二个渲染 channel 的更新:

// Swapchain image
VkAttachmentDescription attachment{};
attachment.format = swpachainImageFormat;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;

VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;

VkRenderPass renderPass1Layer = createRenderPass(info);

这是新的片段着色器:

// Assume it's bound here
layout (set = 0, binding = 0) uniform sampler2D ImageLayer;

layout (location = 0) out vec4 oColor;

void main()
{
// Assume that I have the viewport from an uniform buffer.
const vec2 uv = gl_FragCoord.xy / Viewport;
oColor = texture(ImageLayer, uv);
}

uv 值是正确的,当我尝试输出 vec4(uv, 0, 1) 时,我在屏幕上得到了预期的颜色,对于我尝试显示的每个图像层:

黑色,红色,

绿色、黄色

这是图像屏障的变化:

barrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;

还有一些更改,例如图像使用标志或描述符集布局,但我没有在此处包含它们。

最佳答案

我终于弄清楚出了什么问题。

layout (triangle_strip, max_vertices = 3) out;

我的几何着色器中的这条线导致了第三个顶点之后的其他顶点默默地丢弃。因此,我的着色器能够写入的唯一层是第一个层。

我已经解决了这样的问题:

布局(triangle_strip, max_vertices = 18);

我想在 6 层上绘制一个三角形(3 个顶点),因此 max_vertices = 3 x 6 = 18。

另一个问题在我的编辑 3 中解决了。我的帧缓冲区只创建了一层而不是所需的 6 层,这使得几何着色器静默专门写入第一层。似乎当您尝试在大于您在帧缓冲区中提供的层数的层上写入时,着色器会自动在层 0 上写入。

关于c++ - 使用几何着色器进行图层渲染似乎只输出图像数组的第一层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57651415/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com