为什么四边形上的透明像素只能从一个角度正确渲染?
Why are transparent pixels on quads only rendering correctly from one angle?
这是一行 textures/quads,最接近最后创建的相机的图像:
这非常有效!但是,一旦您从 首先创建最接近相机的图像的角度查看纹理 ,透明像素只会拾取背景颜色:
但令人困惑的是,这个角度的像素将正确拾取 "real" 3D 模型,同时完全忽略它们之间的四边形,无论 3D 模型的创建顺序如何:
代码转储
老实说,我不确定这里 post 的代码片段是什么,这个问题是由错误配置的深度模板引起的还是完全由其他原因引起的。如果有任何相关遗漏,请告诉我,我会更新问题。
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(四边形 vertices/indices)
// 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 着色器只是一个基本的模型视图投影矩阵和一个纹理采样器。
知道是什么导致纹理忽略透明像素中的其他纹理四边形吗?
谢谢!
深度测试是绘制透明物体时的常见问题。当您首先绘制最靠近相机的对象时,它会与帧缓冲区中已有的对象混合。如果什么都没有,它会与背景(透明)颜色混合。接下来您渲染一个更远的对象。发生什么了?它未能通过深度测试,因为第一个对象是将数据写入深度缓冲区的四边形。这就是为什么您还可以在第二个对象上看到这个 "quad"(作为背景色)。但是您不能禁用深度测试,因为稍后绘制的对象和较远的对象会遮挡更靠近相机的对象。您要么需要:
- 根据对象与相机的距离对对象进行排序,并且(如果是透明对象)按从后到前的顺序绘制它们,或者
- 在片段着色器中使用 discard() 函数对透明像素执行 "alpha" 测试。
为什么 "normal" 对象以不同的方式呈现?可能是由于不同的深度 test/depth 写入设置和不同的绘制顺序。
这是一行 textures/quads,最接近最后创建的相机的图像:
这非常有效!但是,一旦您从 首先创建最接近相机的图像的角度查看纹理 ,透明像素只会拾取背景颜色:
但令人困惑的是,这个角度的像素将正确拾取 "real" 3D 模型,同时完全忽略它们之间的四边形,无论 3D 模型的创建顺序如何:
代码转储
老实说,我不确定这里 post 的代码片段是什么,这个问题是由错误配置的深度模板引起的还是完全由其他原因引起的。如果有任何相关遗漏,请告诉我,我会更新问题。
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(四边形 vertices/indices)
// 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 着色器只是一个基本的模型视图投影矩阵和一个纹理采样器。
知道是什么导致纹理忽略透明像素中的其他纹理四边形吗?
谢谢!
深度测试是绘制透明物体时的常见问题。当您首先绘制最靠近相机的对象时,它会与帧缓冲区中已有的对象混合。如果什么都没有,它会与背景(透明)颜色混合。接下来您渲染一个更远的对象。发生什么了?它未能通过深度测试,因为第一个对象是将数据写入深度缓冲区的四边形。这就是为什么您还可以在第二个对象上看到这个 "quad"(作为背景色)。但是您不能禁用深度测试,因为稍后绘制的对象和较远的对象会遮挡更靠近相机的对象。您要么需要:
- 根据对象与相机的距离对对象进行排序,并且(如果是透明对象)按从后到前的顺序绘制它们,或者
- 在片段着色器中使用 discard() 函数对透明像素执行 "alpha" 测试。
为什么 "normal" 对象以不同的方式呈现?可能是由于不同的深度 test/depth 写入设置和不同的绘制顺序。