本人想手动实现从世界坐标系中的一点到屏幕坐标系的转换 , 网上的资料都是在讲解固定管线的渲染过程 , 本人的需求并不需要做 背面拣选裁剪等操作 , 所以自己来写一个 ,总体流程是
世界坐标系->视图坐标系->投影平面坐标系->屏幕坐标系
世界坐标系->视图坐标系
见本人的另外一篇
详述世界坐标系到视图坐标系(摄像机坐标系)的矩阵变换
视图坐标系->投影平面坐标系(透视投影)
投影平面, 在D3D中Z = 1 且与X, Y轴平行的平面 , 由于透视投影, 灭点在视图坐标系的原点, 任意一点在该平面的投影为 .
已知视图坐标系的一点P(Y , Z) , 求 在投影平面的点P(Y’ , Z’) , 角a未知 ,则
由三角形相似可得 , (X Z的坐标轴与上图相同 , 只是把Y换成X而已)
Y’= Y * Z’ / Z
X’= X * Z’ / Z
D3D中投影平面Z’ =1, 所以
Y’= Y / Z
X’= X / Z
Z’= 1
由上可得变换矩阵为
1 0 0 0
0 1 0 0
0 0 1 1
0 0 0 0
投影平面坐标系->屏幕坐标系
设投投影平面最大高宽为Ph ,Pw ,通过Y轴的最大可视角度a , 视截体的最远Z值 Zf 则可得出 , 投影平面的最大高度Ph(Y轴方向)
Ph= tan( a/2 ) * Zf
通过屏幕高宽比Aspect, 求出最大宽度Pw
Pw= Ph * Aspect
求得Ph , Pw , 我们可以得到投影平面到屏幕平面的转换比例(由于Ph , Pw仅是整个最大高宽的一半 , 所以屏幕最大高宽也除二)
Yscale= (Sh/2)/Ph
Xscale= (Sw/2)/Pw
则投影面上任意一点P(X, Y) 到屏幕平面P’(X’ , Y’)的转换为
X’= Sw/2 + X * Xscale
Y’= Sh/2 - Y * Yscale
PS.屏幕坐标原点在左上角
由上可得变换矩阵为
Xscale 0 00
0 -Yscale 0 0
0 0 1 0
Sw/2 Sh/2 0 1
视口默认位置为(0 , 0) , 不排除你会修改 , 所以还要加上视口在windows窗口的起始位置 , 可以通过getviewport获得 所以矩阵应为
Xscale 0 0 0
0 -Yscale 0 0
0 0 1 0
Port.x +Sw/2 Port.y +Sh/2 0 1