DirectX渲染视频帧降采样模糊:高质量HLSL Shader优化咨询
DirectX视频降采样画面模糊的Shader优化方案
你的核心问题在于当前Shader仅用单采样操作完成YUV到RGB转换,降采样时未对输入像素做多样本加权融合,导致画面细节丢失、模糊。以下是针对性优化方案:
1. 替换高质量采样器配置
默认采样器的过滤逻辑无法满足降采样的细节保留需求,先定义适配降采样的采样器:
SamplerState downsampleSampler : register(s0) { Filter = MIN_MAG_MIP_LINEAR; // 线性过滤基础,配合自定义滤镜叠加 AddressU = Clamp; AddressV = Clamp; MipLODBias = 0.0f; };
2. 实现Lanczos降采样滤镜(重点优化亮度通道)
亮度通道(Y)是画面细节核心,使用Lanczos滤镜可在降采样时有效保留边缘细节,避免模糊。添加Lanczos核函数,并在像素着色器中实现多样本加权采样:
添加Lanczos核函数
// Lanczos核函数,a=3时兼顾细节保留与性能 float Lanczos(float x, float a) { x = abs(x); if (x < 1e-6) return 1.0f; if (x > a) return 0.0f; float piX = 3.1415926535f * x; return (sin(piX) / piX) * (sin(piX / a) / (piX / a)); }
修改像素着色器的采样逻辑
假设降采样比例为scale(例如从1920x1080到960x540时scale=0.5),手动计算采样区域并加权:
float4 PS(PS_INPUT input) : SV_TARGET { float2 texelSizeY = 1.0f / luminanceChannel.GetDimensions(); float2 texelSizeUV = 1.0f / chrominanceChannel.GetDimensions(); float scale = 0.5f; // 根据实际降采样比例调整,可改为常量或传入参数 // 亮度通道Lanczos降采样 float ySum = 0.0f; float weightSum = 0.0f; const int kernelSize = 3; // Lanczos核大小,a=3对应±3个像素 for (int x = -kernelSize; x <= kernelSize; x++) { for (int y = -kernelSize; y <= kernelSize; y++) { float2 offset = float2(x, y) * texelSizeY; float2 sampleUV = input.inTexCoord + offset * scale; float weight = Lanczos(x / (float)kernelSize, 3.0f) * Lanczos(y / (float)kernelSize, 3.0f); ySum += luminanceChannel.Sample(downsampleSampler, sampleUV).r * weight; weightSum += weight; } } float y = ySum / weightSum; // 色度通道双线性采样(UV通道分辨率低,无需过度复杂) float2 uv = chrominanceChannel.Sample(downsampleSampler, input.inTexCoord).rg; return float4(ConvertYUVtoRGB(float3(y, uv)), 1.f); }
3. 优化纹理坐标对齐
降采样时,输出像素的纹理坐标需对应输入纹理的像素中心,避免偏移导致的模糊。可在像素着色器开头添加坐标修正:
// 修正坐标到输入像素中心 float2 correctedUV = input.inTexCoord; correctedUV -= 0.5f * texelSizeY * scale;
4. 性能优化建议
- 若Lanczos滤镜性能开销过大,可替换为双三次滤镜(计算量更低,细节保留优于双线性)
- 降采样比例较大时,采用分阶段降采样(先降为中间分辨率,再降为目标分辨率),平衡性能与画质
- 将
scale改为常量缓冲区传入参数,适配不同降采样需求
内容的提问来源于stack exchange,提问作者Hoka Biu
相关产品推荐
相关产品推荐

