体素世界无缝纹理问题求助:基于Vulkan的Minecraft复刻项目
我正在开发一款Minecraft复刻项目,已实现基于噪声高度图的简易无限世界生成,但目前遇到纹理问题:纹理存在明显边框,无法实现无缝拼接。项目采用精灵表将单张纹理传入GPU,通过不同纹理坐标区分不同方块类型,渲染后端使用Vulkan,相关纹理配置代码如下:
VkSamplerCreateInfo sInfo{}; sInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sInfo.pNext = nullptr; sInfo.magFilter = VK_FILTER_NEAREST; sInfo.minFilter = VK_FILTER_LINEAR; sInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; sInfo.anisotropyEnable = VK_TRUE; VkPhysicalDeviceProperties Props; vkGetPhysicalDeviceProperties(Engine::Get().GetGpuHandle(), &Props); sInfo.maxAnisotropy = Props.limits.maxSamplerAnisotropy; sInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; sInfo.unnormalizedCoordinates = VK_FALSE; sInfo.compareEnable = VK_FALSE; sInfo.compareOp = VK_COMPARE_OP_ALWAYS; sInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sInfo.mipLodBias = 0.f; sInfo.minLod = 0.f; sInfo.maxLod = 1; VkImageCreateInfo iInfo{}; iInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; iInfo.pNext = nullptr; iInfo.arrayLayers = 1; iInfo.extent = { extent.width,extent.height,1 }; iInfo.imageType = VK_IMAGE_TYPE_2D; iInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; iInfo.mipLevels = 1; iInfo.samples = samples; iInfo.flags = 0; iInfo.tiling = VK_IMAGE_TILING_OPTIMAL; Info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; iInfo.format = format; iInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkImageViewCreateInfo vInfo{}; vInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vInfo.pNext = nullptr; vInfo.image = m_Image; vInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; vInfo.format = format; vInfo.flags = 0; vInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; vInfo.subresourceRange.baseMipLevel = 0; vInfo.subresourceRange.levelCount = 1; vInfo.subresourceRange.baseArrayLayer = 0; vInfo.subresourceRange.layerCount = 1;
起初认为是精灵表的问题,更换多张精灵表后问题依旧;尝试调整多种采样器参数组合也未解决。以下是可行的排查和解决思路:
修复纹理创建的参数错误:代码中
Info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;存在明显错误——VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL是纹理布局枚举,不是usage枚举。正确的写法应为iInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;,纹理布局需要通过vkCmdPipelineBarrier在后续步骤中转换,错误的usage配置会导致纹理采样行为异常,这很可能是核心问题。修正纹理坐标的边缘偏移:使用精灵表时,若纹理坐标刚好落在块边缘,线性过滤会采样到相邻纹理块的像素。给每个纹理块的UV坐标添加微小偏移,比如每个方块为
N×N像素,那么坐标范围应改为从(x*N + 0.5)/总纹理宽度到((x+1)*N - 0.5)/总纹理宽度(V方向同理),避免采样到边缘外的像素。调整采样器与mipmap的匹配设置:当前采样器设置了
mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,但纹理的mipLevels = 1(无多级渐远纹理),这种不匹配可能导致采样异常。可以将mipmapMode改为VK_SAMPLER_MIPMAP_MODE_NEAREST,同时将maxLod设为0.f,确保采样器只使用基础层级纹理。给精灵表添加边缘padding:在制作精灵表时,给每个纹理块周围添加1像素的重复边缘(复制纹理块的边缘像素到padding区域),这样即使GPU采样到边缘,插值的也是相同像素,不会出现跨块的边框。
统一过滤模式测试:当前采样器混合使用了
NEAREST和LINEAR过滤,可尝试暂时统一为VK_FILTER_NEAREST,观察边框是否消失,以此判断是否是线性过滤的边缘插值导致的问题。
内容的提问来源于stack exchange,提问作者Ishan Chaudhari

