将2D地图坐标绘制为OpenGL 3D投影

时间:2018-06-11 12:33:07

标签: c++ opengl math graphics tesselation

我正在尝试将在地图编辑器中创建的2D地图转换为使用OpenGL进行3D绘图。这是我在地图编辑器中生成的地图:

Map editor

这些顶点是相对于我的笛卡尔原点世界坐标(图片的顶部)而我正在应用此公式将其转换为OpenGL对象坐标:

世界尺寸:800x600

x = (X / 800) -0.5
y = (Y / 600) -0.5

获得此结果:

(第一个物体脸)

−0.48625, 0.068333333
0.12625, 0.07
0.12875, −0.481666667
−0.4875, −0.486666667

在OpenGL中绘制这个顶点缓冲区,我得到了一个非常奇怪的结果。那么如何从这些顶点位置获得3D模型呢?喜欢这张图片:

Box room

我正在以三角形模式渲染OpenGL并使用此示例作为起点:https://github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/7.4.camera_class/camera_class.cpp

使用转换公式+ Earcut镶嵌(https://github.com/mapbox/earcut.hpp),我终于在OpenGL中正确渲染了这个矩形。由于两个平面只有Z轴不同,现在的问题是如何渲染它的横向,因为Earcut只适用于2D坐标......

Planes

2 个答案:

答案 0 :(得分:2)

如果我做对了,你会得到一些平面 2D 多边形以及为它添加一些恒定厚度的内容(作为3D网格)。这很容易实现。正确地假设您需要先进行三角测量。所以你应该有这个输入:

  1. 积分表pnt[pnts]

    对象的所有点列表。

  2. 多边形pol[pols](对象的周长)

    刚刚排序的点索引列表引用了点表

  3. 三角测量结果fac[facs]

    表示所有三角形的3个点索引的有序列表。

  4. 现在要从中制作网格,我们需要这样做:

    1. 复制所有点并通过一些翻译挤出它们。

      所有这些新点都将添加到当前pnt[pnts]表中。不要忘记记住原始表格大小pnts0,因为稍后将需要它。

    2. 复制/撤销三角测量。

      三角形多边形的另一侧在反向多边形缠绕中是相同的。因此,只需将其作为反向索引顺序的新三角形复制到fac[facs] ...不要忘记将原始点表大小添加到所有新面。这将使用新的点...从你的图像中你已经到了这一点。

    3. 创建缺少的侧面。

      为此,我们可以利用原始多边形。由于我们刚刚复制了这些点,因此我们知道pnt[3*i]pnt[pnts0+3*i]相反。所以我们只创建连接多边形相对边的三角形面。

    4. 这里的小C ++示例我现在已经破坏了这个:

      //---------------------------------------------------------------------------
      #include <vcl.h>
      #include <math.h>
      #pragma hdrstop
      #include "Unit1.h"
      #include "gl_simple.h"
      //---------------------------------------------------------------------------
      #pragma package(smart_init)
      #pragma resource "*.dfm"
      TForm1 *Form1;
      //---------------------------------------------------------------------------
      const int N=128;
      int pnts=6*3;                   // 3* number of points
      float pnt[N]=                   // x,y per each point
          {
          -0.5,-0.5,0.0,              //   6 ------ 9
          -0.4, 0.0,0.0,              //    +      +
          -0.5,+0.5,0.0,              //     3   12
          +0.5,+0.5,0.0,              //    +      +
          +0.4, 0.0,0.0,              //   0 ----- 15
          +0.5,-0.5,0.0,
          };
      int pol[N]={ 0,3,6,9,12,15 }, pols=6; // original polygon (3*pnt index), number of its vertexes
      int fac[N]=                     // triangulation result (3*pnt index)
          {
          0,3,15,
          3,12,15,
          3,6,12,
          6,9,12,
          }, facs=4*3;                // number of triangles*3
      //---------------------------------------------------------------------------
      void extrude(float dz)
          {
          int i,i0,pnts0=pnts;
          // copy and reverse triangulation
          for (i=0;i<facs;i++)
           fac[facs+facs-1-i]=fac[i]+pnts; facs+=facs;
          // duplicate points
          for (i=0;i<pnts;i++) pnt[pnts0+i]=pnt[i]; pnts+=pnts;
          // extrude points
          for (i=      2;i<pnts0;i+=3) pnt[i]-=dz;
          for (         ;i<pnts ;i+=3) pnt[i]+=dz;
          // side faces
          for (i0=pols-1,i=0;i<pols;i0=i,i++)
              {
              fac[facs]=pol[i ]+pnts0; facs++;
              fac[facs]=pol[i ];       facs++;
              fac[facs]=pol[i0];       facs++;
      
              fac[facs]=pol[i0]+pnts0; facs++;
              fac[facs]=pol[i ]+pnts0; facs++;
              fac[facs]=pol[i0];       facs++;
              }
          }
      //---------------------------------------------------------------------------
      void gl_draw()
          {
          glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
          glDisable(GL_TEXTURE_2D);
          glEnable(GL_DEPTH_TEST);
          glEnable(GL_LIGHTING);
          glEnable(GL_LIGHT0);
          glEnable(GL_CULL_FACE);
          glFrontFace(GL_CCW);
          glEnable(GL_COLOR_MATERIAL);
      /*
          glPolygonMode(GL_FRONT,GL_FILL);
          glPolygonMode(GL_BACK,GL_LINE);
          glDisable(GL_CULL_FACE);
      */
      
          // set view
          glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();
          glTranslatef(0.0,0.0,-5.0);
          static float ang=0.0;
          glRotatef(ang,0.2,0.7,0.1); ang+=5.0; if (ang>=360.0) ang-=360.0;
      
          // render mesh
          float *p0,*p1,*p2,n[3],a[3],b[3],c;
          glColor3f(0.7,0.7,0.7);
      
          glBegin(GL_TRIANGLES);
          for (int i=0;i+3<=facs;i+=3)
              {
              // points
              p0=pnt+fac[i+0];
              p1=pnt+fac[i+1];
              p2=pnt+fac[i+2];
              // compute normal
              a[0]=p1[0]-p0[0]; a[1]=p1[1]-p0[1]; a[2]=p1[2]-p0[2];
              b[0]=p2[0]-p1[0]; b[1]=p2[1]-p1[1]; b[2]=p2[2]-p1[2];
              n[0]=(a[1]*b[2])-(a[2]*b[1]);
              n[1]=(a[2]*b[0])-(a[0]*b[2]);
              n[2]=(a[0]*b[1])-(a[1]*b[0]);
              c=1.0/sqrt((n[0]*n[0])+(n[1]*n[1])+(n[2]*n[2]));
              n[0]*=c; n[1]*=c; n[2]*=c;
              // render
              glNormal3fv(n);
              glVertex3fv(p0);
              glVertex3fv(p1);
              glVertex3fv(p2);
              }
          glEnd();
      
      //  glFlush();
          glFinish();
          SwapBuffers(hdc);
          }
      //---------------------------------------------------------------------------
      __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
          {
          // Init of program
          gl_init(Handle);    // init OpenGL
          extrude(0.2);
          }
      //---------------------------------------------------------------------------
      void __fastcall TForm1::FormDestroy(TObject *Sender)
          {
          // Exit of program
          gl_exit();
          }
      //---------------------------------------------------------------------------
      void __fastcall TForm1::FormPaint(TObject *Sender)
          {
          // repaint
          gl_draw();
          }
      //---------------------------------------------------------------------------
      void __fastcall TForm1::FormResize(TObject *Sender)
          {
          // resize
          gl_resize(ClientWidth,ClientHeight);
          }
      //---------------------------------------------------------------------------
      void __fastcall TForm1::tim_redrawTimer(TObject *Sender)
          {
          gl_draw();
          }
      //---------------------------------------------------------------------------
      

      基于 VCL ,请忽略所有 VCL 内容并将您想要/需要的事件和 GL上下文内容移植到您的风格编程。这里唯一重要的东西是:

      保存输入的表pnt,fac,pol,后者也输出。 extrude(dz)将创建网格(仅调用一次!),gl_draw将表格渲染为网格(为简单起见,使用旧样式 GL api)。

      对于GL的东西,我使用了gl_simple.h,您可以在相关的QA中找到它:

      以下是上述代码的预览:

      preview

      波涛汹涌是由于我的GIF捕获,渲染是平滑的。我使用静态分配和运行正常计算,因此代码简单易懂。对于实际交易而言,您需要实现动态列表和VAO / VBO ...如果您想要良好的性能

答案 1 :(得分:0)

很难确定,但似乎你的对象只有两个面被渲染,因为你没有将其他面添加到索引中。

因为你有你的顶点,但你还需要告诉你有两边的三角形。如果它们是三角形,您最终应该绘制16个三角形。 如果不使用索引,则需要为每个三角形复制顶点,最后绘制48个顶点。

为了使earing算法在3D中工作,如果你确定你的多边形在同一个计划中具有所有它的点,你可以取3个顶点,推导它的计划,并创建一个转换矩阵来带来所有这些指向(x,y,0),就像2D坐标。