Search code examples
c++opengltexturesopengl-compat

Texture for Torus is not applying properly


I'm creating a open GL program with 6 Torus. When I applied the texture it's displaying with one color. Even though it's not in a single color.

I'm getting images from array. Other textures (skybox, planet, HUD) are applying properly except Torus textures. I tried to apply light source as well but no luck. Can somebody help me to achieve this?

Below is my code.

                glPushMatrix();
                glEnable(GL_TEXTURE_2D);
                glTranslatef(xpos, ypos, zpos);
                glRotatef(fPlanetRot, 0.0f, -1.0f, 0.0f);
                glColor3f(0.0, 0.0, 0.0);

                // Select the texture object
                glBindTexture(GL_TEXTURE_2D, textures[3]);

                glutSolidTorus(0.1, 1.0, 30, 30);
                glDisable(GL_TEXTURE_2D);
                glPopMatrix();

//This is where I load the texture

void SetupRC()
{
    //textures

    GLuint texture;
    // allocate a texture name
    glGenTextures( 1, &texture );
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);

    //there are quite a few ways of loading images
    // Load textures in a for loop
    glGenTextures(TEXTURE_COUNT, textures);
    //this puts the texture into OpenGL texture memory
 //   glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - not defined so probably need to update GLEW - not needed here so ignore
    for(int iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
    {
        // Bind to next texture object
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        // Load texture data, set filter and wrap modes
        //note that gltLoadTGA is in the glm.cpp file and not a built-in openGL function
        pBytes0 = gltLoadTGA(textureFiles[iLoop],&iWidth, &iHeight,
                             &iComponents, &eFormat);
        
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes0);
        
            //set up texture parameters
        
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        //try these too
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        free(pBytes0);
    }
    
    //enable textures
    glEnable(GL_TEXTURE_2D);

    
    glEnable(GL_DEPTH_TEST);    // Hidden surface removal    
    glFrontFace(GL_CCW);// Counter clock-wise polygons face out
    glEnable(GL_CULL_FACE);     // Do not calculate inside

//    glCullFace(GL_FRONT_AND_BACK);
    
    // Enable lighting
    glEnable(GL_LIGHTING);
    glEnable(GL_POINT_SMOOTH);
    // Setup and enable light 0
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLightLessBright);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,redLight);
    glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
    glEnable(GL_LIGHT0);

    // Enable colour tracking
    glEnable(GL_COLOR_MATERIAL);
    
    // Set Material properties to follow glColor values
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    
    // Black blue background
    glClearColor(0.0f, 0.0f, 0.03f, 1.0f );
}

This is how the texture is displaying after applied. Plain dark blue color This is the Torus texture that I'm applying


Solution

  • In short:

    glutSolidTorus() just doesn't emit texture coordinates for the torus but only coordinates and per-vertex normals.

    The long story:

    Out of curiosity, I googled a bit, and I believe I found the explanation to OPs observation

    Other textures (skybox, planet, HUD) are applying properly except Torus textures.

    First I had a look at the doc. 11.4 glutSolidTorus, glutWireTorus but I couldn't find any hint whether texture coordinates are supported nor that they are not. I tried some other docs but mostly they were copies of this or didn't mention texturing as well.

    Next I tried to find sample images for "glutSolidTorus texture" but I couldn't.

    Very suspicious…

    So, I finally had a look onto the source code of glutSolidTorus() on github:

    void APIENTRY
    glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,
      GLint nsides, GLint rings)
    {
      doughnut(innerRadius, outerRadius, nsides, rings);
    }
    

    The doughnut() function is defined in the same source file:

    static void
    doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
    {
      int i, j;
      GLfloat theta, phi, theta1;
      GLfloat cosTheta, sinTheta;
      GLfloat cosTheta1, sinTheta1;
      GLfloat ringDelta, sideDelta;
    
      ringDelta = 2.0 * M_PI / rings;
      sideDelta = 2.0 * M_PI / nsides;
    
      theta = 0.0;
      cosTheta = 1.0;
      sinTheta = 0.0;
      for (i = rings - 1; i >= 0; i--) {
        theta1 = theta + ringDelta;
        cosTheta1 = cos(theta1);
        sinTheta1 = sin(theta1);
        glBegin(GL_QUAD_STRIP);
        phi = 0.0;
        for (j = nsides; j >= 0; j--) {
          GLfloat cosPhi, sinPhi, dist;
    
          phi += sideDelta;
          cosPhi = cos(phi);
          sinPhi = sin(phi);
          dist = R + r * cosPhi;
    
          glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
          glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
          glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
          glVertex3f(cosTheta * dist, -sinTheta * dist,  r * sinPhi);
        }
        glEnd();
        theta = theta1;
        cosTheta = cosTheta1;
        sinTheta = sinTheta1;
      }
    }
    

    The answer is simple and obvious – glutSolidTorus() just doesn't emit texture coordinates for the torus but only coordinates and per-vertex normals. Hence, all pixels will have the same and only texture coordinate from beginning. This will result in a uniformly colored torus (like observed by OP).

    So, when glutSolidTorus() doesn't support texturing why does e.g. glutSolidSphere()? The answer is given in the same source file:

    void APIENTRY
    glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
    {
      QUAD_OBJ_INIT();
      gluQuadricDrawStyle(quadObj, GLU_FILL);
      gluQuadricNormals(quadObj, GLU_SMOOTH);
      /* If we ever changed/used the texture or orientation state
         of quadObj, we'd need to change it to the defaults here
         with gluQuadricTexture and/or gluQuadricOrientation. */
      gluSphere(quadObj, radius, slices, stacks);
    }
    

    I.e. glutSolidSphere() is just a wrapper for gluSphere(). The doc. of gluSphere() mentions texturing explicitly:

    If texturing is turned on (with gluQuadricTexture), then texture coordinates are generated so that t ranges from 0.0 at z = - radius to 1.0 at z = radius (t increases linearly along longitudinal lines), and s ranges from 0.0 at the +y axis, to 0.25 at the +x axis, to 0.5 at the -y axis, to 0.75 at the -x axis, and back to 1.0 at the +y axis.


    If OP intends to have a textured torus then glutSolidTorus() has to be replaced by a custom version which emits texture coordinates. With the given source code, it shouldn't be too hard to extend the function resp. (Please, don't forget to give it a new name to prevent link errors for duplicate definition of symbol glutSolidTorus()…)


    Useful Links I found Afterwards: