透视投影 - 帮助一个菜鸟

时间:2009-03-31 15:12:32

标签: java opengl projection

我希望确定3D空间(x,y,z)中点的2D屏幕坐标(x,y)。

我希望投射的点是由GPS坐标和海拔高度表示的真实世界点。

例如: Point(Lat:49.291882,Long:-123.131676,Height:14m)

摄像机位置和高度也可以确定为x,y,z点。我还有相机的标题(罗盘度),倾斜度(地平线上方/下方)和滚动(绕z轴)。

我没有3D编程的经验,因此,我已经阅读了透视投影的主题,并了解到它需要了解矩阵,变换等等 - 所有这些都使我目前感到困惑。

我被告知OpenGL可能用于构建真实世界点的3D模型,设置相机方向并检索3D点的2D坐标。

但是,我不确定使用OpenGL是否是解决此问题的最佳解决方案,即使它是我不知道如何创建模型,设置相机等

有人可以提出解决问题的最佳方法吗?如果OpenGL是一个可行的解决方案,我必须使用OpenGL ES,如果这有任何区别。哦,无论我选择哪种解决方案,都必须快速执行。

感谢您的帮助

5 个答案:

答案 0 :(得分:13)

这是一个非常一般的答案。假设相机处于(Xc,Yc,Zc)并且您要投影的点是P =(X,Y,Z)。从摄像机到投影到的2D平面的距离为F(因此平面的方程为Z-Zc = F)。投影到平面上的P的2D坐标是(X',Y')。

然后,非常简单:

X'=((X-Xc)*(F / Z))+ Xc

Y'=((Y-Yc)*(F / Z))+ Yc

如果你的相机是原点,那么这简化为:

X'= X *(F / Z)

Y'= Y *(F / Z)

答案 1 :(得分:4)

确实需要perspective projectionmatrix operations大大简化这样做。我假设您已经知道,为了进行这些计算,您的spherical coordinates必须转换为Cartesian coordinates

使用OpenGL可能会比滚动自己的software rasterizer节省大量工作。所以,我先建议trying it。您可以在PC上对系统进行原型设计,因为只要您保持简单,OpenGL ES就不会有太大差异。

答案 2 :(得分:2)

如果只需要计算某些点的坐标,你应该只需要一些代数技能,而不需要用openGL进行3D编程。

此外 openGL不处理地理坐标

首先获得一些关于WGS84和测地坐标的文档,首先要将GPS数据转换为笛卡尔坐标系(例如,以地球为中心的笛卡尔坐标系定义为WGS84椭圆体)。

然后可以进行矩阵计算。 变换链大致是:

  • WGS84
  • 以地球为中心的坐标
  • 一些本地框架
  • 相框
  • 2D投影

首次转化时,请参阅this 最后一个涉及投影矩阵 其他只是坐标旋转和平移。 “一些本地框架”是本地笛卡尔框架,其原点是您的相机位置 与椭圆体相切。

答案 3 :(得分:2)

我推荐Eric Lengyel的“3D游戏编程和计算机图形学数学”。它涵盖了矩阵,变换,视锥体,透视投影等。

“OpenGL编程指南”(红皮书)中有关于查看转换和设置相机的一章(包括如何使用gluLookAt)。

如果您对显示3D场景不感兴趣并且仅限于使用OpenGL ES,那么最好编写自己的代码来执行从3D到2D窗口坐标的映射。作为起点,您可以下载Mesa 3D,OpenGL的开源实现,以了解它们如何实现gluPerspective(设置投影矩阵),gluLookAt(设置相机转换)和gluProject(投影3D点)到2D窗口坐标)。

答案 4 :(得分:0)

return [((fol/v[2])*v[0]+x),((fol/v[2])*v[1]+y)];

指向[0,0,1]的点将为x = 0和y = 0,除非您添加中心屏幕xy-而不是相机xy。 fol是从fov角度和屏幕宽度得出的焦距-三角形(切线)的高度。此方法将不匹配three.js透视矩阵,这就是为什么我要寻找它。

我不应该寻找它。我在openGL上匹配了xy,就像超级胶水一样!但是我无法使其在Java中正常工作。完美的搭配紧随其后。

var pmat = [0,0,0,0,0,0,0,0,0,0,
(farclip + nearclip) / (nearclip - farclip),-1,0,0,
2*farclip*nearclip / (nearclip - farclip),0 ];

void setpmat() {
  double fl; // = tan(dtor(90-fovx/aspect/2)); /// UNIT focal length
  fl = 1/tan(dtor(fov/Aspect/2)); ///  same number
  pmat[0]  = fl/Aspect;
  pmat[5]  = fl;
}
void fovmat(double v[],double p[]) {
  int cx = (int)(_Width/2),cy = (int)(_Height/2);
  double pnt2[4], pnt[4] = { 0,0,0,1 } ;
  COPYVECTOR(pnt,p);NORMALIZE(pnt);
  popmatrix4(pnt2,pmat,pnt);
  COPYVECTOR(v,pnt2);
  v[0] *= -cx; v[1] *= -cy;
  v[0] += cx; v[1] += cy;
}  // world to screen matrix
void w2sm(int xy[],double p[]) {
    double v[3]; fovmat(v,p);
    xy[0] = (int)v[0];
    xy[1] = (int)v[1];
}

我还有另一种匹配Three.js xy的方法,直到我得到矩阵起作用,只是一种情况。必须以2的纵横比运行

function w2s(fol,v,x,y) {
    var a = width / height;
    var b =  height/width ;
    /// b = .5 // a = 2
    var f = 1/Math.tan(dtor(_fov/a)) * x * b;
    return [intr((f/v[2])*v[0]+x),intr((f/v[2])*v[1]+y)];
}

将其与倒置的相机矩阵一起使用,则需要invert_matrix()。

    v = orbital(i);
    v = subv(v,campos);
    v3 = popmatrix(wmatrix,v); //inverted mat
    if (v3[2] > 0) {
    xy = w2s(flen,v3,cx,cy);

最后,这是(每个人现在都应该知道的)无矩阵匹配,任何方面。

function angle2fol(deg,centerx) {
    var b = width / height;
    var a = dtor(90 - (clamp(deg,0.0001,174.0) / 2));
    return asa_sin(PI_5,centerx,a) / b;
}
function asa_sin(a,s,b) {
    return Math.sin(b) * (s / Math.sin(PI-(a+b)));
} // ASA solve opposing side of angle2 (b)
function w2s(fol,v,x,y) {
    return [intr((fol/v[2])*v[0]+x),intr((fol/v[2])*v[1]+y)];
}

更新了用于打样的图像。输入_fov可让您“大约”获得1.5。要正确查看FOV读数,请使用新的焦距重做三角形。

function afov(deg,centerx) {
    var f = angle2fol(deg,centerx);
    return rtod(2 * sss_cos(f,centerx,sas_cos(f,PI_5,centerx)));
}
function sas_cos(s,a,ss) {
    return Math.sqrt((Math.pow(s,2)+Math.pow(ss,2))-(2*s*ss*Math.cos(a)));
} // Side Angle Side - solve length of missing side
function sss_cos(a,b,c) {
    with (Math) {
        return acos((pow(a,2)+pow(c,2)-pow(b,2))/(2*a*c));
    }
} // SSS solve angle opposite side2 (b)

星空库确认了视角,然后可以测量VIEW! http://innerbeing.epizy.com/cwebgl/perspective.jpg

我可以用一个词进动来解释对月球北极的90度校正。那么当前的上升向量是多少。 PNT?拉德克?

function ininorths() {
    if (0) {
        var c = ctime;
        var v = LunarPos(jdm(c));
        c += secday();
        var vv = LunarPos(jdm(c));
        vv = crossprod(v,vv);
        v = eyeradec(vv);
        echo(v,vv);
        v = [266.86-90,65.64]; //old
    }
    var v = [282.6425,65.8873]; /// new.
    // ...
}

我还没有解释两套矢量:Three.milkyway.matrix和3D到2D绘图。他们是:

function drawmilkyway() {
  var v2 = radec2pos(dtor(192.8595), dtor(27.1283),75000000);
  // gcenter 266.4168 -29.0078
  var v3 = radec2pos(dtor(266.4168), dtor(-29.0078),75000000);
 // ...
}
function initmwmat() {
    var r,u,e;
    e = radec2pos(dtor(156.35), dtor(12.7),1);
    u = radec2pos(dtor(60.1533), dtor(25.5935),1);
    r = normaliz(crossprod(u,e));
    u = normaliz(crossprod(e,r));
    e = normaliz(crossprod(r,u));
    var m = MilkyWayMatrix;
    m[0]=r[0];m[1]=r[1];m[2]=r[2];m[3]=0.0;
    m[4]=u[0];m[5]=u[1];m[6]=u[2];m[7]=0.0;
    m[8]=e[0];m[9]=e[1];m[10]=e[2];m[11]=0.0;
    m[12]=0.0;m[13]=0.0;m[14]=0.0;m[15]=1.0;
}
/// draw vectors and matrix were the same in C !
void initmwmat(double m[16]) {
  double r[3], u[3], e[3];
  radec2pos(e,dtor(192.8595), dtor(27.1283),1); //up
  radec2pos(u,dtor(266.4051), dtor(-28.9362),-1); //eye
}