简体   繁体   English

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

[英]Plotting 2D map coordinates to OpenGL 3D projection

I'm trying to convert a 2D map created in my map editor to a 3D plotting with OpenGL. 我正在尝试将在地图编辑器中创建的2D地图转换为使用OpenGL的3D绘图。 This is my map generated in my map editor: 这是在地图编辑器中生成的地图:

地图编辑器

Those vertices are relative to my Cartesian origin world coordinate (top up of the picture) and I'm applying this formula to convert it to an OpenGL object coordinate: 这些顶点是相对于我的笛卡尔原点世界坐标(图片的顶部)的,我正在应用此公式将其转换为OpenGL对象坐标:

World size: 800x600 世界尺寸:800x600

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

Getting this result: 得到这个结果:

(First object face) (第一个对象的脸)

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

Plotting this vertex buffer in OpenGL, I got a very weird result. 在OpenGL中绘制此顶点缓冲区,得到了一个非常奇怪的结果。 So how can I get a 3D model from those vertex positions? 那么如何从这些顶点位置获得3D模型呢? Like this picture: 像这张照片:

收藏室

I'm rendering OpenGL in triangles mode and using this example as the start point: https://github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/7.4.camera_class/camera_class.cpp 我正在以三角形模式渲染OpenGL,并以以下示例为起点: https : //github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/7.4.camera_class/camera_class.cpp

Using the conversion formula + the Earcut tessellation ( https://github.com/mapbox/earcut.hpp ), I've finally got this rectangle rendering correctly inside OpenGL. 使用转换公式+ Earcut镶嵌( https://github.com/mapbox/earcut.hpp ),我终于在OpenGL中正确渲染了此矩形。 With two planes with just the Z-axis different, now the problem is how to render its laterals since Earcut just works with 2D coordinates... 由于两个平面的Z轴不同,所以现在的问题是如何渲染侧面,因为Earcut只适用于2D坐标...

飞机

If I get it right you got some planar 2D polygon and what to add some constant thickness to it (as a 3D mesh). 如果我做对了,您会得到一些平面2D多边形以及要为其添加一些恒定厚度的内容(作为3D网格)。 That is doable fairly easily. 这很容易做到。 As you correctly assumed you need to triangulate first. 正确假设您需要首先进行三角剖分。 So you should have this input: 因此,您应该输入以下内容:

  1. table of points pnt[pnts] 点表pnt[pnts]

    list of all points of your object. 对象所有点的列表。

  2. polygon pol[pols] (circumference of your object) 多边形pol[pols] (物体的圆周)

    just ordered list of points indexes referencing to table of points 刚排序的点索引列表引用点表

  3. triangulation result fac[facs] 三角剖分结果fac[facs]

    ordered list of 3 point indexes representing all the triangles. 代表所有三角形的3点索引的有序列表。

Now to make a mesh from it we need to do this: 现在要从中制作网格,我们需要这样做:

  1. copy all the points and extrude them by some translation. 复制所有要点,并通过翻译将其挤出。

    all this new points will be added to current pnt[pnts] table. 所有这些新点都将添加到当前pnt[pnts]表中。 Do not forget to remember original table size pnts0 as it will be needed later. 不要忘记记住原始表大小pnts0因为以后将需要它。

  2. copy/reverse the triangulation. 复制/反转三角剖分。

    The opposite side of the triangulated polygon will be the same just in reverse polygon winding. 三角多边形的相反侧将在反向多边形缠绕中相同。 So just copy it to fac[facs] as new triangles in reverse index order ... Do not forget to add the original point table size to all the new faces. 因此,只需按照相反的索引顺序将其复制到fac[facs]作为新的三角形即可。不要忘记将原始点表的大小添加到所有新面中。 This will use the new points ... From the images of yours you got to this point already. 这将使用新的点...从您的图像中,您已经达到了这一点。

  3. create the missing side faces. 创建缺少的侧面。

    For this we can exploit the original polygon. 为此,我们可以利用原始多边形。 As we just copied the points then we know that pnt[3*i] is opposite to pnt[pnts0+3*i] . 当我们仅复制点时,便知道pnt[3*i]pnt[pnts0+3*i]相反。 So we just create triangle faces joining the opposite edges of the polygon. 因此,我们只创建连接多边形相对边缘的三角形面。

Here small C++ example I busted for this right now: 这是我现在为此提出的一个小型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();
    }
//---------------------------------------------------------------------------

It is VCL based so ignore all the VCL stuff and port the events you want/need and GL context stuff to your style of programing. 它基于VCL,因此请忽略所有VCL内容,并将您想要/需要的事件和GL上下文内容移植到您的编程风格中。 The only important stuff here are: 这里唯一重要的东西是:

the tables pnt,fac,pol which holds the input and latter also output. pnt,fac,pol保存输入,后者也输出。 The extrude(dz) will create the mesh (call it just once!) and gl_draw will render the tables as mesh (Using the old style GL api for simplicity). extrude(dz)将创建网格(只需调用一次!),而gl_draw将表呈现为网格(为简单起见,使用旧样式GL api)。

For the GL stuff I used my gl_simple.h which you can find in this related QA: 对于GL的东西,我使用了我的gl_simple.h ,您可以在相关的质量检查中找到它:

Here is preview of the code above: 这是上面代码的预览:

预习

the choppynes is due to my GIF capture the rendering is smooth. 之所以如此,是因为我的GIF捕获使渲染变得平滑。 I used static allocation and on the run normal computation so the code is simple and easy to understand. 我使用静态分配并运行常规计算,因此代码简单易懂。 Of coarse for the real deal you need to implement dynamic lists and VAO/VBO ... if you want good performance 对于真实交易而言,您需要实施动态列表和VAO / VBO ...如果您想获得良好的性能,那么这很粗糙

It's hard to know for sure, but it seems your object has only thwo faces rendered because you didn't add the other faces to the index. 很难确定,但是您的对象似乎只渲染了两个面,因为您没有将其他面添加到索引中。

Because you have your vertices, but you also need to tell have a triangles for the sides. 因为您有自己的顶点,但是您还需要告诉侧面有一个三角形。 If they are triangles you should end up with 16 triangles to draw. 如果它们是三角形,则最终应绘制16个三角形。 If you don't use an index, you need to duplicate your vertices, for each triangle and end up with 48 vertices to draw. 如果不使用索引,则需要为每个三角形复制顶点,最后绘制48个顶点。

As to get the earing algorithm to work in 3D, if you know for sure that your polygon has all it's point in the same plan, you can take 3 vertices, deduce it's plan, and create a transformation matrix to bring all these points to (x,y,0) which is like 2D coordinates. 为了使Earing算法能够在3D中工作,如果您确定多边形在同一平面中具有所有点,则可以获取3个顶点,推导其平面,然后创建一个转换矩阵以将所有这些点带到( x,y,0),就像2D坐标一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM