Если я правильно понял, у вас есть плоский 2D полигон и что добавить к нему постоянную толщину (как 3D-сетка). Это выполнимо довольно легко. Как вы правильно предположили, вам нужно сначала триангулировать. Итак, у вас должен быть этот ввод:
таблица очков pnt[pnts]
список всех точек вашего объекта.
многоугольник pol[pols]
(окружность вашего объекта)
просто упорядоченный список индексов точек, ссылающихся на таблицу точек
результат триангуляции fac[facs]
упорядоченный список из трех точечных индексов, представляющих все треугольники.
Теперь, чтобы сделать из него сетку, нам нужно сделать следующее:
скопируйте все точки и выдавите их с некоторым перемещением.
все эти новые точки будут добавлены в текущую таблицу pnt[pnts]
. Не забудьте запомнить исходный размер таблицы pnts0
, так как он понадобится позже.
копировать/обратить триангуляцию.
Противоположная сторона треугольного многоугольника будет такой же только при обратной намотке многоугольника. Так что просто скопируйте его в fac[facs]
как новые треугольники в обратном порядке индексов... Не забудьте добавить исходный размер таблицы точек ко всем новым граням. Это будет использовать новые точки ... Судя по вашим изображениям, вы уже попали в эту точку.
создайте недостающие боковые грани.
Для этого мы можем использовать исходный полигон. Поскольку мы только что скопировали точки, мы знаем, что 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