Отображение координат 2D-карты в 3D-проекции OpenGL

Я пытаюсь преобразовать 2D-карту, созданную в моем редакторе карт, в 3D-графику с помощью OpenGL. Это моя карта, созданная в моем редакторе карт:

Редактор карт

Эти вершины относятся к моей декартовой исходной мировой координате (верхняя часть изображения), и я применяю эту формулу для преобразования ее в координату объекта 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-модель из этих позиций вершин? Как на этой картинке:

Бокс

Я визуализирую 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-координатами...

Самолеты


person GabrielBiga    schedule 11.06.2018    source источник
comment
несколько непонятно, что вы спрашиваете. Как разместить и изменить размер QUAD, представляющего вашу карту, на экран? или как создать сетку на основе куба из какого-то массива 2D карт (пустого пространства или текстурированного куба)... Зачем вообще нужно отсечение ушей?   -  person Spektre    schedule 11.06.2018
comment
Мне нужно отсечение ушей, потому что пользователь может рисовать более 4 вершин, формируя другие вещи, кроме четырехугольников. Например, как шестиугольник, но это зависит от пользователя, рисующего в 2D-пространстве. Можно ли выдавить эту 2D-сетку в 3D?   -  person GabrielBiga    schedule 11.06.2018
comment
Как вы пояснили, я отказался от закрытого голосования и добавил ответ с простым примером C++, как я это вижу.   -  person Spektre    schedule 11.06.2018


Ответы (2)


Если я правильно понял, у вас есть плоский 2D полигон и что добавить к нему постоянную толщину (как 3D-сетка). Это выполнимо довольно легко. Как вы правильно предположили, вам нужно сначала триангулировать. Итак, у вас должен быть этот ввод:

  1. таблица очков pnt[pnts]

    список всех точек вашего объекта.

  2. многоугольник pol[pols] (окружность вашего объекта)

    просто упорядоченный список индексов точек, ссылающихся на таблицу точек

  3. результат триангуляции fac[facs]

    упорядоченный список из трех точечных индексов, представляющих все треугольники.

Теперь, чтобы сделать из него сетку, нам нужно сделать следующее:

  1. скопируйте все точки и выдавите их с некоторым перемещением.

    все эти новые точки будут добавлены в текущую таблицу pnt[pnts]. Не забудьте запомнить исходный размер таблицы pnts0, так как он понадобится позже.

  2. копировать/обратить триангуляцию.

    Противоположная сторона треугольного многоугольника будет такой же только при обратной намотке многоугольника. Так что просто скопируйте его в fac[facs] как новые треугольники в обратном порядке индексов... Не забудьте добавить исходный размер таблицы точек ко всем новым граням. Это будет использовать новые точки ... Судя по вашим изображениям, вы уже попали в эту точку.

  3. создайте недостающие боковые грани.

    Для этого мы можем использовать исходный полигон. Поскольку мы только что скопировали точки, мы знаем, что pnt[3*i] противоположно pnt[pnts0+3*i]. Поэтому мы просто создаем треугольные грани, соединяющие противоположные края многоугольника.

Вот небольшой пример на С++, который я сейчас разорил:

//---------------------------------------------------------------------------
#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 отобразит таблицы как сетку (используя старый стиль API GL для простоты).

Для материала GL я использовал свой gl_simple.h, который вы можете найти в этом связанном QA:

Вот предварительный просмотр кода выше:

предварительный просмотр

чоппины из-за моего захвата GIF, рендеринг гладкий. Я использовал статическое распределение и обычные вычисления во время выполнения, поэтому код прост и понятен. Конечно, для реальной сделки вам нужно реализовать динамические списки и VAO/VBO... если вам нужна хорошая производительность.

person Spektre    schedule 11.06.2018

Трудно сказать наверняка, но кажется, что ваш объект имеет только два лица, потому что вы не добавили другие лица в индекс.

Потому что у вас есть вершины, но вам также нужно указать треугольники для сторон. Если это треугольники, у вас должно получиться 16 треугольников. Если вы не используете индекс, вам нужно продублировать свои вершины для каждого треугольника и в итоге получить 48 вершин для рисования.

Что касается того, чтобы заставить алгоритм колошения работать в 3D, если вы точно знаете, что все точки вашего многоугольника находятся в одном плане, вы можете взять 3 вершины, вывести его план и создать матрицу преобразования, чтобы привести все эти точки к ( x, y, 0), что похоже на 2D-координаты.

person florent teppe    schedule 11.06.2018