我一直在努力解决这个问题。我正在尝试使用devKitPro确定我的NDS屏幕上模型中顶点的屏幕坐标。该库似乎实现了OpenGL的一些功能,但特别是缺少gluProject函数,这将(我假设)允许我轻松地做到这一点。
我一直在努力尝试使用存储在DS寄存器中的投影基质来手动计算屏幕坐标,但即使尝试构建投影矩阵,我也没有太多运气。基于OpenGL文档的划痕。这是我正在尝试使用的代码:
void get2DPoint(v16 x, v16 y, v16 z, float &result_x, float &result_y)
{
//Wait for the graphics engine to be ready
/*while (*(int*)(0x04000600) & BIT(27))
continue;*/
//Read in the matrix that we're currently transforming with
double currentMatrix[4][4]; int i;
for (i = 0; i < 16; i++)
currentMatrix[0][i] =
(double(((int*)0x04000640)[i]))/(double(1<<12));
//Now this hurts-- take that matrix, and multiply it by the projection matrix, so we obtain
//proper screen coordinates.
double f = 1.0 / tan(70.0/2.0);
double aspect = 256.0/192.0;
double zNear = 0.1;
double zFar = 40.0;
double projectionMatrix[4][4] =
{
{ (f/aspect), 0.0, 0.0, 0.0 },
{ 0.0, f, 0.0, 0.0 },
{ 0.0, 0.0, ((zFar + zNear) / (zNear - zFar)), ((2*zFar*zNear)/(zNear - zFar)) },
{ 0.0, 0.0, -1.0, 0.0 },
};
double finalMatrix[4][4];
//Ugh...
int mx = 0; int my = 0;
for (my = 0; my < 4; my++)
for (mx = 0; mx < 4; mx++)
finalMatrix[mx][my] =
currentMatrix[my][0] * projectionMatrix[0][mx] +
currentMatrix[my][1] * projectionMatrix[1][mx] +
currentMatrix[my][2] * projectionMatrix[2][mx] +
currentMatrix[my][3] * projectionMatrix[3][mx] ;
double dx = ((double)x) / (double(1<<12));
double dy = ((double)y) / (double(1<<12));
double dz = ((double)z) / (double(1<<12));
result_x = dx*finalMatrix[0][0] + dy*finalMatrix[0][1] + dz*finalMatrix[0][2] + finalMatrix[0][3];
result_y = dx*finalMatrix[1][0] + dy*finalMatrix[1][1] + dz*finalMatrix[1][2] + finalMatrix[1][3];
result_x = ((result_x*1.0) + 4.0)*32.0;
result_y = ((result_y*1.0) + 4.0)*32.0;
printf("Result: %f, %f\n", result_x, result_y);
}
涉及到很多变化,DS使用定点表示法在内部工作,我需要将其转换为双精度才能使用。我所得到的似乎有些正确 - 如果我使用的是面向屏幕的平面四边形,则像素可以完美地转换,但旋转是不稳定的。另外,由于我要通过投影矩阵(占屏幕宽度/高度?),我需要使用的最后步骤似乎并不正确。投影矩阵不应该为我完成屏幕分辨率的升级吗?
我对所有这些都很陌生,我对矩阵数学有了很好的把握,但我并不像我想要的那样熟练掌握3D图形。这里有没有人知道一种方法,给定模型顶点的3D,非变换坐标,并给出应用于它的基质,实际提出屏幕坐标,而不使用OpenGL的gluProject函数?你能看到我在代码中遗漏的明显明显的东西吗? (我会在可能的情况下澄清,我知道这很粗糙,这是我正在研究的原型,清洁度不是高优先级)
非常感谢!
PS:根据我的理解,currentMatrix,我从DS的寄存器中提取,应该给我组合的投影,平移和旋转矩阵,因为它应该是正在进行的精确矩阵用于DS自己硬件的翻译,至少根据GBATEK的规范。在实践中,它似乎没有实际应用投影坐标,我想这与我的问题有关。但我不确定,因为计算投影本身并没有产生不同的结果。答案 0 :(得分:5)
这几乎是正确的。
正确的步骤是:
使用投影矩阵乘以模型视图(正如您已经做过的那样)。
通过添加值为1的W分量将3D顶点扩展为齐次坐标。例如,您的(x,y,z) - 矢量变为(x,y,z,w),其中w = 1。
将此向量与矩阵乘积相乘。你的矩阵应该是4x4,你的矢量是4。结果也是size4的向量(不要掉落!)。这种乘法的结果是剪辑空间中的向量。仅供参考:您可以使用此向量在此处执行一些非常有用的操作:测试点是否在屏幕上。六个条件是:
x < -w : Point is outside the screen (left of the viewport) x > W : Point is outside the screen (right of the viewport) y < -w : Point is outside the screen (above the viewport) y > w : Point is outside the screen (below the viewport) z < -w : Point is outside the screen (beyond znear) z > w : Point is outside the screen (beyond zfar)
x' = x / w; y' = y / w;
z' = z / w
请注意,如果w为零,则上一步不起作用。如果您的点等于摄像机位置,则会发生这种情况。在这种情况下,您可以做的最好的事情是将x'和y'设置为零。 (将在下一步将点移动到屏幕中心..)。
最终步骤:获取OpenGL视口坐标并应用它:
x_screen = viewport_left + (x' + 1) * viewport_width * 0.5; y_screen = viewport_top + (y' + 1) * viewport_height * 0.5;
就是这样。
答案 1 :(得分:1)
我会在Nils的全面答案中添加一些想法。