为什么四边形上的透明像素只能从一个角度正确渲染?

时间:2018-10-19 11:35:30

标签: vulkan

这是一排纹理/四边形,其中最近创建的与相机最近的图像

Screenshot 1

这很好用!但是,只要您从首先创建与相机最接近的图像的角度查看纹理,透明像素就只会拾取背景色:

Screenshot 2

尽管如此,令人困惑的是,从这个角度来看,像素将正确地拾取“真实” 3D模型,而完全忽略它们之间的四边形,而与3D模型的创建顺序无关:

Screenshot 3

代码转储

说实话,我不确定此问题是由错误配置的深度模板还是完全由其他原因引起的。如果有任何相关的遗漏,请告诉我,我将更新问题。

createDepthStencil()

// Get Depth Format
std::array<VkFormat, 5> depthFormats = {
    VK_FORMAT_D32_SFLOAT_S8_UINT,
    VK_FORMAT_D32_SFLOAT,
    VK_FORMAT_D24_UNORM_S8_UINT,
    VK_FORMAT_D16_UNORM_S8_UINT,
    VK_FORMAT_D16_UNORM
};

for (auto& format : depthFormats)
{
    VkFormatProperties formatProps;
    vkGetPhysicalDeviceFormatProperties(vulkanDevice.physicalDevice, format, &formatProps);
    // Format must support depth stencil attachment for optimal tiling
    if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
    {
        depthFormat = format;
        break;
    }
}

// Assert that we have a depth format to use
assert(depthFormat != VK_FORMAT_UNDEFINED);

VkImageCreateInfo depthImageInfo = {};
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
depthImageInfo.pNext = nullptr;
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
depthImageInfo.format = depthFormat;
depthImageInfo.extent = { vulkanSwapChain.extent.width, vulkanSwapChain.extent.height, 1 };
depthImageInfo.mipLevels = 1;
depthImageInfo.arrayLayers = 1;
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
depthImageInfo.flags = 0;

VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;

// Create Depth Stencil Image
if (vmaCreateImage(vulkanMemory, &depthImageInfo, &depthImageAllocCreateInfo, &depthImage, &depthImageAllocation, &depthImageAllocationInfo) != VK_SUCCESS) {
    throw std::runtime_error("Failed to create Depth Stencil Image!");
}

VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.pNext = nullptr;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.image = depthImage;
depthStencilView.format = depthFormat;
depthStencilView.flags = 0;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;

// Create Depth Stencil Image View
if (vkCreateImageView(vulkanDevice.logicalDevice, &depthStencilView, nullptr, &depthImageView) != VK_SUCCESS) {
    throw std::runtime_error("Failed to create Depth Stencil Image View!");
}

createRenderPasses()

std::array<VkAttachmentDescription, 2> attachments = {};

...

// Depth attachment
attachments[1].format = depthFormat;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
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_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

VkAttachmentReference depthAttachmentRef = {};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

VkSubpassDescription subpass = {};
subpass.pDepthStencilAttachment = &depthAttachmentRef;

renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();

createGraphicsPipelines()

VkPipelineRasterizationStateCreateInfo rasterizer = {};
    rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    rasterizer.depthClampEnable = VK_FALSE;
    rasterizer.rasterizerDiscardEnable = VK_FALSE;
    rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
    rasterizer.lineWidth = 1.0f;
    rasterizer.cullMode = VK_CULL_MODE_NONE;
    rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
    rasterizer.depthBiasEnable = VK_TRUE; // VK_DYNAMIC_STATE_DEPTH_BIAS is set
    rasterizer.flags = 0;

VkPipelineDepthStencilStateCreateInfo depthStencil = {};
    depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
    depthStencil.depthTestEnable = VK_TRUE;
    depthStencil.depthWriteEnable = VK_TRUE;
    depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
    depthStencil.depthBoundsTestEnable = VK_FALSE;
    depthStencil.minDepthBounds = 0.0f;
    depthStencil.maxDepthBounds = 1.0f;
    depthStencil.stencilTestEnable = VK_FALSE;
    depthStencil.front = {};
    depthStencil.back = {};


    VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
    colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    colorBlendAttachment.blendEnable = VK_TRUE;
    colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
    colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
    colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
    colorBlendAttachment.srcAlphaBlendFactor =  VK_BLEND_FACTOR_ONE;
    colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
    colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;

    VkPipelineColorBlendStateCreateInfo colorBlending = {};
    colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlending.logicOpEnable = VK_FALSE;
    colorBlending.logicOp = VK_LOGIC_OP_COPY;
    colorBlending.attachmentCount = 1;
    colorBlending.pAttachments = &colorBlendAttachment;
    colorBlending.blendConstants[0] = 0.0f;
    colorBlending.blendConstants[1] = 0.0f;
    colorBlending.blendConstants[2] = 0.0f;
    colorBlending.blendConstants[3] = 0.0f;

createFrameBuffers()

std::array<VkImageView, 2> attachments;
attachments[1] = depthImageView;
...
frameBufferInfo.pAttachments = attachments.data();

drawFrame()

std::array<VkClearValue, 2> clearValues;
clearValues[0].color = {0.25f, 0.25f, 0.5f, 1.0f}; // Purple
clearValues[1].depthStencil = { 1.0f, 0 };

renderPassBeginInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassBeginInfo.pClearValues = clearValues.data(); 

Texture.cpp(四边形顶点/索引)

// Position              // Color RGBA               // UV Map
{{  1.0f,  1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f }},
{{ -1.0f,  1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, { 0.0f, 1.0f }},
{{ -1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f }},
{{  1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, 0.0f }}

std::vector<uint32_t> indices = {
        0, 1, 2, 2, 3, 0
    };

一些注意事项:纹理是GLI以VK_FORMAT_R8G8B8A8_UNORM格式加载的.ktx,而GLSL着色器只是基本的模型视图投影矩阵和纹理采样器。

您知道是什么导致纹理忽略透明像素中的其他纹理四边形吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

深度测试是绘制透明对象时的常见问题。当您首先绘制最接近相机的对象时,它会与帧缓冲区中已有的对象融合。如果没有任何内容,它将与背景(透明)颜色混合。下一步渲染距离较远的对象。怎么了?由于第一个对象是将数据写入深度缓冲区的四边形,因此它未能通过深度测试。这就是为什么您还可以在第二个对象上看到此“四边形”(作为背景色)的原因。但是您不能禁用深度测试,因为稍后绘制的物体和距离较远的物体会遮挡更靠近相机的物体。您要么需要:

  1. 按照物体与相机的距离对其排序,并(如果是透明物体)以从后到前的顺序绘制它们,或者
  2. 在片段着色器内部使用一个replace()函数对透明像素执行“ alpha”测试。

为什么“正常”对象以不同的方式呈现?可能是由于深度测试/深度写入设置不同以及绘制顺序不同所致。

相关问题