在Vulkan与OpenGL中渲染立方体

时间:2018-04-17 07:24:34

标签: vulkan

我写了一个简单的OpenGL程序,它只是从一个角度渲染一个立方体。它就是你能得到的那么简单:只有顶点缓冲区(没有索引缓冲区),顶点着色器只能将顶点乘以来自统一缓冲区的MVP矩阵,而静态片段着色器只返回红色。最近,我尝试在Vulkan中编写同样的程序,但我遇到了一些问题。

我首先遵循英特尔API无秘密教程来设置一个简单的2d纹理渲染程序,但当我进入3d时,我开始遇到问题。为了调试这个,我简化了程序以匹配我的旧OpenGL程序(删除纹理和我在Vulkan中做的其他一些额外的东西),甚至甚至使用完全相同的顶点和MVP数据。但是,我无法在Vulkan中正确渲染多维数据集。

我知道OpenGL坐标不会直接映射到Vulkan坐标,因为Y坐标被翻转,但是如果有任何东西应该只是翻转图像,我已经尝试在MVP中切换Y值。我觉得这里有一些其他的细节,我在这里缺少坐标,但是我无法弄清楚地搜索并查看有关将OpenGL代码库转换为Vulkan的指南。

我将上传的数据包含在着色器中,以及Vulkan代码库中的一些核心代码。 Vulkan代码在D中,所以它与C ++类似,但有点不同。使用我用于包装Vulkan(erupted)的库,设备级功能被加载到设备分派中(在代码中作为device.dispatch访问),当在没有vk前缀的调度上调用它们时,设备和命令缓冲区(在代码中分配给调度)参数是自动填充的。

顶点数据:

[ [1, 1, 1, 1],
  [1, 1, -1, 1],
  [-1, 1, -1, 1],
  [1, 1, 1, 1],
  [-1, 1, -1, 1],
  [-1, 1, 1, 1],
  [1, 1, 1, 1],
  [1, -1, 1, 1],
  [1, -1, -1, 1],
  [1, 1, 1, 1],
  [1, -1, -1, 1],
  [1, 1, -1, 1],
  [1, 1, -1, 1],
  [1, -1, -1, 1],
  [-1, -1, -1, 1],
  [1, 1, -1, 1],
  [-1, -1, -1, 1],
  [-1, 1, -1, 1],
  [-1, 1, -1, 1],
  [-1, -1, -1, 1],
  [-1, -1, 1, 1],
  [-1, 1, -1, 1],
  [-1, -1, 1, 1],
  [-1, 1, 1, 1],
  [-1, 1, 1, 1],
  [-1, -1, 1, 1],
  [1, -1, 1, 1],
  [-1, 1, 1, 1],
  [1, -1, 1, 1],
  [1, 1, 1, 1],
  [1, -1, 1, 1],
  [1, -1, -1, 1],
  [-1, -1, -1, 1],
  [1, -1, 1, 1],
  [-1, -1, -1, 1],
  [-1, -1, 1, 1] ]

MVP:

[ [-1.0864, -0.993682, -0.687368, -0.685994],
  [0, 2.07017, 0.515526, -0.514496],
  [-1.44853, 0.745262, 0.515526, 0.514496],
  [-8.04095e-16, 0, 5.64243, 5.83095] ]

图形管道设置:

VkPipelineShaderStageCreateInfo[] shader_stage_infos = [
  {
    stage: VK_SHADER_STAGE_VERTEX_BIT,
    _module: vertex_shader,
    pName: "main"
  },
  {
    stage: VK_SHADER_STAGE_FRAGMENT_BIT,
    _module: fragment_shader,
    pName: "main"
  }
];
VkVertexInputBindingDescription[] vertex_binding_descriptions = [
  {
    binding: 0,
    stride: VertexData.sizeof,
    inputRate: VK_VERTEX_INPUT_RATE_VERTEX
  }
];
VkVertexInputAttributeDescription[] vertex_attribute_descriptions = [
  {
    location: 0,
    binding: vertex_binding_descriptions[0].binding,
    format: VK_FORMAT_R32G32B32A32_SFLOAT,
    offset: VertexData.x.offsetof
  },
  {
    location: 1,
    binding: vertex_binding_descriptions[0].binding,
    format: VK_FORMAT_R32G32_SFLOAT,
    offset: VertexData.u.offsetof
  }
];
VkPipelineVertexInputStateCreateInfo vertex_input_state_info = {
  vertexBindingDescriptionCount: vertex_binding_descriptions.length.to!uint,
  pVertexBindingDescriptions: vertex_binding_descriptions.ptr,
  vertexAttributeDescriptionCount: vertex_attribute_descriptions.length.to!uint,
  pVertexAttributeDescriptions: vertex_attribute_descriptions.ptr
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_state_info = {
  topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
  primitiveRestartEnable: VK_FALSE
};
VkPipelineViewportStateCreateInfo viewport_state_info = {
  viewportCount: 1,
  pViewports: null,
  scissorCount: 1,
  pScissors: null
};
VkPipelineRasterizationStateCreateInfo rasterization_state_info = {
  depthBiasClamp: 0.0,
  polygonMode: VK_POLYGON_MODE_FILL,
  cullMode: VK_CULL_MODE_FRONT_AND_BACK,
  frontFace: VK_FRONT_FACE_COUNTER_CLOCKWISE,
  lineWidth: 1
};
VkPipelineMultisampleStateCreateInfo multisample_state_info = {
  rasterizationSamples: VK_SAMPLE_COUNT_1_BIT,
  minSampleShading: 1
};
VkPipelineColorBlendAttachmentState[] color_blend_attachment_states = [
  {
    blendEnable: VK_FALSE,
    srcColorBlendFactor: VK_BLEND_FACTOR_ONE,
    dstColorBlendFactor: VK_BLEND_FACTOR_ZERO,
    colorBlendOp: VK_BLEND_OP_ADD,
    srcAlphaBlendFactor: VK_BLEND_FACTOR_ONE,
    dstAlphaBlendFactor: VK_BLEND_FACTOR_ZERO,
    alphaBlendOp: VK_BLEND_OP_ADD,
    colorWriteMask:
      VK_COLOR_COMPONENT_R_BIT |
      VK_COLOR_COMPONENT_G_BIT |
      VK_COLOR_COMPONENT_B_BIT |
      VK_COLOR_COMPONENT_A_BIT
  }
];
VkPipelineColorBlendStateCreateInfo color_blend_state_info = {
  logicOpEnable: VK_FALSE,
  logicOp: VK_LOGIC_OP_COPY,
  attachmentCount: color_blend_attachment_states.length.to!uint,
  pAttachments: color_blend_attachment_states.ptr,
  blendConstants: [ 0, 0, 0, 0 ]
};
VkDynamicState[] dynamic_states = [
  VK_DYNAMIC_STATE_VIEWPORT,
  VK_DYNAMIC_STATE_SCISSOR
];
VkPipelineDynamicStateCreateInfo dynamic_state_info = {
  dynamicStateCount: dynamic_states.length.to!uint,
  pDynamicStates: dynamic_states.ptr
};
VkGraphicsPipelineCreateInfo pipeline_info = {
  stageCount: shader_stage_infos.length.to!uint,
  pStages: shader_stage_infos.ptr,
  pVertexInputState: &vertex_input_state_info,
  pInputAssemblyState: &input_assembly_state_info,
  pTessellationState: null,
  pViewportState: &viewport_state_info,
  pRasterizationState: &rasterization_state_info,
  pMultisampleState: &multisample_state_info,
  pDepthStencilState: null,
  pColorBlendState: &color_blend_state_info,
  pDynamicState: &dynamic_state_info,
  layout: pipeline_layout,
  renderPass: render_pass,
  subpass: 0,
  basePipelineHandle: VK_NULL_HANDLE,
  basePipelineIndex: -1
};
VkPipeline[1] pipelines;
checkVk(device.dispatch.CreateGraphicsPipelines(VK_NULL_HANDLE, 1, [pipeline_info].ptr, pipelines.ptr));
pipeline = pipelines[0];

图:

if(device.dispatch.WaitForFences(1, [fence].ptr, VK_FALSE, 1000000000) != VK_SUCCESS)
  throw new StringException("timed out waiting for fence");
device.dispatch.ResetFences(1, [fence].ptr);

uint image_index;
switch(device.dispatch.AcquireNextImageKHR(swapchain.swapchain, uint64_t.max, image_available_semaphore, VK_NULL_HANDLE, &image_index)) {
  case VK_SUCCESS:
  case VK_SUBOPTIMAL_KHR:
    break;
  case VK_ERROR_OUT_OF_DATE_KHR:
    on_window_size_changed();
    break;
  default:
    throw new StringException("unhandled vk result on swapchain image acquisition");
}

if(framebuffer != VK_NULL_HANDLE) device.dispatch.DestroyFramebuffer(framebuffer);

VkFramebufferCreateInfo framebuffer_info = {
  renderPass: swapchain.render_pass,
  attachmentCount: 1,
  pAttachments: [swapchain.image_resources[image_index].image_view].ptr,
  width: swapchain.extent.width,
  height: swapchain.extent.height,
  layers: 1
};
checkVk(device.dispatch.CreateFramebuffer(&framebuffer_info, &framebuffer));

VkCommandBufferBeginInfo cmd_begin_info = { flags: VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT };
VkImageSubresourceRange image_subresource_range = {
  aspectMask: VK_IMAGE_ASPECT_COLOR_BIT,
  baseMipLevel: 0,
  levelCount: 1,
  baseArrayLayer: 0,
  layerCount: 1,
};
VkImageMemoryBarrier barrier_from_present_to_draw = {
  srcAccessMask: VK_ACCESS_MEMORY_READ_BIT,
  dstAccessMask: VK_ACCESS_MEMORY_READ_BIT,
  oldLayout: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  newLayout: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  srcQueueFamilyIndex: device.present_queue.family_index,
  dstQueueFamilyIndex: device.graphics_queue.family_index,
  image: swapchain.image_resources[image_index].image,
  subresourceRange: image_subresource_range
};
VkImageMemoryBarrier barrier_from_draw_to_present = {
  srcAccessMask: VK_ACCESS_MEMORY_READ_BIT,
  dstAccessMask: VK_ACCESS_MEMORY_READ_BIT,
  oldLayout: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  newLayout: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  srcQueueFamilyIndex: device.graphics_queue.family_index,
  dstQueueFamilyIndex: device.present_queue.family_index,
  image: swapchain.image_resources[image_index].image,
  subresourceRange: image_subresource_range
};
VkViewport viewport = {
  x: 0,
  y: 0,
  width: swapchain.extent.width,
  height: swapchain.extent.height,
  minDepth: 0,
  maxDepth: 1
};
VkRect2D scissor = {
  offset: {
    x: 0,
    y: 0
  },
  extent: swapchain.extent
};
VkClearValue[] clear_values = [
  { color: { [ 1.0, 0.8, 0.4, 0.0 ] } }
];
VkRenderPassBeginInfo render_pass_begin_info = {
  renderPass: swapchain.render_pass,
  framebuffer: framebuffer,
  renderArea: {
    offset: {
      x: 0,
      y: 0
    },
    extent: swapchain.extent
  },
  clearValueCount: clear_values.length.to!uint,
  pClearValues: clear_values.ptr
};

device.dispatch.commandBuffer = command_buffer;
device.dispatch.BeginCommandBuffer(&cmd_begin_info);
  if(device.graphics_queue.handle != device.present_queue.handle)
    device.dispatch.CmdPipelineBarrier(
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        0, 0, null, 0, null, 1,
        &barrier_from_present_to_draw
    );
  device.dispatch.CmdBeginRenderPass(&render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
    device.dispatch.CmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, swapchain.pipeline);
    device.dispatch.CmdSetViewport(0, 1, &viewport);
    device.dispatch.CmdSetScissor(0, 1, &scissor);
    const(ulong) vertex_buffer_offset = 0;
    device.dispatch.CmdBindVertexBuffers(0, 1, &vertex_buffer, &vertex_buffer_offset);
    device.dispatch.CmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, null);
    device.dispatch.CmdDraw(draw_count, 1, 0, 0);
  device.dispatch.CmdEndRenderPass();
  if(device.graphics_queue.handle != device.present_queue.handle)
    device.dispatch.CmdPipelineBarrier(
        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
        0, 0, null, 0, null, 1,
        &barrier_from_draw_to_present
    );
checkVk(device.dispatch.EndCommandBuffer());
device.dispatch.commandBuffer = VK_NULL_HANDLE;

VkSubmitInfo submit_info = {
  waitSemaphoreCount: 1,
  pWaitSemaphores: [image_available_semaphore].ptr,
  pWaitDstStageMask: castFrom!(VkPipelineStageFlagBits*).to!(const(uint)*)([VK_PIPELINE_STAGE_TRANSFER_BIT].ptr),
  commandBufferCount: 1,
  pCommandBuffers: [command_buffer].ptr,
  signalSemaphoreCount: 1,
  pSignalSemaphores: [rendering_finished_semaphore].ptr
};
checkVk(device.dispatch.vkQueueSubmit(device.graphics_queue.handle, 1, [submit_info].ptr, fence));

VkPresentInfoKHR present_info = {
  waitSemaphoreCount: 1,
  pWaitSemaphores: [rendering_finished_semaphore].ptr,
  swapchainCount: 1,
  pSwapchains: [swapchain.swapchain].ptr,
  pImageIndices: [image_index].ptr
};
switch(device.dispatch.vkQueuePresentKHR(device.present_queue.handle, &present_info)) {
  case VK_SUCCESS:
    break;

  case VK_ERROR_OUT_OF_DATE_KHR:
  case VK_SUBOPTIMAL_KHR:
    on_window_size_changed();
    break;

  default:
    throw new StringException("unhandled vk result on presentation");
}

(我无法嵌入图片,因为我的代表太低了,抱歉)

节目输出:

OpenGL按预期绘制多维数据集 OpenGL Output

除了清晰的颜色外,Vulkan不会渲染任何东西。

UPDATE:

通过将剔除模式更改为VK_CULL_MODE_NONE来修复剔除模式后,这是我得到的结果: Output after cull mode fix

2 个答案:

答案 0 :(得分:0)

VK_CULL_MODE_FRONT_AND_BACK

我认为这是你的问题:)

答案 1 :(得分:0)

在剔除模式修复后,您的顶点数据布局中似乎存在问题。 Vulkan期望(相应于您的布局绑定)类似

struct Vertex {
    vec4 x;
    vec2 u;
};

Vertex VertexData[] = {...};

因为您在VK_VERTEX_INPUT_RATE_VERTEX字段中设置了vertex_binding_descriptions.inputRate

似乎在你的情况下你应该设置VK_VERTEX_INPUT_RATE_INSTANCE而不是互相使用缓冲区。

修复:看过你的新评论,看起来我误解了你的顶点布局,所以它没有帮助。