23 Jun 2010 dangermaus   » (Journeyer)

Texturing a sphere in OpenGL?

I am writing a simple climate simulation which will be released soon as frontend for the Global Processing unit project.

One of the tasks is about plotting the Earth in OpenGL, for this I have bitmaps with continents, clouds, temperatures, etc, which I would like to project on the sphere.

I read through documentation on how to texture a sphere. After a while, I decide to go for this approach instead (in Freepascal, which is a phantastic Open source substitute for Delphi):

I create first a "sphere grid" in an array called sphere3d:


procedure init3DGrid(var w : TWorld; var clima : TClima);
var i, j : Longint;
    p1   :T3DPoint;
    lat, lon, altitude : Extended;
begin
 for j := 0 to 179 do
     for i := 0 to 359 do
       begin
         lat := YtoLat(j);       //-90..+90
         lon := XtoLon(i);       //-180..+180
         lat := lat/90 * Pi/2 + Pi/2; //0..180
         lon := lon/180 * Pi + Pi;  //0..360
// adding half a degree to longitude for triangles
// in each second row
         if (j mod 2 = 0) then
               lon := lon + 1/720 * 2 * Pi;
         p1.x := - radius * sin(lat) * cos(lon);
         p1.z :=   radius * sin(lat) * sin(lon);
         p1.y := - radius * cos(lat);
         sphere3D[i][j] := p1;
       end;
end;


function XtoLon(x : Longint) : Double; begin if (x<0) or (x > 359) then raise Exception.create('x on array has to be between 0 and 359 but was '+IntToStr(x)); Result := x - 180; end;

function YtoLat(y : Longint) : Double; begin if (y<0) or (y > 180) then raise Exception.create('y on array has to be between 0 and 180 but was '+IntToStr(y)); Result := 90 - y; end;

And in the Paint method of my extended TOpenGLControl I do a call to plot3d with my color bitmap and the vertex array computed in the previous procedure Init3dgrid:


procedure plot3d(vertex : P3DGrid; colors : PGridColor);
var i, j,
    target_i,
    target_j : Longint;
    p1,p2,p3,p4 : T3DPoint;
    r, g, b : Extended;
begin
  for j := 0 to 179 do
     for i := 0 to 359 do
       begin
          target_i := i+1;
          target_j := j+1;
          if (target_i>359) then target_i := target_i-359;
          if (target_j>179) then target_j := target_j-179;
          p1 := vertex^[i]  [j];
          p2 := vertex^[target_i][j];
          p3 := vertex^[i][target_j];
          p4 := vertex^[target_i][target_j];
          r := Red(colors^[i][j])/255;
          g := Green(colors^[i][j])/255;
          b := Blue(colors^[i][j])/255;
          glBegin(GL_TRIANGLES);
          glColor3f(r,g,b);
          glVertex3f( p1.x, p1.y, p1.z);              
          glVertex3f( p2.x, p2.y, p2.z);              
          glVertex3f( p3.x, p3.y, p3.z);              
          glEnd();
          glBegin(GL_TRIANGLES);
          glColor3f(r,g,b);
          glVertex3f( p2.x, p2.y, p2.z);              
          glVertex3f( p3.x, p3.y, p3.z);              
          glVertex3f( p4.x, p4.y, p4.z);              
          glEnd();
       end;
end; 

For my limited knowledge of OpenGL, this is easier to setup (and for me to understand) than loading a texture and using a cubic or cilindric projection on a sphere. The performance of this solution is also acceptable, at least for my Earth surface with 129600 (360x180*2) triangles.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!