Search code examples
copengltextures

OpenGL: Wrapping texture around cylinder


I am trying to add textures to a cylinder to draw a stone well. I'm starting with a cylinder and then mapping a stone texture I found here but am getting some weird results. Here is the function I am using:

void draw_well(double x, double y, double z,
    double dx, double dy, double dz,
    double th)
{
    //  Set specular color to white
    float white[] = {1,1,1,1};
    float black[] = {0,0,0,1};
    glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,shinyvec);
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,white);
    glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,black);

    glPushMatrix();

    //  Offset
    glTranslated(x,y,z);
    glRotated(th,0,1,0);
    glScaled(dx,dy,dz);

    //  Enable textures
    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

    glBindTexture(GL_TEXTURE_2D,texture[0]); // Stone texture

    glBegin(GL_QUAD_STRIP);
    for (int i = 0; i <= 359; i++)
    {
        glNormal3d(Cos(i), 1, Sin(i));

        glTexCoord2f(0,0); glVertex3f(Cos(i), -1, Sin(i));
        glTexCoord2f(0,1); glVertex3f(Cos(i), 1, Sin(i));
        glTexCoord2f(1,1); glVertex3f(Cos(i + 1), 1, Sin(i + 1));
        glTexCoord2f(1,0); glVertex3f(Cos(i + 1), -1, Sin(i + 1));
    }
    glEnd();

    glPopMatrix();
    glDisable(GL_TEXTURE_2D);
}


// Later down in the display function
draw_well(0, 0, 0, 1, 1, 1, 0);

and the output I receive is

enter image description here

I'm still pretty new to OpenGL and more specifically textures so my understanding is pretty limited. My thought process here is that I would map the texture to each QUAD used to make the cylinder, but clearly I am doing something wrong. Any explanation on what is causing this weird output and how to fix it would be greatly appreciated.


Solution

  • There are possibly three main issues with your draw routine. quad-strip indexing, texture coordinates repeating too often and possible incorrect usage of the trig functions;

    Trigonometric functions usually accept values which represent angles expressed in radians and not degrees. Double check what the parameters of the Sin and Cos functions you are using.

    Quadstrip indexing is incorrect. Indexing should go like this...

    enter image description here

    Notice how the quad is defined in a clock-wise fashion, however the diagonal vertices are defined sequentially. You are defining the quad as v0, v1, v3, v2 instead of v0, v1, v2, v3 so swap the last two vertices of the four. This also leads to another error in not sharing the vertices correctly. You are duplicating them along each vertical edge since you draw the same set of vertices (i+1) in one loop, as you do in the next (i.e since i has now been incremented by 1).

    Texture coordinates are in the range from 0, 1 for each quad which means you are defining a cylinder which is segmented 360 times and this texture is repeated 360 times around the cylinder. I'm assuming the texture should be mapped 1:1 to the Cylinder and not repeated?

    Here is some example code using what you provided. I have reduced the number of segments down to 64, if you wish to still have 360 then ammend numberOfSegments accordingly.

    float pi = 3.141592654f;
    
    unsigned int numberOfSegments = 64;
    float angleIncrement = (2.0f * pi) / static_cast<float>(numberOfSegments);
    float textureCoordinateIncrement = 1.0f / static_cast<float>(numberOfSegments);
    
    glBegin(GL_QUAD_STRIP);
    for (unsigned int i = 0; i <= numberOfSegments; ++i)
    {
        float c = cos(angleIncrement * i);
        float s = sin(angleIncrement * i);
    
        glTexCoord2f( textureCoordinateIncrement * i, 0); glVertex3f( c, -1.0f, s);
        glTexCoord2f( textureCoordinateIncrement * i, 1.0f); glVertex3f( c, 1.0f, s);
    }
    glEnd();
    

    N.BYou are using an old version of OpenGL (the use of glBegin/glVertex etc).