Как я могу разобрать простой файл .obj в треугольники? - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь реализовать ray caster, и я начинаю с простых файлов .obj (utah-teapot), и в настоящее время я делаю только классы для Сфер и Треугольников, у меня в основном есть все функции для пересечений, генерирующиепросмотр лучей и т. д. все готово, но я просто не могу разобрать файл .obj в треугольники (по три вектора в каждом), поэтому я могу иметь возможность приведения лучей в пользовательских файлах .obj, а не просто в сферах.

Это мой текущий анализатор файлов .obj (здесь не указан полный рабочий код)

char lineHeader[512];
// read the first word of the line
int res = fscanf(file, "%s", lineHeader);
if (res == EOF)
    break; // EOF

// else : parse lineHeader

if (strcmp(lineHeader, "v") == 0) {
    glm::vec3 vertex;
    fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
    vertex.x *= scale;
    vertex.y *= scale;
    vertex.z *= scale;
    temp_vertices.push_back(vertex);
}
else if (strcmp(lineHeader, "vt") == 0) {
    glm::vec2 uv;
    fscanf(file, "%f %f\n", &uv.x, &uv.y);
    uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
    temp_uvs.push_back(uv);
}
else if (strcmp(lineHeader, "vn") == 0) {
    glm::vec3 normal;
    fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
    temp_normals.push_back(normal);
}
else if (strcmp(lineHeader, "f") == 0) {
    std::string vertex1, vertex2, vertex3;
    unsigned int vertexIndex[3] = { 0 }, uvIndex[3] = { 0 }, normalIndex[3] = { 0 };
    char stupidBuffer[1024];
    fgets(stupidBuffer, 1024, file);
    int matches = sscanf(stupidBuffer, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
    if (matches != 9) {
        vertexIndex[3] = { 0 }, uvIndex[3] = { 0 }, normalIndex[3] = { 0 };
        matches = sscanf(stupidBuffer, "%d//%d %d//%d %d//%d\n", &vertexIndex[0], &normalIndex[0], &vertexIndex[1], &normalIndex[1], &vertexIndex[2], &normalIndex[2]);
        if (matches != 6) {
            vertexIndex[3] = { 0 }, uvIndex[3] = { 0 }, normalIndex[3] = { 0 };
            matches = sscanf(stupidBuffer, "%d %d %d\n", &vertexIndex[0], &vertexIndex[1], &vertexIndex[2]);
            if (matches != 3) {
                printf("File can't be read \n");
                fclose(file);
                return false;
            }
        }
    }
}

Это мой класс треугольника

class Triangle {
public:
    Vector p0, p1, p2;
    Vector color;
    Vector normal(void);
};

Я могу 't понять, как разбить информацию из файла .obj на треугольники, состоящие из трех трехмерных векторов (точек).Мне не нужен код, мне просто нужно понять, как (если возможно?) Разобрать всю эту информацию в треугольники.Любые другие идеи приветствуются.Я хочу сделать простую головоломку в долгосрочной перспективе, но я просто делаю шаг за шагом.

1 Ответ

0 голосов
/ 18 октября 2018

Ты на 90% пути туда.В вашем синтаксическом анализаторе элемента лица используйте проанализированные индексы позиции / нормального / texcoord каждой грани-вершины, чтобы получить информацию из векторов temp_*.Если у элемента лица есть три вершины, вы можете испустить треугольник как есть, в противном случае для 4+ вершин я обычно предполагал, что результирующий многоугольник является выпуклым и копланарным, и в этом случае вы можете триангулировать, притворяясь, что этотреугольный вентилятор .

Все вместе:

struct Vertex
{
    glm::vec3 position;
    glm::vec2 texcoord;
    glm::vec3 normal;
};

struct VertRef
{
    VertRef( int v, int vt, int vn ) : v(v), vt(vt), vn(vn) { }
    int v, vt, vn;
};

std::vector< Vertex > LoadOBJ( std::istream& in )
{
    std::vector< Vertex > verts;

    std::vector< glm::vec4 > positions( 1, glm::vec4( 0, 0, 0, 0 ) );
    std::vector< glm::vec3 > texcoords( 1, glm::vec3( 0, 0, 0 ) );
    std::vector< glm::vec3 > normals( 1, glm::vec3( 0, 0, 0 ) );
    std::string lineStr;
    while( std::getline( in, lineStr ) )
    {
        std::istringstream lineSS( lineStr );
        std::string lineType;
        lineSS >> lineType;

        // vertex
        if( lineType == "v" )
        {
            float x = 0, y = 0, z = 0, w = 1;
            lineSS >> x >> y >> z >> w;
            positions.push_back( glm::vec4( x, y, z, w ) );
        }

        // texture
        if( lineType == "vt" )
        {
            float u = 0, v = 0, w = 0;
            lineSS >> u >> v >> w;
            texcoords.push_back( glm::vec3( u, v, w ) );
        }

        // normal
        if( lineType == "vn" )
        {
            float i = 0, j = 0, k = 0;
            lineSS >> i >> j >> k;
            normals.push_back( glm::normalize( glm::vec3( i, j, k ) ) );
        }

        // polygon
        if( lineType == "f" )
        {
            std::vector< VertRef > refs;
            std::string refStr;
            while( lineSS >> refStr )
            {
                std::istringstream ref( refStr );
                std::string vStr, vtStr, vnStr;
                std::getline( ref, vStr, '/' );
                std::getline( ref, vtStr, '/' );
                std::getline( ref, vnStr, '/' );
                int v = atoi( vStr.c_str() );
                int vt = atoi( vtStr.c_str() );
                int vn = atoi( vnStr.c_str() );
                v  = (  v >= 0 ?  v : positions.size() +  v );
                vt = ( vt >= 0 ? vt : texcoords.size() + vt );
                vn = ( vn >= 0 ? vn : normals.size()   + vn );
                refs.push_back( VertRef( v, vt, vn ) );
            }

            // triangulate, assuming n>3-gons are convex and coplanar
            for( size_t i = 1; i+1 < refs.size(); ++i )
            {
                const VertRef* p[3] = { &refs[0], &refs[i], &refs[i+1] };

                // http://www.opengl.org/wiki/Calculating_a_Surface_Normal
                glm::vec3 U( positions[ p[1]->v ] - positions[ p[0]->v ] );
                glm::vec3 V( positions[ p[2]->v ] - positions[ p[0]->v ] );
                glm::vec3 faceNormal = glm::normalize( glm::cross( U, V ) );

                for( size_t j = 0; j < 3; ++j )
                {
                    Vertex vert;
                    vert.position = glm::vec3( positions[ p[j]->v ] );
                    vert.texcoord = glm::vec2( texcoords[ p[j]->vt ] );
                    vert.normal = ( p[j]->vn != 0 ? normals[ p[j]->vn ] : faceNormal );
                    verts.push_back( vert );
                }
            }
        }
    }

    return verts;
}

Смотрите полную программу здесь .

...