c++ - 绘制 2D map 坐标到 OpenGL 3D 投影

标签 c++ opengl math graphics tesselation

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

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 曲面 segmentation ( https://github.com/mapbox/earcut.hpp ),我终于在 OpenGL 中正确渲染了这个矩形。两个平面只有 Z 轴不同,现在的问题是如何渲染它的横向,因为 Earcut 只适用于 2D 坐标...

Planes

最佳答案

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

  1. 点表 pnt[pnts]

    对象所有点的列表。

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

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

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

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

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

  1. 复制所有点并通过一些平移将它们挤出。

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

  2. 复制/反转三角剖分。

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

  3. 创建缺失的侧面。

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

这是我现在为此破坏的 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 context 的东西到你的风格编程。这里唯一重要的东西是:

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

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

下面是上面代码的预览:

preview

断断续续是由于我的 GIF 捕捉渲染很流畅。我使用静态分配和运行正常计算,所以代码简单易懂。对于真正的交易来说,你需要实现动态列表和 VAO/VBO ......如果你想要良好的性能

关于c++ - 绘制 2D map 坐标到 OpenGL 3D 投影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50797846/

相关文章:

c++ - 无法删除指针,已触发断点

c++ - 在 vector 末尾找到周期的最大频率的最快方法?

python - 如何隐藏嵌入在 C++ 应用程序中的 Python 代码?

python - 无法再添加三个立方体

opengl - GLSL gl_Position 中的第四维是什么?

javascript - 寻找两个盒子之间的边缘的数学

python - python中的调和均值

c++ - undef 后代码补全仍然确认宏

qt - openGL - 无法显示图像

c++ - 在 C++ 中操作对角线