在3D游戏中获得游戏人物敌人坐标xyz后,并不能直接绘制到屏幕上,需要进行一系列的转换算法,目前主流的算法包括三角函数转换与矩阵变换,三角函数转换方法过时且繁琐,这里不推荐使用,本文主讲矩阵变换原理:
一、游戏中多种坐标矩阵的转换关系
游戏中用CE可以找到敌人的world space坐标,也就是XYZ的游戏世界空间坐标, 通过矩阵变换得到Clip Space坐标(剪切坐标),通过透视分割算法得到NDC坐标,最后将NDC坐标视窗映射矩阵即可获得屏幕坐标。
二、D3D和opengl中矩阵存储形式
Direct3D 采用行主序(Row major)存储
“Effect matrix parameters and HLSL matrix variables can define whether the value is a row-major or column-major matrix; however, the DirectX APIs always treat D3DMATRIX and D3DXMATRIX as row-major.”
OpenGL 采用列主序(Colume major)存储
“The m parameter points to a 4x4 matrix of single- or double-precision floating-point values stored in column-major order. That is, the matrix is stored as follows”
存储顺序说明了线性代数中的矩阵如何在线性的内存数组中存储,d3d 将每一行在数组中按行存储,而opengl将每一列存储到数组的每一行中:
因此,对于线程代数中的同一个矩阵,则在d3d和OpenGL中有不同的表示形式:
线代矩阵:a11,a12,a13,a14 d3d保存: a11,a12,a13,a14 OpenGL保存: a11,a21,a31,a41 a21,a22,a23,a24 a21,a22,a23,a24 a12,a22,a32,a42 a31,a32,a33,a34 a31,a32,a33,a34 a13,a23,a33,a43 a41,a42,a43,a44 a41,a42,a43,a44 a14,a24,a34,a44
三、算法实现流程(以D3D为例)
1.假设敌人的世界坐标为X, Y, Z,W;其中W为其次项,一般设置为1(D3D规范如此,这个不必计较)
2.计算剪切坐标:
剪切坐标X = a11*X + a12*Y + a13*Z + a14
剪切坐标Y = a21*X + a22*Y + a23*Z + a24
剪切坐标Z = a31*X + a32*Y + a33*Z + a34
剪切坐标W = a41*X + a42*Y + a43*Z + a44
(此处注意设置筛选条件,仅剪切坐标w>0的才可以继续以下操作,小于0的可以忽略,因为不在你的视角内,PS:不信的同学可以最后试一下加与不加的区别)
3.计算NDC坐标:(透视分割算法:用剪切坐标XYZ除以W即可)
NDC坐标X = 剪切坐标X / 剪切坐标W
NDC坐标Y = 剪切坐标Y / 剪切坐标W
NDC坐标Z = 剪切坐标Z / 剪切坐标W
4.NDC坐标转屏幕坐标:
转换公式如下:
屏幕坐标.x = 窗口宽度 ÷ 2 × NDC坐标.x + NDC坐标.x + 窗口宽度 ÷ 2
屏幕坐标.y = -(窗口高度 ÷ 2 × NDC坐标.y) + NDC坐标.y + 窗口高度 ÷ 2
至此,已经描述完世界坐标转换屏幕坐标的算法了
如果对NDC转屏幕坐标感兴趣的小伙伴可以继续往下看:
四、NDC转屏幕公式解析
如图所示,我们通过视口变换矩阵ViewPort与NDC坐标进行矩阵乘,即可得到以上公式,但是对于屏幕坐标Y的公式不可由该矩阵乘推得,注意公式前面的符号:屏幕坐标.y = -(窗口高度 ÷ 2 × NDC坐标.y) + NDC坐标.y + 窗口高度 ÷ 2,
按照矩阵乘推理,应该没有负号,但是此处有,原因如下:
先普及下正常的屏幕坐标系和屏幕视口坐标系的区别:
由此可以知道,在与VIewPort做矩阵乘运算中,Y应该为与原来相反,所以在
[x,
y;
z,
1]竖矩阵中将y加上符号,再做矩阵乘,即可得到以上正确的算法公式,自己动手算一遍就会懂了。
参考文献:
https://www.bilibili.com/video/BV1UK4y1D781/?spm_id_from=trigger_reload
https://www.cnblogs.com/icmzn/p/13531265.html
https://space.bilibili.com/442168898/channel/detail?cid=123750
https://www.bilibili.com/video/av286268338/