我正在尝试在HLSL中将YUV写入RGB着色器。具体来说,它转换Yuv420p格式,该格式由Y值的N M平面组成,接着是U值的(N / 2)(M / 2)平面,然后是(N / 2) *(M / 2)V值平面。例如,这张1280x720图片:
在YUV格式中看起来像这样解释为8位,1280x1080纹理:
在Direct3D11中,我将其作为Texture2D加载,格式为R8_UNorm,尺寸为1280x1080。棘手的部分是重建U和V平面,因为正如你所看到的,一半的线位于纹理的左侧,另一半位于右侧。在着色器中,我这样做:
struct PS_IN
{
float4 pos : SV_POSITION;
float2 tex : TEXCOORD;
};
Texture2D picture;
SamplerState pictureSampler;
float4 PS(PS_IN input) : SV_Target
{
int pixelCoord = input.tex.y * 720;
bool evenRow = (pixelCoord / 2) % 2 == 0;
//(...) illustrating U values:
float ux = input.tex.x / 2.0;
float uy = input.tex.y / 6.0 + (4.0 / 6.0);
if (!evenRow)
{
ux += 0.5;
}
float u = picture.Sample(pictureSampler, float2(ux, uy)).r;
u *= 255.0;
// for debug purposes, display just the U values
float4 rgb;
rgb.r = u;//y + (1.402 * (v - 128.0));
rgb.g = u;//y - (0.344 * (u - 128.0)) - (0.714 * (v - 128.0));
rgb.b = u;//y + (1.772 * (u - 128.0));
rgb.a = 255.0;
return rgb / 255.0;
}
然而,由于一些奇怪的原因,这似乎产生了一个奇怪的水平边缘模糊图案:
请注意,如果将条件设置为true或false(以便ux始终或从不增加0.5f),则不会出现模式 - 尽管我们当然得到一半的分辨率。另请注意,我对HLSL代码进行了基本的复制粘贴C#转换,但它不会产生这种效果:
FWIW,我正在使用WPF创建窗口并通过WindowInteropHelper使用其HWND初始化Direct3D。窗口的大小设置为1280x720。