16

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

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

例如:点(纬度:49.291882,经度:-123.131676,高度:14m)

相机位置和高度也可以确定为 ax,y,z 点。我还有相机的航向(罗盘度数),它的倾斜度(高于/低于地平线)和滚动(围绕 z 轴)。

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

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

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

有人可以建议解决我的问题的最佳方法吗?如果 OpenGL 是一个可行的解决方案,我将不得不使用 OpenGL ES,如果这有什么不同的话。哦,无论我选择什么解决方案,它都必须快速执行。

4

5 回答 5

20

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

然后,非常简单:

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

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

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

X' =​​ X * (F/Z)

Y' = Y * (F/Z)

于 2009-03-31T16:50:01.037 回答
5

您确实需要透视投影,并且矩阵运算大大简化了这样做。我假设您已经知道您的球坐标必须转换为笛卡尔坐标才能进行这些计算。

与滚动您自己的软件光栅化器相比,使用OpenGL可能会为您节省大量工作。所以,我建议先尝试一下。您可以在 PC 上对您的系统进行原型设计,因为只要您保持简单,OpenGL ES 并没有太大的不同。

于 2009-03-31T15:36:21.010 回答
2

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

此外,openGL 不处理地理坐标

首先获取一些关于WGS84和测地坐标的文档,您必须首先将 GPS 数据转换为笛卡尔坐标系(例如定义为 WGS84 椭球的地心笛卡尔坐标系)。

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

  • WGS84
  • 地心坐标
  • 一些局部框架
  • 相机框架
  • 二维投影

对于第一次转换,请参见最后 一个涉及投影矩阵其他只是坐标旋转和平移。“某个局部框架”是局部笛卡尔框架,其原点是与椭圆体相切的相机位置。

于 2009-03-31T15:42:00.420 回答
2

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

The OpenGL Programming Guide(红皮书)中还有一个很好的章节,介绍了查看转换和设置相机(包括如何使用 gluLookAt)。

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

于 2009-03-31T16:41:32.960 回答
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,直到我得到矩阵工作,只有一个条件。必须以 Aspect of 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度的校正。那么当前的向上向量是多少。点?拉德克?

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
}
于 2020-08-01T01:49:06.687 回答