简体   繁体   English

如何使用点基元将纹理映射到由参数方程渲染的球体

[英]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 ?是否可以将纹理映射到由参数方程生成并使用 GL_POINTS 基元渲染的球体? 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.我没有遵循的一件事是指定纹理坐标的顶点,我不确定在使用 Sphere 和 GL_POINTS 基元渲染时如何准确指定它。

I am using the old OpenGL2 for my project and doing a solar system simulation我正在为我的项目使用旧的 OpenGL2 并进行太阳系模拟

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这是我的 loadTexture 方法

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

// 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.仅供参考:该项目说它是 2D 的,但实际上我在 3D 中做它只是为了澄清它。

A sphere can either be created by tessellating an existing object like a icosahedron, or by stacking discs.球体既可以通过细分现有对象(如二十面体)来创建,也可以通过堆叠圆盘来创建。

Stacking discs:堆叠盘:

堆叠盘

The following code creates a sphere by stacking up a number of discs ( layers ).以下代码通过堆叠多个圆盘( layers )来创建一个球体。 Each layer has circumferenceTiles tiles around its circum.每一层都有circumferenceTiles围绕其circum瓷砖。 The U texture coordinate is wrapped arund the circum. U 纹理坐标被包裹在周围。 The V texture coordinate is wrapped from the south pole to the north pole of the sphere. V 纹理坐标从球体的南极向北极包裹。

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:对于现代 OpenGL,必须像这样定义通用顶点属性数据数组:

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:预览:

预览

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM