我正在修改一个由同事编写的粒子系统,通过计算管道中的手动混合/设置像素进行渲染(!)以使用 2D 图形进行绘制。我发现透明度存在一些奇怪的问题。
我已经检查了大多数可能的错误来源 - 我确实启用了混合并且操作看起来合法:
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;
我确实看到了输出的透明度。高于一定的 alpha 级别(大约 0.2),图像可以正确渲染。 低于该值,粒子呈现为纯白色。
粒子纹理在 GIMP 中看起来不错。如果我调整片段着色器以显示 alpha 值,它也看起来像我期望的那样:
顶点和片段着色器很简单:
#version 450
layout(binding = 0) uniform UniformBufferObject {
mat4 proj;
} ubo;
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec2 inTexCoord;
layout(location = 2) in vec4 inColor;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragTexCoord;
void main()
{
gl_Position = ubo.proj * vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
fragTexCoord = inTexCoord;
}
//----------------------------------------
#version 450
layout(binding = 1) uniform sampler2D texSampler;
layout(location = 0) in vec4 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
void main()
{
outColor = texture(texSampler, fragTexCoord);
}
渲染代码本身:
CommandBufferBeginInfo const beginInfo{};
VK_CHECK_RESULT(vkBeginCommandBuffer(vkCommandBuffer_, &beginInfo));
RenderPassBeginInfo renderPassInfo{};
renderPassInfo.renderPass = *renderPass_;
renderPassInfo.framebuffer = framebuffer_->getVulkanFramebuffer();
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent.width = uint32_t(windowSize_.x);
renderPassInfo.renderArea.extent.height = uint32_t(windowSize_.y);
constexpr VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;
vkCmdBeginRenderPass(vkCommandBuffer_, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(vkCommandBuffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_);
const VkBuffer vertexBuffers[] = { backgroundVertexBuffer_->getVulkanBuffer(), particleVertexBuffer_->getVulkanBuffer() };
const VkDescriptorSet descriptorSets[] = { *backgroundDescriptorSet_, *particleDescriptorSet_ };
constexpr VkDeviceSize offsets[] = { 0 };
vkCmdBindIndexBuffer(vkCommandBuffer_, indexBuffer_->getVulkanBuffer(), 0, VK_INDEX_TYPE_UINT16);
// Draw Background
vkCmdBindVertexBuffers(vkCommandBuffer_, 0, 1, &vertexBuffers[0], offsets);
vkCmdBindDescriptorSets(vkCommandBuffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout_, 0, 1,
&descriptorSets[0], 0, nullptr);
vkCmdDrawIndexed(vkCommandBuffer_, uint32_t(std::size(Quad::indices)), 1, 0, 0, 0);
// Draw particles.
vkCmdBindVertexBuffers(vkCommandBuffer_, 0, 1, &vertexBuffers[1], offsets);
vkCmdBindDescriptorSets(vkCommandBuffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout_, 0, 1,
&descriptorSets[1], 0, nullptr);
for (auto i = 0u; i < effect_->getParticleCount(); ++i)
{
vkCmdDrawIndexed(vkCommandBuffer_, uint32_t(std::size(Quad::indices)), 1, 0, int32_t(i) * 4, 0);
}
vkCmdEndRenderPass(vkCommandBuffer_);
VK_CHECK_RESULT(vkEndCommandBuffer(vkCommandBuffer_));
不确定还可能是什么?我没有深度缓冲区,所以没有深度子通道。会是这样吗?并没有真正解释我所看到的。有什么建议吗?
好吧,这是 Alpha 混合设置的问题,它需要与颜色通道相同的设置才能正常工作。对于带宽被盗表示歉意。
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;