高级加载obj文件

时间:2014-04-22 18:25:04

标签: c++ opengl wavefront

我似乎找不到关于如何进行高级obj加载(又名.Wavefront)的好教程 我想加载一个带有指定纹理的模型,什么不是,我发现的所有教程都没有解释它(只是显示一个窗口,它有效)或者只是做基本的,顶点,法线和索引。 / p>

首先,对教程有什么建议吗?

这是我的代码,我需要做些什么来使它适用于不同的纹理?

数据结构:

struct ObjectData {
    vector <glm::vec3> vertices, normals, colors;
    vector <glm::vec2> texCoords;
    vector <GLuint> vIndices, uIndices, nIndices;
};

对象加载器h:

class ObjectLoader {
private:
    struct Material {
        string name;
        glm::vec3 color;
    };

    vector <Material*> materials;
    Material *currentMaterial;
    ObjectData *object;
    bool hasUV, hasNormals, isQuads, indexChecked;

    string parseString(string src, string code);
    glm::vec2 parseVec2(string src, string code);
    glm::vec3 parseVec3(string src, string code);
    void addIndices(string str);
    void checkIndices(string str);
    void loadObjects(string objPath);
    void loadMaterials(string matPath);

public:
    ObjectLoader(string objName);
    ~ObjectLoader();

    ObjectData* getModel();
    GLenum getRenderMode();
};

对象加载器cpp:

ObjectLoader::ObjectLoader(string objName) {
    indexChecked = false;
    isQuads = false;

    string fileName = DIR_OBJECTS + objName + "/" + objName;
    loadMaterials(fileName + ".mtl");
    loadObjects(fileName + ".obj");
}

ObjectLoader::~ObjectLoader() {

}

string ObjectLoader::parseString(string src, string code) {
    char buffer[64];
    string scanStr = code + " %s";
    sscanf_s(src.c_str(), scanStr.c_str(), &buffer, _countof(buffer));
    return string(buffer);
}

glm::vec2 ObjectLoader::parseVec2(string src, string code) {
    float x, y;
    string scanStr = code + " %f %f";
    sscanf_s(src.c_str(), scanStr.c_str(), &x, &y);
    return glm::vec2(x, y);
}

glm::vec3 ObjectLoader::parseVec3(string src, string code) {
    float x, y, z;
    string scanStr = code + " %f %f %f";
    sscanf_s(src.c_str(), scanStr.c_str(), &x, &y, &z);
    return glm::vec3(x, y, z);
}

void ObjectLoader::addIndices(string str) {
    int v1 = -1, u1 = -1, n1 = -1,
        v2 = -1, u2 = -1, n2 = -1,
        v3 = -1, u3 = -1, n3 = -1,
        v4 = -1, u4 = -1, n4 = -1;

    checkIndices(str);

    if (!hasUV && !hasNormals) {
        sscanf_s(str.c_str(),"f %d %d %d %d",
            &v1,
            &v2,
            &v3,
            &v4);
    }
    else if (hasUV && !hasNormals) {
        sscanf_s(str.c_str(),"f %d/%d %d/%d %d/%d %d/%d",
            &v1, &u1,
            &v2, &u2,
            &v3, &u3,
            &v4, &u4);
    }
    else if (!hasUV && hasNormals) {
        sscanf_s(str.c_str(),"f %d//%d %d//%d %d//%d %d//%d",
            &v1, &n1,
            &v2, &n2,
            &v3, &n3,
            &v4, &n4);
    }
    else if (hasUV && hasNormals) {
        sscanf_s(str.c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d",
            &v1, &u1, &n1,
            &v2, &u2, &n2,
            &v3, &u3, &n3,
            &v4, &u4, &n4);
    }

    v1--; u1--; n1--;
    v2--; u2--; n2--;
    v3--; u3--; n3--;
    v4--; u4--; n4--;

    if (v3 >= 0) {
        float r = currentMaterial->color.r;
        float g = currentMaterial->color.g;
        float b = currentMaterial->color.b;

        object->vIndices.push_back(v1);
        object->vIndices.push_back(v2);
        object->vIndices.push_back(v3);
        object->colors.push_back(currentMaterial->color);
        object->colors.push_back(currentMaterial->color);
        object->colors.push_back(currentMaterial->color);
        if (v4 >= 0) {
            object->vIndices.push_back(v4);
            object->colors.push_back(currentMaterial->color);
            isQuads = true;
        }
    }

    if (u3 >= 0) {
        object->uIndices.push_back(u1);
        object->uIndices.push_back(u2);
        object->uIndices.push_back(u3);
        if (u4 >= 0) {
            object->uIndices.push_back(u4);
        }
    }

    if (n3 >= 0) {
        object->nIndices.push_back(n1);
        object->nIndices.push_back(n2);
        object->nIndices.push_back(n3);
        if (n4 >= 0) {
            object->nIndices.push_back(n4);
        }
    }
}

void ObjectLoader::checkIndices(string str) {
    if (!indexChecked) {
        int bestSample = 0;
        int sampleV1 = -1, sampleU1 = -1, sampleN1 = -1;
        int tmp = -1, sampleV4 = -1;

        int form1 = sscanf_s(str.c_str(),"f %d", &sampleV1);
        int form2 = sscanf_s(str.c_str(),"f %d/%d", &sampleV1, &sampleU1);
        int form3 = sscanf_s(str.c_str(),"f %d//%d", &sampleV1, &sampleN1);
        int form4 = sscanf_s(str.c_str(),"f %d/%d/%d", &sampleV1, &sampleU1, &sampleN1);

        if (form1 > bestSample) {
            bestSample = form1;
            hasUV = false;
            hasNormals = false;
        }
        if (form2 > bestSample) {
            bestSample = form2;
            hasUV = true;
            hasNormals = false;
        }
        if (form3 > bestSample) {
            bestSample = form3;
            hasUV = false;
            hasNormals = true;
        }
        if (form4 > bestSample) {
            bestSample = form4;
            hasUV = true;
            hasNormals = true;
        }

        indexChecked = true;
    }
}

void ObjectLoader::loadObjects(string objPath) {
    ifstream file(objPath);
    string buffer;
    object = new ObjectData();
    currentMaterial = materials[0];

    if (file.is_open()) {
        while (!file.eof()) {
            getline(file, buffer);

            if (buffer.find("v ") == 0) {
                object->vertices.push_back(parseVec3(buffer, "v"));
            }
            else if (buffer.find("vn") == 0) {
                object->normals.push_back(parseVec3(buffer, "vn"));
            }
            else if (buffer.find("vt") == 0) {
                object->texCoords.push_back(parseVec2(buffer, "vt"));
            }
            else if (buffer.find("usemtl") == 0) {
                string name = parseString(buffer, "usemtl");
                for (int i = 0; i < materials.size(); i++) {
                    if (name == materials[i]->name) {
                        currentMaterial = materials[i];
                    }
                }
            }
            else if (buffer.find("f ") != string::npos) {
                addIndices(buffer);
            }
        }
    }
    else {
        printf("Unable to find: %s\n", objPath.c_str());
    }
}

void ObjectLoader::loadMaterials(string matPath) {
    ifstream file(matPath);
    string buffer;
    currentMaterial = NULL;

    if (file.is_open()) {
        while (!file.eof()) {
            getline(file, buffer);

            if (buffer.find("newmtl") == 0) {
                if (currentMaterial != NULL) {
                    materials.push_back(currentMaterial);
                }
                currentMaterial = new Material();
                currentMaterial->name = parseString(buffer, "newmtl");
            }
            else if (buffer.find("Kd") == 0) {
                currentMaterial->color = parseVec3(buffer, "Kd");
            }
        }
    }
    else {
        printf("Unable to find: %s\n", matPath.c_str());
    }

    if (currentMaterial == NULL) {
        currentMaterial = new Material();
        currentMaterial->color = glm::vec3(1, 1, 1);
    }

    materials.push_back(currentMaterial);
}

ObjectData* ObjectLoader::getModel() {
    return object;
}

GLenum ObjectLoader::getRenderMode() {
    GLenum mode = ((isQuads) ? GL_QUADS : GL_TRIANGLES);
    return mode;
}

0 个答案:

没有答案