Chapter 8

Chapter 8 covers texturing, the process of applying an image to a surface, instead of simply making it a solid color. This can improve an image by adding a lot of detail without adding a huge number of triangles with their attendant supply of vertexes, normals and color data.

The first sample program applies a stone pattern to a pyramid. I adjusted the proportions of the pyramid to match the Great Pyramid at Giza, and then modified it to look like the dollar bill pyramid, with the apex floating above the base, like this:

The basic pyramid has five points and six triangles (four faces and two on the square base), but the floating-apex pyramid requires a lot more effort. I wrote a triangle-drawing method that takes three vertex index values, which then set the normal to the triangle, calculated the texture coordinates for each vertex, and then drew the three vertexes. That made the drawPyramid method much clearer: it just had to draw triangles, and the heavy lifting got done behind the scenes. Here’s the code:

- (void)drawTrianglePointA:(int)iA 
                    pointB:(int)iB 
                    pointC:(int)iC {
    M3DVector3f vNormal;
    m3dFindNormal(vNormal, vCorners[iA], vCorners[iB], vCorners[iC]);
    // NSLog(@"Triangle %i, %i, %i with normal (%f, %f, %f)", 
    //      iA, iB, iC, vNormal[0], vNormal[1], vNormal[2]);
    int sAxis, tAxis;
    float sFactor, tFactor;
    float sBias, tBias;
    float s, t;
    if (vNormal[1] > 0.8 | vNormal[1] < -0.8) { // top of apex
        sAxis = 0;
        tAxis = 2;
        sFactor = tFactor = vNormal[1]/(2.0f*width);
        sBias = tBias = 0.5f;
    } else if (vNormal[0] > 0.7f) {
        sAxis = 2;
        tAxis = 1;
        sFactor = -0.5f/width;
        sBias = 0.5f;
        tFactor = 1.0f/height;
        tBias = 0.0f;
    } else if (vNormal[0] < -0.7f) {
        sAxis = 2;
        tAxis = 1;
        sFactor = +0.5f/width;
        sBias = 0.5f;
        tFactor = 1.0f/height;
        tBias = 0.0f;
    } else if (vNormal[2] > 0.7f) {
        sAxis = 0;
        tAxis = 1;
        sFactor = +0.5f/width;
        sBias = 0.5f;
        tFactor = 1.0f/height;
        tBias = 0.0f;
    } else {
        sAxis = 0;
        tAxis = 1;
        sFactor = -0.5f/width;
        sBias = 0.5f;
        tFactor = 1.0f/height;
        tBias = 0.0f;
    }
    // NSLog(@"sAxis = %i, tAxis = %i, sFactor, sBias = %f, %f; tFactor, tBias = %f, %f",
    //      sAxis, tAxis, sFactor, sBias, tFactor, tBias);
    glNormal3fv(vNormal);
    s = vCorners[iA][sAxis]*sFactor + sBias;
    t = vCorners[iA][tAxis]*tFactor + tBias;
    // NSLog(@"s = %f, t = %f", s, t);
    glTexCoord2f(s, t);
    glVertex3fv(vCorners[iA]);

    s = vCorners[iB][sAxis]*sFactor + sBias;
    t = vCorners[iB][tAxis]*tFactor + tBias;
    // NSLog(@"s = %f, t = %f", s, t);
    glTexCoord2f(s, t);
    glVertex3fv(vCorners[iB]);

    s = vCorners[iC][sAxis]*sFactor + sBias;
    t = vCorners[iC][tAxis]*tFactor + tBias;
    // NSLog(@"s = %f, t = %f", s, t);
    glTexCoord2f(s, t);
    glVertex3fv(vCorners[iC]);
}

- (void)drawPyramid {
    // bottom of apex
    [self drawTrianglePointA:2 pointB:4 pointC:1];
    [self drawTrianglePointA:2 pointB:3 pointC:4];

    // faces of apex
    [self drawTrianglePointA:0 pointB:4 pointC:3];
    [self drawTrianglePointA:0 pointB:1 pointC:4];
    [self drawTrianglePointA:0 pointB:2 pointC:1];
    [self drawTrianglePointA:0 pointB:3 pointC:2];

    // Top of base
    [self drawTrianglePointA:6 pointB:5 pointC:8];
    [self drawTrianglePointA:8 pointB:7 pointC:6];

    // faces of base
    [self drawTrianglePointA:8 pointB:12 pointC:7];
    [self drawTrianglePointA:7 pointB:12 pointC:11];
    [self drawTrianglePointA:5 pointB:9  pointC:8];
    [self drawTrianglePointA:8 pointB:9  pointC:12];
    [self drawTrianglePointA:6 pointB:10 pointC:5];
    [self drawTrianglePointA:5 pointB:10 pointC:9];
    [self drawTrianglePointA:7 pointB:11 pointC:6];
    [self drawTrianglePointA:6 pointB:11 pointC:10];

    // bottom of base
    [self drawTrianglePointA:10 pointB:12 pointC:9 ];
    [self drawTrianglePointA:10 pointB:11 pointC:12];
}

Here are the coordinates:

vCorners = {{    0.000000,   280.000000,     0.000000},
            {  -52.380951,   213.333344,   -52.380951},
            {   52.380951,   213.333344,   -52.380951},
            {   52.380951,   213.333344,    52.380951},
            {  -52.380951,   213.333344,    52.380951},
            {  -83.809525,   173.333344,   -83.809525},
            {   83.809525,   173.333344,   -83.809525},
            {   83.809525,   173.333344,    83.809525},
            {  -83.809525,   173.333344,    83.809525},
            { -220.000000,     0.000000,  -220.000000},
            {  220.000000,     0.000000,  -220.000000},
            {  220.000000,     0.000000,   220.000000},
            { -220.000000,     0.000000,   220.000000}};

The apex really needs to be casting a shadow to make the image more believable.

Now I need to add an eye texture to one face of the apex, and maybe “Novus Ordo Seclorum” or “MDCCLXXVI” at the bottom of the base. Or I could add it to SphereWorld and make the apex rotate…

Advertisements
This entry was posted in OpenGL. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s