Material::Ref createMaterial(const ArticulatedModel::Preprocess& preprocess) const {
        debugPrintf("Creating material %s...", name.c_str());
        Material::Specification spec;

        if ((diffuseMap != "") && ! preprocess.stripMaterials) {
            Texture::Specification s;
            s.dimension = Texture::DIM_2D_NPOT;

            // If we turn this off, the BSDF just does it anyway
            s.preprocess.computeMinMaxMean = true;
            s.settings.maxAnisotropy = 2.0f;
            s.filename = diffuseMap;
            spec.setLambertian(s);

        } else {
            spec.setLambertian(diffuseConstant);
        }

        // Assume in air
        spec.setEta(max(1.0f, eta), 1.0f);

        // OBJ models are way too specular and not shiny enough
        spec.setSpecular(specularConstant.pow(9.0f) * 0.4f);
        spec.setGlossyExponentShininess(shininess * 100.0f);

        // spec.setBump(bumpMap);

        Material::Ref m = Material::create(spec);
        debugPrintf("Done\n");
        return m;
    }
static Material::Specification compute3DSMaterial
(const void*         ptr,
 const std::string&  path,
 const ArticulatedModel::Specification&   specification) {

    const Parse3DS::Material& material = *reinterpret_cast<const Parse3DS::Material*>(ptr);

    Material::Specification spec;

    if (specification.stripMaterials) {
        spec.setLambertian(Color3::one() * 0.7f);
        spec.setSpecular(Color3::one() * 0.2f);
        spec.setGlossyExponentShininess(100);
        return spec;
    }
    
    const Parse3DS::Map& texture1 = material.texture1;

    const Color4& lambertianConstant = 
        Color4((material.diffuse * material.texture1.pct) *
               (1.0f - material.transparency), 1.0f);

    const std::string& lambertianFilename = find3DSTexture(texture1.filename, path);
    
    spec.setLambertian(lambertianFilename, lambertianConstant);

    // Strength of the shininess (higher is brighter)
    spec.setSpecular(max(material.shininessStrength * material.specular, Color3(material.reflection)) * (1.0f - material.transparency));

    if (material.reflection > 0.05f) {
        spec.setMirrorShininess();
    }

    //extent (area, higher is closely contained, lower is spread out) of shininess.
    // Don't scale up to the G3D maximum (1024) because 3DS files don't expect to ever be that shiny
    spec.setGlossyExponentShininess(material.shininess * 512);

    spec.setTransmissive(Color3::white() * material.transparency);
    spec.setEmissive(Color3::white() * material.emissive);

    std::string bumpFilename = find3DSTexture(material.bumpMap.filename, path);
    if (bumpFilename != "") {
        // TODO: use percentage specified in material.bumpMap
        spec.setBump(bumpFilename);
    }

    // TODO: load reflection, specular, etc maps.
    // triList->material.reflect.map = 

    /*
    if (preprocess.addBumpMaps) {
        // See if a bump map exists:
        std::string filename = 
            FilePath::concat(FilePath::concat(path, filenamePath(texture1.filename)),
                       filenameBase(texture1.filename) + "-bump");

        filename = findAnyImage(filename);
        if (filename != "") {
            BumpMap::Settings s;
            s.scale = preprocess.bumpMapScale;
            s.bias = 0;
            s.iterations = preprocess.parallaxSteps;
            spec.setBump(filename, s, preprocess.normalMapWhiteHeightInPixels);
        }
    } // if bump maps
    */

    return spec;
}