2

Is it possible to map texture to Sphere that are generated by parametric equation and rendered using GL_POINTS primitive ? If it is possible, how is it be done and inside my code, I copy the code image loading code from the web and load it as it is instructed. One thing that I did not followed them is specifying the vertex for the texture coordinate, which I am not sure how to specify it exactly when render it with Sphere and with GL_POINTS primitive.

I am using the old OpenGL2 for my project and doing a solar system simulation

Here is the repository to the code and it is public

This is how I generate the sphere

// void Sphere::render () method, inside src/sphere.cpp - line 28

void Sphere::render () {

    unsigned int angle = 0, angle2 = 0;
    const double degree_to_rad = 3.14 / 180.0;
    double value = .0, value2 = .0;

    if ( this -> texture_file_name != "" ) {

        glEnable ( GL_TEXTURE_2D );
        glBindTexture( GL_TEXTURE_2D, this -> texture );

    }

    glBegin ( GL_POINTS );

        for ( ; angle < 360; ++ angle ) {

            value = angle * degree_to_rad;

            for ( ; angle2 < 180; ++ angle2 ) {

                value2 = angle2 * degree_to_rad;

                /*/////////////////////////////////////////////
                // do I need to do sth in here like glTexCoord2d ( ... ) ?
                ////////////////////////////////////////////*/

                glVertex3d (

                    this -> calculateX ( value, value2 ),
                    this -> calculateY ( value, value2 ),
                    this -> calculateZ ( value )

                );

            }

            angle2 = 0;

        }

    glEnd ();

    if ( this -> texture_file_name != "" ) {

        glDisable ( GL_TEXTURE_2D );

    }

};

// void Sphere::draw () method, src/sphere.cpp - line 75

void Sphere::draw () {

    glPushMatrix ();

        glTranslated (

            this -> coordinate [ 0 ],
            this -> coordinate [ 1 ],
            this -> coordinate [ 2 ]

        );

        glRotated (

            this -> angle_degree,
            this -> rotation [ 0 ],
            this -> rotation [ 1 ],
            this -> rotation [ 2 ]

        );

        this -> render ();

    glPopMatrix ();

};

double Sphere::calculateX ( const double theta_degree_angle, const double phi_degree_angle ) {

    return this -> radius * sin ( theta_degree_angle ) * cos ( phi_degree_angle );

};

double Sphere::calculateY ( const double theta_degree_angle, const double phi_degree_angle ) {

    return this -> radius * sin ( theta_degree_angle ) * sin ( phi_degree_angle );

};

double Sphere::calculateZ ( const double theta_degree_angle ) {

    return this -> radius * cos ( theta_degree_angle );

};

This is my loadTexture method

void Object::loadTexture () {

    int & w = this -> texture_width, & h = this -> texture_height;
    unsigned char * data = new unsigned char [ w * h * 3 ];
    FILE * file;

    try {

        file = fopen ( this -> texture_file_name.c_str () , "rb" );

        if ( !file ) return;

        fread ( data, w * h * 3, 1, file );
        fclose ( file );

    } catch ( std::exception & error ) {

        std::cout << "Loading Texture Error: " << error.what () << std::endl;

    }

    glGenTextures ( 1, & this -> texture );
    glBindTexture ( GL_TEXTURE_2D, this -> texture );

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data );

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );

    glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    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 );

    delete [] data;

};

void Object::setTexture ( const char * file_name, const int width, const int height ) {

    this -> texture_file_name = file_name;
    this -> texture_width = width;
    this -> texture_height = height;

    this -> loadTexture ();

};

This is my main.cpp

// main.cpp

// gloabl vars
NonStd::Sphere sun = NonStd::Sphere ( 10 );
NonStd::Sphere earth = NonStd::Sphere ( 3 );
NonStd::Sphere moon = NonStd::Sphere ( 1 );

NonStd::Object space = NonStd::Object ();

void render ();
void modelInit ();
void idle ();
void windowOnChange ( int width, int height );
void mouseOnDrag ( int x, int y );

int main ( int args_len, char ** args_context ) {

    glutInit ( &args_len, args_context );
    glutInitDisplayMode ( GLUT_SINGLE );
    glutInitWindowSize ( WINDOW_WIDTH, WINDOW_HEIGHT );
    glutInitWindowPosition ( 100, 100 );
    glutCreateWindow ( "Solar System Simulation" );

    glEnable ( GL_NORMALIZE );
    glEnable ( GL_COLOR_MATERIAL );

    // all models initialization
    modelInit ();

    // event handlers
    glutDisplayFunc ( render );
    glutReshapeFunc ( windowOnChange );
    // glutMotionFunc ( mouseOnDrag );

    // global idle func
    glutIdleFunc ( idle );

    glutMainLoop ();

    return 0;

};

void render () {

    glClearColor ( .2, .3, .5, .8 );
    glClear ( GL_COLOR_BUFFER_BIT );

    if ( sun.isObjectShown () ) {

        sun.draw ();

    }

    if ( earth.isObjectShown () ) {

        earth.draw ();

    }

    if ( moon.isObjectShown () ) {

        moon.draw ();

    }

    glFlush ();

};

void modelInit () {

    // object visibility default is false
    sun.setVisible ( true );
    // move to proper position to for object for better viewing
    sun.translateZ ( -90.0 ); 
    // set object texture
    sun.setTexture ( "resources/earth.jpg", 100, 100 );
    // spin default is false, toggle it for spinning
    sun.toggleSpin (); 

    earth.setVisible ( true );
    earth.translateZ ( -90.0 );
    earth.translateX ( 26.0 );
    earth.setTexture ( "resources/earth.jpg", 100, 100 );
    earth.toggleSpin ();
    earth.setSpinSpeed ( 2 );

    moon.setVisible ( true );
    moon.translateZ ( -90.0 );
    moon.translateX ( 20.0 );
    moon.setTexture ( "resources/earth.jpg", 100, 100 );
    moon.toggleSpin ();

};

After I set the texture on my sphere object, the sphere turn into this yellow color and before setting the texture, it was white, does this mean the texture already set but I have not yet specify the texture coordinate for it ?

FYI: The project said it is 2D, but actually I am doing it in 3D just to clarify it.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
shadowlegend
  • 373
  • 2
  • 7
  • 21
  • 1
    You have to show a minimal but complete code in the question itself. Linking to external resources should only be done as supplemental material. Also: It is very unclear what you are doing. Are the spheres itself generated by parameteric equations or is each sphere just a point? – BDL Jan 22 '18 at 11:27
  • Ok I will add that one in – shadowlegend Jan 22 '18 at 11:37
  • GL_POINTS is meant to render, well, points. What do you want to apply the texture to? What do you want to end up with? Should the points change colour, or should the sphere appear filled? – Bartek Banachewicz Jan 22 '18 at 11:47
  • @BartekBanachewicz I want my sphere to end up with, say it is an earth, so I want to map the earth texture to it – shadowlegend Jan 22 '18 at 11:56
  • @sadlife In this case I think rendering it as triangles makes more sense. And yes, you'll need texture coordinates, but it's relatively easy to generate them procedurally. Just remember that there's no easy way to map a rectangle on a sphere without causing at least some distortion. This might or might not be acceptable in your case. One of the (again, relatively) easy ways is to use cubemapping. There are numerous assets and tools online that help with cubemap generation. – Bartek Banachewicz Jan 22 '18 at 11:57
  • 1
    @BartekBanachewicz Ok, I will try render it as GL_TRIANGLE_FAN and play around with the texture coordinates – shadowlegend Jan 22 '18 at 12:01
  • Possible duplicate of [Applying map of the earth texture a Sphere](https://stackoverflow.com/questions/31799670/applying-map-of-the-earth-texture-a-sphere) – Spektre Jan 23 '18 at 07:44
  • see the linked duplicate and this: [Is it possible to make realistic n-body solar system simulation in matter of size and mass?](https://stackoverflow.com/a/28020934/2521214) might interests you too – Spektre Jan 23 '18 at 07:46

1 Answers1

0

A sphere can either be created by tessellating an existing object like a icosahedron, or by stacking discs.

Stacking discs:

Stacking discs

The following code creates a sphere by stacking up a number of discs (layers). Each layer has circumferenceTiles tiles around its circum. The U texture coordinate is wrapped arund the circum. The V texture coordinate is wrapped from the south pole to the north pole of the sphere.

void CreateSphereMesh( int layers, int circumferenceTiles, std::vector<float> &va, std::vector<int> &ia )
{
    const float pi = 3.1414927f;

    // create the vertex attributes
    va.reserve( (layers+1)*(circumferenceTiles+1)*5 );  // 5 floats: x, y, z, u, v 
    for ( int il = 0; il <= layers; ++ il )
    {
        float layer_rel = (float)il / (float)layers;
        float layer_ang = (1.0f - 2.0f * layer_rel) * pi/2.0f ;
        float layer_sin = std::sin( layer_ang );
        float layer_cos = std::cos( layer_ang );
        for ( int ic = 0; ic <= circumferenceTiles; ic ++ )
        {
            float circum_rel = (float)ic / (float)circumferenceTiles;
            float cricum_ang = circum_rel * 2.0f*pi - pi;
            float circum_sin = std::sin( cricum_ang );
            float circum_cos = std::cos( cricum_ang );

            va.push_back( layer_cos * circum_cos ); // x
            va.push_back( layer_cos * circum_sin ); // y
            va.push_back( layer_sin );              // z
            va.push_back( circum_rel );             // u
            va.push_back( 1.0f - layer_rel );       // v
        }
    }

    // create the face indices 
    ia.reserve( layers*circumferenceTiles*6 );
    for ( int il = 0; il < layers; ++ il )
    {
        for ( int ic = 0; ic < circumferenceTiles; ic ++ )
        {
          int i0 = il * (circumferenceTiles+1) + ic;
          int i1 = i0 + 1;
          int i3 = i0 + circumferenceTiles+1;
          int i2 = i3 + 1;

          int faces[]{ i0, i1, i2, i0, i2, i3 };
          ia.insert(ia.end(), faces+(il==0?3:0), faces+(il==layers-1?3:6));
        }
    }
}


An vertex array object for the fixed function pipline can be specified like this:

GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );

GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, va.size()*sizeof(*va.data()), va.data(), GL_STATIC_DRAW );

GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, ia.size()*sizeof(*ia.data()), ia.data(), GL_STATIC_DRAW );

glVertexPointer( 3, GL_FLOAT, 5*sizeof(*va.data()), 0 );
glEnableClientState( GL_VERTEX_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );

glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

For modern OpenGL the generic vertex attribute data arrays have to be defined like this:

GLint avert_loc = ....;
GLint atexc_loc = ....;
glVertexAttribPointer( avert_loc, 3, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), 0 );
glEnableVertexAttribArray( avert_loc );
glVertexAttribPointer( atexc_loc, 2, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data()))  );
glEnableVertexAttribArray( atexc_loc );

Finall the drawing operation:

glEnable( GL_TEXTURE_2D ); // for fixed function pipeline only
glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)ia.size(), GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );

Preview:

Preview

Rabbid76
  • 202,892
  • 27
  • 131
  • 174