【问题标题】:Perspective Projection: determine the 2D screen coordinates (x,y) of points in 3D space (x,y,z)透视投影:确定 3D 空间 (x,y,z) 中点的 2D 屏幕坐标 (x,y)
【发布时间】:2010-10-16 15:14:38
【问题描述】:

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

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

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

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

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

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

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

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

【问题讨论】:

  • 你想画东西还是只计算一些点?

标签: java opengl projection


【解决方案1】:

这是一个非常笼统的答案。假设相机位于 (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)

【讨论】:

  • 前两个等式不应该是X' = ((X - Xc) * (F/(Z-Zc))) + XcY' = ((Y - Yc) * (F/(Z-Zc))) + Yc吗?
  • @Alec Jacobson,F = Z - Zc,如果是 F/(Z - Zc),那么它将是 1(这意味着 X' = X 和 Y = Y')。
  • 对不起,我什至不知道我刚才说了什么;我从字面上认为 F = Z - Zc,所以它会变成 1。
  • 如果相机距离发生变化,也应该有一个缩放因子。要么只是一个比例,要么是比例加旋转。你是怎么得出的?
【解决方案2】:

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

使用OpenGL 可能会比滚动自己的software rasterizer 节省大量工作。所以,我首先建议trying it。您可以在 PC 上制作系统原型,因为 OpenGL ES 并没有太大的不同,只要您保持简单即可。

【讨论】:

  • 我不知道我必须转换为笛卡尔坐标,所以谢谢。关于 OpenGL,我想我会尝试使用它来实现一个解决方案,因为它具有设置相机位置的方法,并且我相信它具有从 3D 模型获取 2D 投影的机制。你知道什么好的教程吗?
  • 这些是移植到多种语言的经典教程:nehe.gamedev.net
【解决方案3】:

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

另外openGL不处理地理坐标

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

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

  • WGS84
  • 地心坐标
  • 一些本​​地框架
  • 相机框架
  • 2D 投影

第一次转换见this 最后涉及到一个投影矩阵 其他的只是坐标旋转和平移。 “一些本地框架”是以原点为您的相机位置的本地笛卡尔框架 与椭球相切。

【讨论】:

    【解决方案4】:

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

    在 OpenGL 编程指南(红皮书)中也有一章很好地介绍了查看转换和设置相机(包括如何使用 gluLookAt)。

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

    【讨论】:

      【解决方案5】:
      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
      }
      

      【讨论】:

        猜你喜欢
        • 2014-05-30
        • 1970-01-01
        • 2022-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-03
        相关资源
        最近更新 更多