Direct3D

Direct3D是Windows平台上开发硬件加速的程序一个架构,它提供了

  • 图形处理和渲染加速
  • 视频编解码加速
  • 并行计算加速

Direct3D和OpenGL非常相似,很多概念、术语和流程基本上是相通的,在显卡(GPU)内部的加速原理基本上差不多,它不仅是Windows和XBox游戏开发的渲染基本技术架构,我们还能利用显卡(GPU)强大的计算能力,为高清视频、图像和图形编解码,渲染和特效处理提供实时和流畅的处理能力,是Windows平台上视频和图像处理进阶的必备编程技术。
本系列主要介绍如何用D3D处理2D视频和图像,所有演示程序和代码均基于Direct3D11。

Direct3D坐标系

Direct3D提供了这么几种坐标系,这些对于D3D rendering pipeline以及shader的代码阅读和编写来说非常重要,毕竟GPU端的代码的调试和优化相对于CPU端来说是比较麻烦的,对于基本概念的不了解会造成代码编写和运行效率的低下。

Pixel Coordinate System

这个坐标系的原点(0, 0)在Render Target(渲染目标)的左上方,这个坐标系与图像和视频decoded buffer是一致的,大部分图片和主流视频都是用这个坐标系来表示图像像素信息,下面这张图片很好的描述了它:

GPU绘图原理 gpu2d绘图是什么意思_视频编解码


图一


从这张图可以看到,因为D3D是矢量图,所以像素的大小和位置可以是小数,而且它们也是连续的,一个像素方框的左上方是整数坐标系,比如(0, 0), (1, 4)等, 一个像素的中心是左上方整数坐标加上(0.5, 0.5)的偏移量。


可以把它理解成buffer坐标系。

Texel Coordinate System

在2D Quad Render Target里面可以理解填充素材(Texture)坐标,也称作uv坐标,主要用来描述素材中哪部分区域用来填充到Render Target中。左上方的坐标为(0, 0),然后右下方normlized坐标为(1, 1):

GPU绘图原理 gpu2d绘图是什么意思_视频编解码_02


图二 在HLSL shader中一般用TEXCOORD来申明。 可以把它理解重素材填充坐标系

NDC(Normalized Device Coordinates)

中文好像翻译成标准化设备坐标,原点(0, 0)在Render Target的中心,左上角坐标为(-1, 1),右下角为(1, -1)。在D3D中一般用来描述点在渲染区域的坐标,比如顶点(Vertex)的坐标。也可以在图一中看到对应的图示。在D3D中,Shader中的SV_Position语义就用在这个坐标系来描述指定屏幕空间坐标(screen space coordinates)。
可以把它理解成渲染坐标系。

相关代码

有了上面这些基本概念之后,来看一段用HSL写的Vetex Shader的代码:

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float2 Tex : TEXCOORD;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS(uint vI : SV_VERTEXID)
{
	PS_INPUT output = (PS_INPUT)0;
	float2 texcoord = float2(vI & 1, vI >> 1);
	output.Pos = float4((texcoord.x - 0.5f) * 2.0f, -(texcoord.y - 0.5f) * 2.0f, 0.0f, 1.0f);
	output.Tex = texcoord;
	return output;
}

从这段代码可以看出, 这个vertex shader的输出PS_INPUT用来告诉pixel shader的输入坐标信息,包括素材(ShaderResourceView)中哪个区域(Tex: TEXCOORD, Texel Coordinate System)应该填充到哪个渲染区域(Render Target)(Pos: SV_POSITION, NDC),然后Vertex Shader就根据设计的场景来构建素材内容和渲染区域,很多转场动画都是通过调整这个输出来达到要想的一些效果。
再来看一段Pixel Shader的代码:

//--------------------------------------------------------------------------------------
// ScreenPS.hlsl
//--------------------------------------------------------------------------------------
Texture2D txInput : register(t0);

SamplerState GenericSampler : register(s0);

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float2 Tex : TEXCOORD;
};

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS(PS_INPUT input) : SV_Target
{
	return txInput.Sample(GenericSampler, input.Tex);
}

这段代码中Pixel Shader的输入为PS_INPUT input, pos: SV_POSITION为在NDC坐标系要处理的某点的D3D坐标(x, y, z, w),而Tex : TEXCOORD则用来描述填充素材(Texture)上对应某点填充到pos:SV_POSITION对应的这个点。而语句txInput.Sample(GenericSampler, input.Tex)则是根据Texel Coordinate System坐标系统从素材(Texture)上取一点的具体信息,比如颜色信息(Blue, Green, Red和Alpha)值,然后把它渲染到Render Target中。当然在这个最简单的场景中, Pixel Coordinate System和NDC坐标并没有参与到具体运算逻辑来影响输出效果。

结论

通过上面的介绍,应该能对用于2D场景中各个坐标系有个粗略的了解,在后面的文章中会进一步讲解这三个坐标如何用在一些实际场景中。