0
\$\begingroup\$

For a project of mine, I need to render spheres without loading a pre-made model or using built-in functions.

I found this bit of code on the internet that seems to work but I really want to understand what is going on for future reference or in case I want to use this again but modify a few things.

This is the code snippet that's specific to this question:

int i, j;
std::vector<GLfloat> vertices;
std::vector<GLuint> indices;
int indicator = 0;
for(i = 0; i <= lats; i++) {
   double lat0 = glm::pi<double>() * (-0.5 + (double) (i - 1) / lats);
   double z0  = sin(lat0);
   double zr0 =  cos(lat0);

   double lat1 = glm::pi<double>() * (-0.5 + (double) i / lats);
   double z1 = sin(lat1);
   double zr1 = cos(lat1);

   for(j = 0; j <= longs; j++) {
       double lng = 2 * glm::pi<double>() * (double) (j - 1) / longs;
       double x = cos(lng);
       double y = sin(lng);

       vertices.push_back(x * zr0);
       vertices.push_back(y * zr0);
       vertices.push_back(z0);
       indices.push_back(indicator);
       indicator++;

       vertices.push_back(x * zr1);
       vertices.push_back(y * zr1);
       vertices.push_back(z1);
       indices.push_back(indicator);
       indicator++;
   }
   indices.push_back(GL_PRIMITIVE_RESTART_FIXED_INDEX);
}

The main part that is confusing me is the math with the lng lat and x y and z variables. Any help would be greatly appreciated.

\$\endgroup\$
6
  • \$\begingroup\$ Do you mean the math to take a point in spherical coordinates (latitude and longitude, optionally radius) and convert it to a point in cartesian coordinates (x y z)? This is covered in lots of existing docs, like the Wikipedia page I linked above and previous Q&A, so answers might just re-hash the same content as hits you've already found in your search. To help focus answers on what you need help understanding, can you explain in more detail what parts are confusing? \$\endgroup\$
    – DMGregory
    Feb 16, 2023 at 16:59
  • \$\begingroup\$ The part that confuses me is the math behind the lat x y and z variables. The code doesn't have any explanation of the math that it's using so I want the math in the for loops explained so I could reproduce similar results on my own \$\endgroup\$
    – Chillzy
    Feb 16, 2023 at 17:02
  • \$\begingroup\$ Right, that's the standard spherical coordinate conversion math, explained in the link above, and lots of other places on the web. Where do you get lost trying to follow these explanations? The better we can understand what's not clicking, the better we can focus our answers to help you. \$\endgroup\$
    – DMGregory
    Feb 16, 2023 at 17:05
  • \$\begingroup\$ Ok well I'll check the article out and let you know if it cleared my confusion up \$\endgroup\$
    – Chillzy
    Feb 16, 2023 at 17:07
  • \$\begingroup\$ Yeahhh so I checked out the article you recommended and a few other ones and still don't understand all the math involved, because I'm to everyone's surprise, not a math major and there are too many different symbols and angles and what not, all I know is I only have a high school knowledge of math and not a math 55 level, so, from here, I'ma just "borrow" bits of code from people older and smarter than me, thanks for clearing up a few points though \$\endgroup\$
    – Chillzy
    Feb 16, 2023 at 17:23

1 Answer 1

0
\$\begingroup\$

The code produces quads that approximate the surface of a sphere.

longs and lats are the number of subdivisions of the circles on their respective axes.

For a globe with 10 degree longitudinal lines the value of longs would be:

longs = 360 / 10; // == 36 

The actual number does not matter to the calculations, just an easy value to demonstrate. Higher values better approximate a sphere at the cost of performance.

With vertex normals, and the shader to support normals, 8 to 20 would be the usual range. Without normals, much higher values(< 100) are needed, depending on number, scale, distance and target platform performance constraints.

Longitude and Lng

Let us start in the second loop and work backwards:

The following line calculates each angle 360 / (-1 to 35) (-10,0,10,...,340,350) in radians(a fraction of 2*PI instead of 360.) Note that -10 == 350 in angles, thus closing the circle.

double lng = 2 * glm::pi<double>() * (double) (j - 1) / longs;

X and Y initial values

These values are based on the equatorial axis.

double x = cos(lng);
double y = sin(lng);

x and y are the coordinates of the point on the circle at the equator of the sphere.

For uniform scaling purposes by radius r, these are part of the lines to change to:

double x = r * cos(lng);
double y = r * sin(lng);
// The Z still needs to be scaled.

Lats and Z

The circles described in this section are polar aligned.

The analysis given above for longs applies to lats with a few differences:

The circle is broken up into 2 parts, one following the other(i and i-1), to allow for the surface to be created across the span.

The following code calculates the radius of the Z (polar) aligned circular component. The XY axis scaling adjustment from the Equator for the Z component of the sphere.

double zr0 =  cos(lat0);

zr1 is the same, only for the next slice.

So:

vertices.push_back(x * zr0); //Apply the Z circular scale from the Equator to the x axis.
vertices.push_back(y * zr0);//Apply the Z circular scale from the Equator to the y axis.

To complete the uniform scaling example

vertices.push_back(z0 * r);
///...
vertices.push_back(z1 * r);

For non-uniform scaling(ellipsoid), the value of r(xyz) is based on the axis it is multiplied against, with 2 multiplies of the same value for Z(z0 and z1).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .