有时候需要在三维坐标系中绘制二维元素,像文字、表格等,需要使用二维坐标系,DirectX之前都说取图不精,也就是没法在整数位置画出一个对应这个整数坐标的像素,譬如我想在二维屏幕坐标(400,50)到(800,50)画出水平线,可能你画出来的线在坐标(400,49)到(800,49),或者画两条相邻像素的线,譬如垂直坐标51,结果出来就是后画的线覆盖了前面画的线,这个问题在最新版的DirectX12还一直存在,微软的工程师似乎也解决不了这个问题,因为directx的坐标范围是float类型,从[-1.0f,1.0f],这就导致了在转换为2D坐标系画文字、线等二维元素时精度误差一个像素,也就是半像素问题,不过,微软工程师本就是为游戏开发了DirectX,所以DirectX在一些工程精细作图方面还是不合适,如果你想要画精确的图元素,还是使用OpenGL吧,目前的DirectX12无法满足,跑题了,下面说说三维坐标转二维坐标系的问题,先看代码:
// 基于左上角是坐标原点 X正方向向右 Y正方向向下 与窗口坐标系相同
// 这里的算法来自于古老的HGE引擎核心
// Orthographic
XMMATRIX mxOrthographic = XMMatrixScaling(1.0f, -1.0f, 1.0f); //上下翻转,配合之前的Quad的Vertex坐标一起使用
//mxOrthographic = XMMatrixMultiply(mxOrthographic, XMMatrixTranslation(-0.5f, +0.5f, 0.0f)); //微量偏移,矫正像素位置(这行代码仍然无法矫正1像素误差,所以注释掉)
mxOrthographic = XMMatrixMultiply(
mxOrthographic
, XMMatrixOrthographicOffCenterLH(stViewPort.TopLeftX
, stViewPort.TopLeftX + stViewPort.Width
, -(stViewPort.TopLeftY + stViewPort.Height)
, -stViewPort.TopLeftY
, stViewPort.MinDepth
, stViewPort.MaxDepth)
);
// View * Orthographic 正交投影时,视矩阵通常是一个单位矩阵,这里之所以乘一下以表示与射影投影一致
mxOrthographic = XMMatrixMultiply(
XMMatrixIdentity()
, mxOrthographic
);
// 渲染矩形框
// 设置矩形框的位置,即矩形左上角的坐标,注意因为正交投影的缘故,这里单位是像素
XMMATRIX xmMVO = XMMatrixMultiply(
XMMatrixTranslation(0.0f, 0.0f, 0.0f)
, mxOrthographic);
// 设置矩形框的大小,单位同样是像素
xmMVO = XMMatrixMultiply(
XMMatrixScaling(300.0f, 300.f, 1.0f)
, xmMVO);
//设置MVO
XMStoreFloat4x4(&pMOV->m_mMVO, xmMVO);
代码应该很容易理解:
XMMatrixScaling(1.0f, -1.0f, 1.0f);是围绕X轴旋转180°,Y轴变成向下
mxOrthographic = XMMatrixMultiply(
mxOrthographic
, XMMatrixOrthographicOffCenterLH(stViewPort.TopLeftX
, stViewPort.TopLeftX + stViewPort.Width
, -(stViewPort.TopLeftY + stViewPort.Height)
, -stViewPort.TopLeftY
, stViewPort.MinDepth
, stViewPort.MaxDepth)
);就是把坐标中心移动到左上角,跟2D窗口的坐标就一致了,也是左上角是原点