I'm working on generating a planet made out of a hexagon grid. The poles aren't needed - making this a bit easier. Is there a better way to turn the cylinder into a sphere that would have uniform hexagons/triangles?
Here's the desired steps:
For step 2, I'm just using Sin and Cos to move the vertices into a circular shape.
For step 3, right now I'm just using: vertices[i] = vertices[i].normalized * radius;
Image to visualize the problem as it is currently.
Note that the poles are cut off on purpose. The red parts show what one hexagon mesh looks like. I would have to keep them roughly the same size and orientation since they are used for gameplay and visual elements. Each hex has a list of neighbors and works like a graph basically.
Instead of cylinder to sphere mapping I would do a sphere triangulation...
I would first start with 2 hexagons
each start at pole and end on the equator or do the half only and mirror the other when all done...
then recursively subdivide the triangles
so divide lines to half and change the mid point coordinate to align with sphere surface. This will create triangulated sphere. Subdivide to valid number of points to form hexagons and have enough grid points.
change the hexagon mid-point coordinates back to plane of hexagon
So take the other 6 point and compute average coordinates which gives you the point for middle ...
Something like this:
for more ideas look here:
[edit1] triangulation (no hexagon corrections)
//---------------------------------------------------------------------------
#include <math.h>
#include "list.h"
class mesh
{
public:
class _pnt { public: double p[3]; _pnt(){}; _pnt(_pnt& a){ *this=a; }; ~_pnt(){}; _pnt* operator = (const _pnt *a) { *this=*a; return this; }; /*_pnt* operator = (const _pnt &a) { ...copy... return this; };*/ };
class _fac { public: int i0,i1,i2; _fac(){}; _fac(_fac& a){ *this=a; }; ~_fac(){}; _fac* operator = (const _fac *a) { *this=*a; return this; }; /*_fac* operator = (const _fac &a) { ...copy... return this; };*/ };
List<_pnt> pnt; // mesh points
List<_fac> fac; // mesh triangles
mesh() {}
mesh(mesh& a) { *this=a; }
~mesh() {}
mesh* operator = (const mesh *a) { *this=*a; return this; }
//mesh* operator = (const mesh &a) { ...copy... return this; }
void draw(); // draws the mesh with OpenGL
void sphere(int n); // init mesh with unit sphere from triangles (n recursion layers)
};
//---------------------------------------------------------------------------
void mesh::draw()
{
int i;
_fac *f;
// fill
glColor3f(0.7,0.7,0.7);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
glBegin(GL_TRIANGLES);
for (i=0,f=fac.dat;i<fac.num;i++,f++)
{
glVertex3dv(pnt.dat[f->i0].p);
glVertex3dv(pnt.dat[f->i1].p);
glVertex3dv(pnt.dat[f->i2].p);
}
glEnd();
// wireframe
glColor3f(0.1,0.3,0.7);
glLineWidth(2.0);
for (i=0,f=fac.dat;i<fac.num;i++,f++)
{
glBegin(GL_LINE_LOOP);
glVertex3dv(pnt.dat[f->i0].p);
glVertex3dv(pnt.dat[f->i1].p);
glVertex3dv(pnt.dat[f->i2].p);
glEnd();
}
glLineWidth(1.0);
}
//---------------------------------------------------------------------------
void mesh::sphere(int n)
{
// init 2 hexagons
int i,j,m,i0,i1,i2,j0,j1,j2;
double a,da=M_PI/3.0;
double *p0,*p1;
_pnt p;
_fac f,*g;
p.p[0]= 0.0;
p.p[1]= 0.0;
p.p[2]=+1.0;
pnt.add(p);
p.p[2]=-1.0;
pnt.add(p);
for (i=0,a=0.0;i<6;i++,a+=da)
{
p.p[0]=cos(a);
p.p[1]=sin(a);
p.p[2]= 0.0;
pnt.add(p);
}
// top half
f.i0=0; f.i1=2; f.i2=3; fac.add(f);
f.i0=0; f.i1=3; f.i2=4; fac.add(f);
f.i0=0; f.i1=4; f.i2=5; fac.add(f);
f.i0=0; f.i1=5; f.i2=6; fac.add(f);
f.i0=0; f.i1=6; f.i2=7; fac.add(f);
f.i0=0; f.i1=7; f.i2=2; fac.add(f);
// botom half
f.i0=1; f.i1=3; f.i2=2; fac.add(f);
f.i0=1; f.i1=4; f.i2=3; fac.add(f);
f.i0=1; f.i1=5; f.i2=4; fac.add(f);
f.i0=1; f.i1=6; f.i2=5; fac.add(f);
f.i0=1; f.i1=7; f.i2=6; fac.add(f);
f.i0=1; f.i1=2; f.i2=7; fac.add(f);
// subdivide triangles
for (;n>0;n--) // recursion layers
for (m=fac.num,i=0;i<m;i++)// scan through all original faces
{
g=&fac[i];
// point indexes
i0=g->i0; j0=pnt.num; // i0
i1=g->i1; j1=j0+1; // j0 j2
i2=g->i2; j2=j0+2; // i1 j1 i2
// genere mid points + sphere surface correction distance from (0,0,0) must be 1.0 (radius)
for (j=0;j<3;j++) p.p[j]=0.5*(pnt[i0].p[j]+pnt[i1].p[j]); a=1.0/sqrt((p.p[0]*p.p[0])+(p.p[1]*p.p[1])+(p.p[2]*p.p[2])); for (j=0;j<3;j++) p.p[j]*=a; pnt.add(p);
for (j=0;j<3;j++) p.p[j]=0.5*(pnt[i1].p[j]+pnt[i2].p[j]); a=1.0/sqrt((p.p[0]*p.p[0])+(p.p[1]*p.p[1])+(p.p[2]*p.p[2])); for (j=0;j<3;j++) p.p[j]*=a; pnt.add(p);
for (j=0;j<3;j++) p.p[j]=0.5*(pnt[i2].p[j]+pnt[i0].p[j]); a=1.0/sqrt((p.p[0]*p.p[0])+(p.p[1]*p.p[1])+(p.p[2]*p.p[2])); for (j=0;j<3;j++) p.p[j]*=a; pnt.add(p);
// change original fac
g->i0=j0; g->i1=j1; g->i2=j2;
// add 3 x fac
f.i0=i0; f.i1=j0; f.i2=j2; fac.add(f);
f.i0=j0; f.i1=i1; f.i2=j1; fac.add(f);
f.i0=j2; f.i1=j1; f.i2=i2; fac.add(f);
}
}
//---------------------------------------------------------------------------
Was a bit curious so I tried to encode this usage is simple:
mesh obj; // somewhere global...
obj.sphere(3); // init (call once or on change of n...)
obj.draw(); // inside your gl draw scene routine/event...
So here is the result overview
top and bottom poles looks good enough, some distortion is present along the equators but partially it can be caused also by fish-eye. If the initial shape is feed with closer to wanted result start geometry then it may have much better results
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With