Почему прозрачные пиксели на четырехугольниках правильно отображаются только под одним углом? - PullRequest
0 голосов
/ 19 октября 2018

Вот ряд текстур / квадов, с ближайшим к камере созданным последним изображением :

Снимок экрана 1

Это работаетв совершенстве!Однако, как только вы просматриваете текстуры под углом, в котором самое близкое к камере изображение создается первым , прозрачные пиксели выбирают только фоновый цвет:

Снимок экрана 2

Что сбивает с толку, так это то, что пиксели под этим углом будут правильно подбирать «реальные» 3D-модели, полностью игнорируя четырехугольники между ними, независимо от того, в каком порядке была создана 3D-модель:

Снимок экрана 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
    };

Пара замечаний: текстура загружена .ktxGLI в формате VK_FORMAT_R8G8B8A8_UNORM, а шейдеры GLSL - это просто матрица проекции вида модели и сэмплер текстуры.

Есть идеи, что заставляет текстуры игнорировать другие текстурированные квадраты в прозрачных пикселях?

Спасибо!

1 Ответ

0 голосов
/ 19 октября 2018

Проверка глубины является распространенной проблемой при рисовании прозрачных объектов.Когда вы сначала рисуете объект, ближайший к камере, он смешивается с тем, что уже есть в кадровом буфере.Если ничего нет, он смешивается с фоновым (прозрачным) цветом.Далее Вы визуализируете объект, который находится дальше.Что просходит?Он не проходит тест глубины, потому что первый объект был квадратором, который записывал данные в буфер глубины.И именно поэтому Вы можете также видеть этот "квад" на втором объекте (как цвет фона).Но Вы не можете отключить тест глубины, потому что объекты, которые нарисованы позже и находятся дальше, будут скрывать объекты ближе к камере.Вам нужно либо:

  1. отсортировать объекты по их расстоянию от камеры и (в случае прозрачных объектов) нарисовать их в обратном порядке, либо
  2. использовать сброс () функция внутри фрагментного шейдера для прозрачных пикселей для выполнения «альфа-теста».

Почему «нормальные» объекты отображаются другим способом?Вероятно, из-за другой настройки глубины теста / записи глубины и другого порядка прорисовки.

...