Modelling the earth

Hello,

i am trying to model the Earth. i am using a .bmp file that consists of the image of the earth, which i am applying onto the
surface of the sphere.

i tried two methods:

  1. Just plot each vertex on the sphere using the pixel values.
    X_SIZE, Y_SIZE are the width and height of the image.

double x, y, z;	
int i = 0, j = 0;

for (double theta = 0; theta <= 360.0; theta += (360.0 / X_SIZE)) {		
	for (double phi = -90; phi <= 90.0; phi += (180.0 / Y_SIZE)) {
		x = sin((3.14 / 180) * theta) * cos((3.14 / 180) * phi);
		y = cos((3.14 / 180) * theta) * cos((3.14 / 180) * phi);
		z = sin((3.14 / 180) * phi);
						
		glColor3d(buff1[j+2] / 255.0, buff1[j+1] / 255.0, buff1[j+2] / 255.0);
                // buff has the raw pixel data
		glPointSize(2);
		glBegin(GL_POINTS);
			glVertex3d(x, y, z);
		glEnd();			
	}
}
	
  1. A texture based method. The sphere is approximated using triangles. i found this on the internet.

TWOPI = 2 * 3.14 and PID2 = 3.14 / 2


   // some texture initializations here.
  gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
		               GL_BGR_EXT, GL_UNSIGNED_BYTE, buff );

   // buff has the raw pixel data

   int i,j;
   double theta1,theta2,theta3;
   XYZ e,p;

   /* XYZ is a tydefed struct:
      typedef struct {
            double x;
            double y;
            double z;
      }
   */  
   

   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();
   }

Now, i find both methods the same as far as the performance is concerned. But, shouldn’t the texture based method be more efficient?

Can anyone please comment as to which method is better and why isn’t there any observable difference in the performance?

It is quite obvious why both methods are slow.
You have a plenty of trigonometric functions in each vertex drawing, and also to many function calls (using immediate mode drawing). My advice is to calculate vertex-positions just once, and store them into VBO (or VA).

Reading the title, I thought you were about to render real model of Earth. But I was wrong. Believe me, rendering Earth is much much complicated than drawing a sphere with the texture. :slight_smile:

Thanks for the reply Aleksandar. Hmm, i did not quite get the second part of the reply. What did you mean by real model of the earth? Did you mean the entire earth with topography data (as in mountains etc)?

Yes, I meant something like Google Earth. :slight_smile:
In that case there are so many problems to be solved.

Ah, why don’t you just import some model with texture coordinates already present, so you won’t need to calculate them. It’ll be faster I bet.

@Aleksandar

Yeah that would be pretty complicated. :slight_smile:

@ugluk

Nice idea, well instead of searching for one model, i though i can create a file myself having those coordinates, then read them in the program and display, rather than calculating the coordinates each time.

Nice idea, i will try it out.

@ugluk

i tried the method suggested by you.
This is what i did:

File that has the pre-calculated data:


void CreateSphereFile(XYZ c,double r,int n)
{
   FILE *fp = fopen("file_data", "wb");
   int i,j;
   double theta1,theta2,theta3;
   XYZ e,p;
   

   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;

        // Data1
	fwrite(&e, 8, 3, fp);
	fwrite(&p, 8, 3, fp);
	
        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;

	fwrite(&e, 8, 3, fp);
        fwrite(&p, 8, 3, fp);
       
      }
   }
 //   finish writing 
   fclose(fp);
}

Now read contents into a vector:

void CreateSphereFileRead()
{
   FILE *fp = fopen("file_data", "rb");
   int i,j, n = 50;
   double theta1,theta2,theta3;  
   Data temp;
   
   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;     
         
	 // read 12 elements
	fread(&temp, 8, 12, fp); 

        // push it into the vector 
	file_data.push_back(temp);
      }
      glEnd();
   }
   fclose(fp);
}

file_data is a global vector:

typedef struct {
	double data1;
	double data2;
	double data3;
	double data4;
	double data5;
	double data6;
	double data7;
	double data8;
	double data9;
	double data10;
	double data11;
	double data12;
} Data;
std :: vector<Data> file_data;

This is where the sphere is drawn:

void CreateSphereRender()
{
  
   int i,j, count, n = 50;
   double theta1,theta2,theta3; 

   for (j=0, count = 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;
	
         glNormal3f(file_data[count].data1, file_data[count].data2, file_data[count].data3);
         glTexCoord2f(i/(double)n, 2 * (j+1)/(double)n);
         
	glVertex3f(file_data[count].data4, file_data[count].data5, file_data[count].data6);
		
        glNormal3f(file_data[count].data7, file_data[count].data8, file_data[count].data9);
        glTexCoord2f(i/(double)n,2*j/(double)n);
		
        glVertex3f(file_data[count].data10, file_data[count].data11, file_data[count].data12);

	// cout << "
" << file_data[count].data1; 	
		count++;
      }
      glEnd();
   }
}

So, the only calculations done are some simple division and multiplications.

But the performance still remains the same.

i read the file and created the vector only once. So, after that it is just reading from the vector, but why is it still slow?

Any suggestions?

You have a plenty of trigonometric functions in each vertex drawing, and also to many function calls (using immediate mode drawing). My advice is to calculate vertex-positions just once, and store them into VBO (or VA).

You did the first part.
Do the second, and it should be better.

With your current implementation, is it faster if the window is small ? In this case you are limited by rendering, and you will need other solutions to make it faster.

Thanks for the reply ZBuffer. Yes, indeed. The performance is really good on small windows.

i am rotating the sphere. It rotates pretty fast on 200x200 window.

But becomes really slow on a 700x700 one.

How can i solve this?

Some graphics cards don’t like quads, even quad strips. I’d convert them to triangles or tristrips first. Then I’d upload them to a VBO and use that for rendering.

Ugluk, it is unlikely the primitive has an effect on rasterization speed.

What about the texture ?
Resolution, POT, filtering method ? Depending on the card it can be slow. And what is your 3d card by the way ?

@ZBuffer

Well, i do not have an external graphics card. Onboard graphics memory of 128MB and i have 1GB RAM.

The texture resolution is 256x256 (.bmp file)

Could this affect the speed by a large extent?

The only way to find out is to bench. Maybe you can resize the 256x256 down to 128x128 or somesuch and see?

Well, i do not have an external graphics card. Onboard graphics memory of 128MB and i have 1GB RAM.

External or integrated, your GPU must have a name. What is it? Are you sure you’re getting an accelerated rendering context? What do you get when you call glGetString(GL_RENDERER)?

@Alfonse Reinheart

glGetString(GL_RENDERER) is returning “GDI Generic”. Please excuse me if this sounds trivial, but i did not understand what you meant by “accelerated rendering context”.

@ugluk

Yes, i tried that, it seems to be a little faster now :). Thanks.

Also, i am having a little problem with the mapping. The texture on the surface of the sphere seems to flip suddenly.

i have attached the entire code in a .txt file.
i could not attach a .bmp file using the file manager, so i just renamed the .bmp extension to .jpg

Please change the extension before reading the file from the program.

There seemed to be a problem downloading the txt file.
The entire code:


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <math.h>
#include <vector>
#include <iostream>
#include <GL/glut.h>

using namespace std;

#define FILENAME "et.bmp"
#define TWOPI 6.2831
#define PID2  1.57079

typedef struct XYZ {
	double x; 
	double y; 
	double z;
} XYZ;

XYZ c = {0, 0, 0};

void  CreateSphereRender();void CreateSphere1(XYZ c,double r,int n);
void CreateSphereFile(XYZ, double, int);
void  CreateSphereFileRead();
void init();

typedef struct {
	double data1;
	double data2;
	double data3;
	double data4;
	double data5;
	double data6;
	double data7;
	double data8;
	double data9;
	double data10;
	double data11;
	double data12;
} Data;
std :: vector<Data> file_data;
		
unsigned char buff[256 * 256 * 3];
unsigned char arr[100];


void init(void) 
{
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel (GL_FLAT);
   glEnable( GL_TEXTURE_2D );
}

void display(void)
{
   FILE *fp;
   cout  << glGetString(GL_RENDERER);

   glClearColor (0.0, 0.0, 0.0, 0.0);
   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
   glFlush();
	
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity();   
   glFrustum(-2, 2, -2, 2, 2, 10);	


   	fp = fopen(FILENAME, "rb");
	fread(arr, 1, 54, fp);	
	fread(buff, 1, 256 * 256 * 3, fp);

	GLuint texture;
	
	glGenTextures( 1, &texture );
	
	// select texture
	glBindTexture( GL_TEXTURE_2D, texture );

	
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

	
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
		             GL_LINEAR_MIPMAP_NEAREST );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );	
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

	int width, height;

	// texture width and height
	width  = 256;
	height = 256;

	gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
		               GL_BGR_EXT, GL_UNSIGNED_BYTE, buff );

   CreateSphereFile(c, 1.5, 50);
   CreateSphereFileRead();

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0);	 	
  
   // keep rotating.
   for (int i = 0; ; ) {        
	    glPushMatrix();	
		 glTranslatef(1.5, 0, 0);
		 glRotatef((i += 10) % 360, 1, 1, 1);
		 CreateSphereRender();
		glPopMatrix();
		
		glutSwapBuffers();		

		Sleep(100);
		glClear (GL_COLOR_BUFFER_BIT); 		
   }
		  
}

void CreateSphereFile(XYZ c,double r,int n)
{
   FILE *fp = fopen("file_data", "wb");
   int i,j;
   double theta1,theta2,theta3;
   XYZ e,p;
   

   for (j=0;j<n/2;j++) {
      theta1 = j * TWOPI / n - PID2;
      theta2 = (j + 1) * TWOPI / n - PID2;
    
      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;
		
		 fwrite(&e, 8, 3, fp);
		 fwrite(&p, 8, 3, fp);		

         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;
		
		 fwrite(&e, 8, 3, fp);		
		 fwrite(&p, 8, 3, fp);
       
      }     
   }
   fclose(fp);
}


void CreateSphereFileRead()
{
   FILE *fp = fopen("file_data", "rb");
   int i,j, n = 50;
   double theta1,theta2,theta3;  
   Data temp;
   

   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;     
         
		 // read 12 elements
		 fread(&temp, 8, 12, fp); 

		 file_data.push_back(temp);
      }
      glEnd();
   }
   fclose(fp);
}

void CreateSphereRender()
{
  
   int i,j, count, n = 50;
   double theta1,theta2,theta3;  
	
   for (j=0, count = 0; j < n / 2; j++) {
      theta1 = j * TWOPI / n - PID2;
      theta2 = (j + 1) * TWOPI / n - PID2;

      glBegin(GL_TRIANGLE_STRIP);
      for (i=0;i<=n;i++) {
         theta3 = i * TWOPI / n;
	
		 glNormal3f(file_data[count].data1, file_data[count].data2, file_data[count].data3);
         glTexCoord2f(i/(double)n, 2 * (j+1)/(double)n);
         
		 glVertex3f(file_data[count].data4, file_data[count].data5, file_data[count].data6);
		
         glNormal3f(file_data[count].data7, file_data[count].data8, file_data[count].data9);
         glTexCoord2f(i/(double)n,2*j/(double)n);
		
         glVertex3f(file_data[count].data10, file_data[count].data11, file_data[count].data12);

		count++;
      }
      glEnd();
   }
}

int main(int argc, char** argv)
{	   
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glEnable(GL_DEPTH_TEST);
   
   glutInitWindowSize (400, 400); 
   glutCreateWindow (argv[0]);
   
   init (); 

   glutDisplayFunc(display);   

   glutMainLoop();
   return 0;
}

Any idea where i am going wrong?

“GDI Generic” means you use OpenGL in software mode, running only on your CPU, without taking advantage of any hardware. So it is normal you get crappy performance.
Try with this instead of LINEAR :
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Should be almost usable.

Anyway, to fix the real problem, you should find what is your integrated graphic chip, and install its drivers.

Even lowest intel chips should render a textured sphere on a small window with adequate performance.

If you have an Intel chip, then it’s Open GL support is problematic. The “GDI generic” thing solves the mystery.

@Aleksandar, ugluk, Alfonse Reinheart, ZbuffeR

Thanks a lot for the support. This thread was really helpful. :slight_smile:

@ugluk

Yes, it is an Intel Chip.