First you need to chose topology of your grid. I see it like this:

Yellow indexes are intersection points on grid and Aqua indexes are individual triangles of the grid. So define basis vectors u,v,w describing 3 possible directions of the grid and then just transform grid point position yellow (i,j) into (x,y). That can be used to form triangles using aqua triangle index parity (even/odd) of each index (4 possible cases) to compute its 3 yellow point indexes ... Here small C++/OpenGL 2D example rendering 2n+1 x 2n+1 triangles grid:
//---------------------------------------------------------------------------
void get_hexpoint(double *p,int i,int j) // i,j yellow
{
static const double deg=M_PI/180.0; // deg -> rad
static const double u[2]={+cos(30.0*deg),-sin(30.0*deg)};
static const double v[2]={+cos(30.0*deg),+sin(30.0*deg)};
static const double w[2]={ 0.0 , +1.0 };
double ii=i,jj=j;
for (i=0;i<2;i++) p[i]=0.0;
for (i=0;i<2;i++) p[i]+=(ii*u[i])+(jj*w[i]);
}
//---------------------------------------------------------------------------
void get_hextriangle(double *p0,double *p1,double *p2,int i,int j) // i,j aqua
{
if (int(j&1)==0)
{
j=(j>>1)+(i>>1);
if (int(i&1)==0)
{
get_hexpoint(p0,i,j);
get_hexpoint(p1,i+1,j);
get_hexpoint(p2,i+1,j+1);
}
else{
get_hexpoint(p0,i,j);
get_hexpoint(p1,i,j+1);
get_hexpoint(p2,i+1,j+1);
}
}
else{
j=(j>>1)+(i>>1);
if (int(i&1)==0)
{
get_hexpoint(p0,i,j);
get_hexpoint(p1,i+1,j+1);
get_hexpoint(p2,i,j+1);
}
else{
j++;
get_hexpoint(p0,i,j);
get_hexpoint(p1,i+1,j);
get_hexpoint(p2,i+1,j+1);
}
}
}
//---------------------------------------------------------------------------
void TMain::draw()
{
scr.cls();
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(0.2,0.2,1.0);
int i,j,n=10;
double p0[2],p1[2],p2[2];
glLineWidth(3);
for (i=-n;i<=+n;i++)
for (j=-n;j<=+n;j++)
{
get_hextriangle(p0,p1,p2,i,j);
glColor3f(0.2,0.2,0.2);
glBegin(GL_TRIANGLES);
glVertex2dv(p0);
glVertex2dv(p1);
glVertex2dv(p2);
glEnd();
glColor3f(1.0,1.0,1.0);
glBegin(GL_LINE_LOOP);
glVertex2dv(p0);
glVertex2dv(p1);
glVertex2dv(p2);
glEnd();
}
glLineWidth(1);
scr.exe();
scr.rfs();
}
//---------------------------------------------------------------------------
And here the output:

Note that the 4 cases branches might be converted to brunch-less code by changing the logic a bit moving the if statements to point index deltas or by using LUTs... but I am too lazy to do that.