Spherical Mesh.
Hi !
For my next openGL hurdle, I'm making the jump to 3 dimensional and pseudo-3D graphics. For now, all I need the game to be able to draw is texture-mapped planes and spheres, the former of which I can handle without trouble.
Anyways, whipping out my first-second year calculus book, I found the section on spherical coordinates (who knew polar coordinates would ACTUALLY be practical).
I came up with the following code for initializing a quadrilateral mesh for a sphere. Keep in mind I want the spheres in my game to appear as rounded as possible. This one has 36*16 + 2 vertices = 578 vertices. I'm not sure how to convert that to "number of polygons," but I know there's a simple formula out there.
Initialization code:
so what I do is set the sphere's bottom and top "axis" points, or north and south points as I call them. Then at ten degree increments, I set the appropriate 3 dimensional pixel coordinates.
for drawing, I'm thinking I should first draw triangles from the north and south points to their respective "nearest meridians," then take all (map_x, map_y) points up to the second last, and draw quadrilaterals at indexes (map_x, map_y) = {(x,y); (x+1,y); (x,y+1); (x+1,y+1)}.
I haven't yet tested this, and I'm afraid to because I expect there is something fundamentally wrong with my approach. Any suggestions / criticism and / or sample code are greatly appreciated!
For my next openGL hurdle, I'm making the jump to 3 dimensional and pseudo-3D graphics. For now, all I need the game to be able to draw is texture-mapped planes and spheres, the former of which I can handle without trouble.
Anyways, whipping out my first-second year calculus book, I found the section on spherical coordinates (who knew polar coordinates would ACTUALLY be practical).
I came up with the following code for initializing a quadrilateral mesh for a sphere. Keep in mind I want the spheres in my game to appear as rounded as possible. This one has 36*16 + 2 vertices = 578 vertices. I'm not sure how to convert that to "number of polygons," but I know there's a simple formula out there.
Initialization code:
Code:
#define kZAngleConstant -80
#define kXAngleConstant 0
#define kZAngleIncrementPerIndex 10.00f
#define kXAngleIncrementPerIndex 10.00f
void SphereMap_Init (void)
{
int map_x, map_y;
GLfloat phi, theta, r;
r = 1.0f;
pm.south_Pt.x =
pm.south_Pt.y = 0;
pm.south_Pt.z = -1.0f;
pm.south_Pt.x =
pm.south_Pt.y = 0;
pm.south_Pt.z = 1.0f;
for (map_y = 0; map_y < kSphereMap_Height; map_y ++) {
// -80 deg <= phi <= 80 deg
phi = kZAngleConstant + kZAngleIncrementPerIndex * map_y;
for (map_x = 0; map_x < kSphereMap_Width; map_x ++) {
// 0 deg <= theta <= 350 deg
theta = kXAngleConstant + kXAngleIncrementPerIndex * map_x;
pm.texMap_pt [map_x][map_y].x = r * sin(phi) * cos(theta);
pm.texMap_pt [map_x][map_y].y = r * sin(phi) * sin(theta);
pm.texMap_pt [map_x][map_y].z = r * cos(phi);
} // set appropriate vertices
}
}so what I do is set the sphere's bottom and top "axis" points, or north and south points as I call them. Then at ten degree increments, I set the appropriate 3 dimensional pixel coordinates.
for drawing, I'm thinking I should first draw triangles from the north and south points to their respective "nearest meridians," then take all (map_x, map_y) points up to the second last, and draw quadrilaterals at indexes (map_x, map_y) = {(x,y); (x+1,y); (x,y+1); (x+1,y+1)}.
I haven't yet tested this, and I'm afraid to because I expect there is something fundamentally wrong with my approach. Any suggestions / criticism and / or sample code are greatly appreciated!
gluSphere?
"Yes, well, that's the sort of blinkered, Philistine pig-ignorance I've come to expect from you non-creative garbage."
Code:
pm.south_Pt.x = // Theres no value here, and no semi colon.
pm.south_Pt.y = 0;
pm.south_Pt.z = -1.0f;
pm.south_Pt.x =
pm.south_Pt.y = 0;
pm.south_Pt.z = 1.0f; // You just set this to -1?!?!?Code:
pm.texMap_pt [map_x][map_y].x = r * sin(phi) * cos(theta);
pm.texMap_pt [map_x][map_y].y = r * sin(phi) * sin(theta);
pm.texMap_pt [map_x][map_y].z = r * cos(phi);Code:
for (map_x = 0; map_x < kSphereMap_Width; map_x ++) {
// 0 deg <= theta <= 350 deg
theta = kXAngleConstant + kXAngleIncrementPerIndex * map_x;Code:
for (theta = 0; theta <= 350; theta += 360/N_slices) {Code:
glTexCoord2f(theta, phi); glVertex3f(.....);Sir, e^iπ + 1 = 0, hence God exists; reply!
This is my code for defining a spherical mesh. Note I define three new vertices for each triangle in the mesh. It would be nicer to define each vertex once and just assign vertex indices to the triangles.
Code:
int i,j;
float vert1[3], vert2[3], vert3[3];
float theta1,theta2,phi1,phi2,dtheta,dphi;
dtheta = PI/((float)Ntheta+1);
dphi = 2.0*PI/((float)Nphi);
/* top cap triangles */
for (j=0; j<Nphi; j++) {
vert1[0] = 0.0;
vert1[1] = 0.0;
vert1[2] = radius;
vert2[0] = radius*sin(dtheta)*cos(j*dphi);
vert2[1] = radius*sin(dtheta)*sin(j*dphi);
vert2[2] = radius*cos(dtheta);
vert3[0] = radius*sin(dtheta)*cos((j+1)*dphi);
vert3[1] = radius*sin(dtheta)*sin((j+1)*dphi);
vert3[2] = radius*cos(dtheta);
}
/* bottom cap triangles */
for (j=0; j<Nphi; j++) {
vert1[0] = 0.0;
vert1[1] = 0.0;
vert1[2] = -radius;
vert2[0] = radius*sin(PI-dtheta)*cos(j*dphi);
vert2[1] = radius*sin(PI-dtheta)*sin(j*dphi);
vert2[2] = radius*cos(PI-dtheta);
vert3[0] = radius*sin(PI-dtheta)*cos((j+1)*dphi);
vert3[1] = radius*sin(PI-dtheta)*sin((j+1)*dphi);
vert3[2] = radius*cos(PI-dtheta);
}
/* bulk of sphere */
for (i=1; i<Ntheta+1; i++) {
for (j=0; j<Nphi; j++) {
theta1 = (float)i*dtheta;
phi1 = (float)j*dphi;
theta2 = (float)(i+1)*dtheta;
phi2 = (float)(j+1)*dphi;
/* triangle 1 */
vert1[0] = radius*sin(theta1)*cos(phi1);
vert1[1] = radius*sin(theta1)*sin(phi1);
vert1[2] = radius*cos(theta1);
vert2[0] = radius*sin(theta2)*cos(phi1);
vert2[1] = radius*sin(theta2)*sin(phi1);
vert2[2] = radius*cos(theta2);
vert3[0] = radius*sin(theta2)*cos(phi2);
vert3[1] = radius*sin(theta2)*sin(phi2);
vert3[2] = radius*cos(theta2);
/* triangle 2 */
vert1[0] = radius*sin(theta1)*cos(phi1);
vert1[1] = radius*sin(theta1)*sin(phi1);
vert1[2] = radius*cos(theta1);
vert2[0] = radius*sin(theta2)*cos(phi2);
vert2[1] = radius*sin(theta2)*sin(phi2);
vert2[2] = radius*cos(theta2);
vert3[0] = radius*sin(theta1)*cos(phi2);
vert3[1] = radius*sin(theta1)*sin(phi2);
vert3[2] = radius*cos(theta1);
}
}
Recursive subdivision of an isocahedron works beautifully -- plus you get even distribution of identically sized triangles. No loss of precision as you approach the poles.
It's in _The Red Book_ but I can post code if you're interested.
It's in _The Red Book_ but I can post code if you're interested.
Along the lines of making spheres, can someone help me identify what PID2 means in the following code? I figure TWOPI is simply 2 * M_PI, but PID2 still gets me. I know this isn't an efficient way of making spheres (unless calling it in a display list and using that), but I just want to make a sphere. I've identified where the PID2 shows up using a <------- after the line. This might also help Dave out with figuring out if his code will work by comparing it to this (though I can't be sure this works until I figure out that PID2 variable).
http://astronomy.swin.edu.au/~pbourke/opengl/sphere/ Wrote:Code:
/*
Create a sphere centered at c, with radius r, and precision n
Draw a point for zero radius spheres
*/
void CreateSphere(XYZ c,double r,int n)
{
int i,j;
double theta1,theta2,theta3;
XYZ e,p;
if (r < 0)
r = -r;
if (n < 0)
n = -n;
if (n < 4 || r <= 0) {
glBegin(GL_POINTS);
glVertex3f(c.x,c.y,c.z);
glEnd();
return;
}
for (j=0;j<n/2;j++) {
theta1 = j * TWOPI / n - PID2; <-------
theta2 = (j + 1) * TWOPI / n - PID2; <-------
glBegin(GL_QUAD_STRIP);
for (i=0;i<=n;i++) {
theta3 = i * TWOPI / n;
e.x = cos(theta2) * cos(theta3);
e.y = sin(theta2);
e.z = cos(theta2) * sin(theta3);
p.x = c.x + r * e.x;
p.y = c.y + r * e.y;
p.z = c.z + r * e.z;
glNormal3f(e.x,e.y,e.z);
glTexCoord2f(i/(double)n,2*(j+1)/(double)n);
glVertex3f(p.x,p.y,p.z);
e.x = cos(theta1) * cos(theta3);
e.y = sin(theta1);
e.z = cos(theta1) * sin(theta3);
p.x = c.x + r * e.x;
p.y = c.y + r * e.y;
p.z = c.z + r * e.z;
glNormal3f(e.x,e.y,e.z);
glTexCoord2f(i/(double)n,2*j/(double)n);
glVertex3f(p.x,p.y,p.z);
}
glEnd();
}
}
Perhaps PI divided by two? See if you can't find where PID2 is defined...
Anyhow, here's how I do it ( I store it in a display list, since the actual generation is recursive and can't take advantage of triangle strips ):
And to actually make it happen:
Disregard the texture stuff...
Anyhow, here's how I do it ( I store it in a display list, since the actual generation is recursive and can't take advantage of triangle strips ):
Code:
/*
X, Z, vdata, tindices -- initial data set for isocahedron -- subdivision will
allow for arbitrarily detailed sphere
BarrelTexCoord{XAxis|ZAxis|YAxis } Texture coordinate generation for barrel wrap
over sphere, along specified axis.
*/
#define X .525731112119133606
#define Z .850650808352039932
static float vdata[12][3] = {
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
{0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
{Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
};
static GLint tindices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11}
};
void SphereGeometry::subdivide(float *v1, float *v2, float *v3, long depth)
{
float v12[3], v23[3], v31[3];
if (depth == 0)
{
vec3 a, b, c;
vec3 n0, n1, n2;
a.x = _radius * v1[0];
a.y = _radius * v1[1];
a.z = _radius * v1[2];
b.x = _radius * v2[0];
b.y = _radius * v2[1];
b.z = _radius * v2[2];
c.x = _radius * v3[0];
c.y = _radius * v3[1];
c.z = _radius * v3[2];
n0.x = a.x;
n0.y = a.y;
n0.z = a.z;
n1.x = b.x;
n1.y = b.y;
n1.z = b.z;
n2.x = c.x;
n2.y = c.y;
n2.z = c.z;
vec2 ta, tb, tc;
switch( textureCoordGeneration() )
{
case Barrel_X:
BarrelTexCoordXAxis( c, b, a, _radius, tc, tb, ta );
break;
case Barrel_Y:
BarrelTexCoordYAxis( c, b, a, _radius, tc, tb, ta );
break;
case Barrel_Z:
BarrelTexCoordZAxis( c, b, a, _radius, tc, tb, ta );
break;
default:
/*
Not a recognized texgen, so just pump the triangle and
get out of here -- note the Bad Form of a return in a switch
*/
triangle( c, b, a, n2, n1, n0 );
return;
}
TriangleTexture tex( tc, tb, ta );
triangle( c, b, a, n2, n1, n0, NULL, &tex );
return;
}
for ( int i = 0; i < 3; i++)
{
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
subdivide(v1, v12, v31, depth-1 );
subdivide(v2, v23, v12, depth-1 );
subdivide(v3, v31, v23, depth-1 );
subdivide(v12, v23, v31, depth-1 );
}And to actually make it happen:
Code:
int depth = 2;
for ( int i = 0; i < 20; i++)
{
subdivide( &vdata[tindices[i][0]][0],
&vdata[tindices[i][1]][0],
&vdata[tindices[i][2]][0],
depth );
}Disregard the texture stuff...
It is indeed M_PI / 2. It's used to adjust the texture as the way the code does it results in the poles being around the equator. By subtracting pi/2 it fixes this problem. That code I posted does in fact work now that I know that. Thanks.
Hi TomorrowPlusX.
I too am trying to get up the steep learning curve of OpenGL ES for iPhone development.
I'm embarrassed to say I have little Objective-C experience too.
My first step is to create a rotating smooth sphere (subdivided icosahedron) with a tennis-ball texture and then build from there. I can get an icosahedron to rotate, but I'm stumped when it comes to 1) subdividing it to smooth it out, and then assuming I can get it to appear 2) apply a texture to it.
I'm pulling my hair out trying to get your code to work - I just get a black screen when trying to subdivide!
Could you please provide the rest of your code? (*.h)
I too am trying to get up the steep learning curve of OpenGL ES for iPhone development.
I'm embarrassed to say I have little Objective-C experience too.
My first step is to create a rotating smooth sphere (subdivided icosahedron) with a tennis-ball texture and then build from there. I can get an icosahedron to rotate, but I'm stumped when it comes to 1) subdividing it to smooth it out, and then assuming I can get it to appear 2) apply a texture to it.
I'm pulling my hair out trying to get your code to work - I just get a black screen when trying to subdivide!
Could you please provide the rest of your code? (*.h)
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| how to create a grid / 2D mesh | bfarah | 1 | 3,154 |
Oct 20, 2010 02:22 AM Last Post: iamflimflam1 |
|
| Boolean Mesh Operations and Mesh-Based CSG | Oddity007 | 2 | 4,800 |
Feb 13, 2010 03:42 PM Last Post: Oddity007 |
|
| OpenGL ES creating a 2D mesh | soulstorm | 0 | 2,425 |
May 20, 2009 02:37 AM Last Post: soulstorm |
|
| Breaking down a concave mesh into convex pieces | Willem | 5 | 3,914 |
Aug 10, 2008 05:49 AM Last Post: Willem |
|
| Mesh Subdivisions | KiroNeem | 0 | 3,179 |
Dec 29, 2005 04:13 PM Last Post: KiroNeem |
|

