Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
725 views
in Technique[技术] by (71.8m points)

c++ - How to map texture to sphere that rendered by parametric equation using points primitive

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...