D3D处理2D图像:2D Quad坐标系介绍(2)

常见的一段代码

在以前的实现中,我们需要自己组织Vertex,对于2D Quad场景来说,一般组织这样的一组数据:

	const ScreenVertex svDefault[4] = {
		//   x      y     z     w         u     v
		{ { -1.0f,  1.0f, 0.5f, 1.0f },{ 0.0f, 0.0f } }, // 0
		{ { 1.0f,  1.0f, 0.5f, 1.0f },{ 1.0f, 0.0f } }, // 1
		{ { -1.0f, -1.0f, 0.5f, 1.0f },{ 0.0f, 1.0f } }, // 2
		{ { 1.0f, -1.0f, 0.5f, 1.0f },{ 1.0f, 1.0f } }  // 3
	};
		// Vertex Buffer Layout
	D3D11_BUFFER_DESC vbdesc;
	ZeroMemory(&vbdesc, sizeof(vbdesc));
	vbdesc.Usage = D3D11_USAGE_DYNAMIC;
	vbdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vbdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	vbdesc.MiscFlags = 0;
	vbdesc.ByteWidth = sizeof(svDefault);

	D3D11_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = svDefault;
	InitData.SysMemPitch = 0;
	InitData.SysMemSlicePitch = 0;

	CHECK_HR(hr = m_pD3D11Device->CreateBuffer(&vbdesc, &InitData, &m_pDefaultVertex));

现在比较流行的写法是省略掉这部分代码,通过系统的顶点ID(SV_VertexID)和下面这一段HLSL Vertex Shader代码中来自动计算这些2D Quad顶点坐标系,包括TexCoord和NDC坐标。

//--------------------------------------------------------------------------------------
// ScreenVS.hlsl
//--------------------------------------------------------------------------------------
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;
}

SV_VERTEXID就是顶点序号,从0开始,比如对于2D的一个屏幕来讲,是一个矩形,有四个顶点,构成两个顺势针方向的三角形填充区域( △ # 0 # 1 # 2 \triangle_{\#0\#1\#2} #0#1#2, △ # 2 # 1 # 3 \triangle_{\#2\#1\#3} #2#1#3)。
在这里插入图片描述
上面的代码计算结果是:

SV_VERTEXIDtexcoord/output.Texoutput.Pos: SV_POSITION
0(0, 0)(-1, 1)
1(1, 0)(1, 1)
2(0, 1)(-1, -1)
3(1, 1)(1, -1)

可以看到正好通过vertex id可以准确计算出Texel Coordinate System和NDC,的确省了很多代码。
texcoord是用来在原来的texture上选择那块三角形来填充, output.Pos SV_POSITION则是用来控制屏幕上哪些位置需要填充texture的素材。

一些简单的扩展

下面用具体的图来演示这两个坐标系的作用,假设这是原图:
在这里插入图片描述
这是素材(Texture)填充坐标系:
在这里插入图片描述

素材有两个可以用来填充的区域,分别是ABC和CBD,如果想要用同一个素材ABC填CBD的区域,只要稍微改一下text coord就行了。

SV_VERTEXIDtexcoord/output.Texoutput.Pos: SV_POSITION
0(0, 0)(-1, 1)
1(1, 0)(1, 1)
2(0, 1)(-1, -1)
3(1, 1) → \to (0,0)(1, -1)

对应的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;
	
	switch (vI)
	{
		case 0: 
			output.Tex = float2(0, 0); 
			output.Pos = float4(-1.0f, 1.0f, 0.0f, 1.0f);
			break;
		case 1: 
			output.Tex = float2(1, 0); 
			output.Pos = float4(1.0f, 1.0f, 0.0f, 1.0f);
			break;
		case 2: 
			output.Tex = float2(0, 1); 
			output.Pos = float4(-1.0f, -1.0f, 0.0f, 1.0f);
			break;
		case 3: 
			output.Tex = float2(0, 0); 
			output.Pos = float4(1.0f, -1.0f, 0.0f, 1.0f);
			break;
	}
	

	return output;
}

这样可以看到如下显示效果:
在这里插入图片描述
如果是一个正方形的图片,可以看到没有变形的以对角线为对称轴的镜像映射图片,实际上D3D engine会以ABC填充对角线的左上部分,然后再以ABC再次填充对角线下部分。

这是屏幕渲染坐标系(SV_POSITION):
在这里插入图片描述
通过控制这个坐标系,可以做平移,变形,比如通过如下调整,可以把图像缩小到中心:

SV_VERTEXIDtexcoord/output.Texoutput.Pos: SV_POSITION
0(0, 0)(-1, 1) → \to (-0.5, 0.5)
1(1, 0)(1, 1) → \to (0.5, 0.5)
2(0, 1)(-1, -1) → \to (-0.5, -0.5)
3(1, 1)(1, -1) → \to (0.5, -0.5)

代码就不贴了,可以参考上面的实现
在这里插入图片描述
再来个变形
在这里插入图片描述

SV_VERTEXIDtexcoord/output.Texoutput.Pos: SV_POSITION
0(0, 0)A (-1, 1) → \to A’ (-0.5, 0.5)
1(1, 0)(1, 1)
2(0, 1)(-1, -1)
3(1, 1)D(1, -1) → \to D’(-0.3, -0.75)

输出的图像大概是:
在这里插入图片描述

结论

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

原创不易,如果对你有帮助,望点赞和关注。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值