Visit Cem Yuksel's web site
Using HAIR files

A HAIR files is a binary file that keeps hair model data (see HAIR file description for more information). This solution presents a way of using cyHair code release to easily load HAIR files and display hair models using OpenGL.


1. Loading HAIR files

The actual loading operation is handled using cyHairFile class by calling LoadFromFile method. The following function loads the given HAIR file into the given cyHairFile object, and calls FillDirectionArray method of cyHairFile to precompute hair directions and store them in the given directions array. These directions will be used for shading when drawing the hair model. If an error occurs, it prints proper error messages.

void LoadHairModel( const char *filename, cyHairFile &hairfile, float &*dirs )
{
    // Load the hair model
    int result = hairfile.LoadFromFile( filename );

    // Check for errors
    switch( result ) {
        case CY_HAIR_FILE_ERROR_CANT_OPEN_FILE:
            printf("Error: Cannot open hair file!\n");
            return;
        case CY_HAIR_FILE_ERROR_CANT_READ_HEADER:
            printf("Error: Cannot read hair file header!\n");
            return;
        case CY_HAIR_FILE_ERROR_WRONG_SIGNATURE:
            printf("Error: File has wrong signature!\n");
            return;
        case CY_HAIR_FILE_ERROR_READING_SEGMENTS:
            printf("Error: Cannot read hair segments!\n");
            return;
        case CY_HAIR_FILE_ERROR_READING_POINTS:
            printf("Error: Cannot read hair points!\n");
            return;
        case CY_HAIR_FILE_ERROR_READING_COLORS:
            printf("Error: Cannot read hair colors!\n");
            return;
        case CY_HAIR_FILE_ERROR_READING_THICKNESS:
            printf("Error: Cannot read hair thickness!\n");
            return;
        case CY_HAIR_FILE_ERROR_READING_TRANSPARENCY:
            printf("Error: Cannot read hair transparency!\n");
            return;
        default:
            printf("Hair file \"%s\" loaded.\n", filename);
    }

    int hairCount = hairfile.GetHeader().hair_count;
    int pointCount = hairfile.GetHeader().point_count;
    printf("Number of hair strands = %d\n", hairCount );
    printf("Number of hair points = %d\n", pointCount );

    // Compute directions
    if( hairfile.FillDirectionArray( dirs ) == 0 ) {
        printf("Error: Cannot compute hair directions!\n");
    }
}

2. Drawing hair models

Now that we have loaded the hair model, we are ready to draw it as line segments. The following function first initializes OpenGL arrays using the given cyHairFile object and precomputed directions, then iterates over all hair strands and draws them using glDrawArrays function.

void LoadHairModel( const cyHairFile &hairfile, float *dirs )
{
    // Set point array
    glVertexPointer( 3, GL_FLOAT, 0, hairfile.GetPointsArray() );
    glEnableClientState( GL_VERTEX_ARRAY );

    // Set normal array
    glNormalPointer( GL_FLOAT, 0, dirs );
    glEnableClientState( GL_NORMAL_ARRAY );

    // Set color array (if exists)
    float *colors = hairfile.GetColorsArray();
    if ( colors ) {
        glColorPointer( 3, GL_FLOAT, 0, colors );
        glEnableClientState( GL_COLOR_ARRAY );
    }

    // Draw arrays
    int pointIndex = 0;
    int hairCount = hairfile.GetHeader().hair_count;
    unsigned short segments = GetSegmentsArray();
    if ( segments ) {
        // If segments array exists
        for ( int hairIndex=0; hairIndex < hairCount; hairIndex++ ) {
            glDrawArrays( GL_LINE_STRIP, pointIndex, segments[ hairIndex ]+1 );
            pointIndex += segments[ hairIndex ]+1;
        }
    } else {
        // If segments array does not exist, use default segment count
        int dsegs = hairfile.GetHeader().d_segments;
        for ( int hairIndex=0; hairIndex < hairCount; hairIndex++ ) {
            glDrawArrays( GL_LINE_STRIP, pointIndex, dsegs+1 );
            pointIndex += dsegs+1;
        }
    }

    // Disable arrays
    glDisableClientState( GL_VERTEX_ARRAY );
    glDisableClientState( GL_NORMAL_ARRAY );
    glDisableClientState( GL_COLOR_ARRAY );
}
Visit Cem Yuksel's website!