Assimp неверный массив текстур - PullRequest
0 голосов
/ 20 октября 2018

Я на самом деле программирую инструмент для выпечки карт нормалей.Итак, у меня есть функция, которая должна брать трехмерный объект и проецировать вектор нормалей каждой вершины на текстуру.

В настоящее время я использую библиотеку Assimp для импорта моделей .obj, и у меня никогда не было этой проблемы раньше...

Вот функция, которая импортирует сетки:

std::vector<Object3D> Loader::load(const char* file){
    Assimp::Importer importer ;
    const aiScene *modelScene = importer.ReadFile(file , aiProcess_CalcTangentSpace | aiProcess_Triangulate  | aiProcess_JoinIdenticalVertices
                            | aiProcess_FlipUVs) ;

    if(modelScene != nullptr)
        {
            std::vector<Object3D> objects; 
            for(int i = 0 ; i < modelScene->mNumMeshes ; i++){
                const aiMesh* mesh = modelScene->mMeshes[i] ; 
                Object3D object ;
                assert(mesh->HasTextureCoords(0) ) ; 
                for(int f = 0 ; f < mesh->mNumVertices ; f++){
                    const aiVector3D* vert = &(mesh->mVertices[f]) ; 
                    const aiVector3D* norm = &(mesh->mNormals[f]) ; 
                    const aiVector3D* tex = &(mesh->mTextureCoords[0][f]) ; 

                object.vertices.push_back(vert->x); 
                object.vertices.push_back(vert->y); 
                object.vertices.push_back(vert->z); 

                object.uv.push_back(tex->x) ; 
                object.uv.push_back(tex->y) ; 

                object.normals.push_back(norm->x) ; 
                object.normals.push_back(norm->y) ; 
                object.normals.push_back(norm->z) ; 

                }

            for(int ind = 0 ; ind < mesh->mNumFaces ; ind++){

                assert(mesh->mFaces[ind].mNumIndices==3) ;  
                object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[0]));
                object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[1]));
                object.indices.push_back(static_cast<unsigned int> (mesh->mFaces[ind].mIndices[2]));

            }
            std::cout << "object loaded : " << mesh->mName.C_Str()<< "\n" ; 
            objects.push_back(object) ;

            }


        return objects ; 
        }
    else
        {

        std::cout << "Problem loading scene" << std::endl ; 
        return std::vector<Object3D>() ;    
        }



}

Она берет сцену, разбивает ее на несколько сеток и возвращает их вершины, UV, нормали и индексы.

Затем я отправляю это этой функции:

SDL_Surface* ImageManager::project_uv_normals(Object3D object , int width ,  int height){


#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32 rmask = 0xFF000000 ; 
Uint32 gmask = 0x00FF0000 ; 
Uint32 bmask = 0x0000FF00 ; 
Uint32 amask = 0x000000FF ; 

#else 

Uint32 amask = 0xFF000000 ; 
Uint32 bmask = 0x00FF0000 ; 
Uint32 gmask = 0x0000FF00 ; 
Uint32 rmask = 0x000000FF ; 


#endif  

    SDL_Surface* surf = SDL_CreateRGBSurface(0 , width , height , 24 , rmask , gmask , bmask , amask) ;
    assert(surf != nullptr) ; 


    for(unsigned int i = 0 ; i < object.indices.size() ; i+=3) {
        auto index = object.indices; 

        Point2D P1 = { object.uv[index[i]] , object.uv[index[i] + 1 ] } ;   
        Point2D P2 = { object.uv[index[i + 1]] , object.uv[index[i + 1] + 1 ] } ; 
        Point2D P3 = { object.uv[index[i + 2]] , object.uv[index[i + 2] + 1 ] } ; 

        P1.print(); 
        P2.print(); 
        P3.print(); 
        std::cout << index[i] << "    " << index[i+1] << "    "<< index[i+2] << "\n" ; 
        Vect3D N1  = { object.normals[index[i]] , object.normals[index[i] + 1 ] , object.normals[index[i] + 2] } ; 
        Vect3D N2 = { object.normals[index[i + 1]]  , object.normals[index[i + 1] + 1 ] , object.normals[index[i + 1 ] + 2] } ; 
        Vect3D N3 = { object.normals[index[i + 2 ]] , object.normals[index[i + 2] + 1 ] , object.normals[index[i + 2 ] + 2 ] } ; 


        P1.x *= width ; 
        P1.y *= height ; 

        P2.x *= width ; 
        P2.y *= height ; 

        P3.x *= width ; 
        P3.y *= height ; 

        set_pixel_color(surf , P1.x , P1.y , 0xFFFFFFFF) ;
        set_pixel_color(surf , P2.x , P2.y , 0xFFFFFFFF) ;
        set_pixel_color(surf , P3.x , P3.y , 0xFFFFFFFF) ;
        auto bounding_coords = [](float x , float y , float z , bool min) { 
            if( min ) {
                if( x <= y )
                    return x <= z ? x : z ; 
                else
                    return y <= z ? y : z ; 
                }
            else {
                if( x >= y )
                    return x >= z ? x : z ; 
                else
                    return y >= z ? y : z ; 
                }
        };



        auto x_max = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , false)); 
        auto x_min = static_cast<int>(bounding_coords( P1.x , P2.x , P3.x , true )); 
        auto y_max = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , false)); 
        auto y_min = static_cast<int>(bounding_coords( P1.y , P2.y , P3.y , true)); 



        auto barycentric_lerp = [] (Point2D P1 , Point2D P2 , Point2D P3 , Point2D I){
            auto W1 = (  (P2.y - P3.y ) * (I.x - P3.x ) + ( P3.x - P2.x) * (I.y - P3.y) ) / ( (P2.y - P3.y ) * (P1.x - P3.x ) + (P3.x - P2.x ) * (P1.y - P3.y ) ) ; 
            auto W2 = ( (P3.y - P1.y) * (I.x - P3.x) + (P1.x - P3.x) * ( I.y - P3.y ) ) / ( (P2.y - P3.y ) * (P1.x - P3.x) + ( P3.x - P2.x) * (P1.y - P3.y ) ) ; 
            auto W3 = 1 - W1 - W2 ; 
            Vect3D v = {W1 , W2 , W3} ; 
            return v ;  



        };



        for(int x = x_min ; x <= x_max ; x++){
            for(int y = y_min ; y <= y_max ; y++){


                Point2D I = {static_cast<float>(x) ,static_cast<float> (y)} ; 
                Vect3D C = barycentric_lerp(P1 , P2 , P3 , I) ; 
                    if(C.x >= 0 && C.y >= 0 && C.z >= 0){
                        Vect3D normal = { N1.x * C.x + N2.x * C.y + N3.x * C.z ,
                                  N1.y * C.x + N2.y * C.y + N3.y * C.z ,
                                  N1.z * C.x + N2.z * C.y + N3.z * C.z }; 
                        RGB rgb = RGB( static_cast<int>(normal.x * 255) ,  static_cast<int>(normal.y * 255)  ,  static_cast<int>(normal.z * 255) , 0 ) ; 
                        uint32_t val = rgb.rgb_to_int() ; 

                        set_pixel_color(surf , x , y , val) ;





                    }

            }


        }





    }


    return surf ; 

    } 

Предполагается взять UV и индексы, спроецировать UV точки на текстуру и интерполировать нормали между каждой точкой.

Итак, я пытаюсь сослаться на UV н-й вершины, выполнив UVarray [indexarray [n-1]] для компонента x и UVarray [indexarray [n-1] +1] дляу компонента.Проблема здесь в том, что это не работает.Например, на простой плоскости, состоящей из двух треугольников, вот что я получил: enter image description here

Итак, что я должен получить, так это точную УФ-проекцию модели,вот так: enter image description here

Наконец, я запустил программу под GDB, я обнаружил, что массив вершин загружен правильно, индексы тоже ... но не UVs:

enter image description here

Я напечатал значения этих массивов в 3 последних строках.

файл .obj содержит следующие простые данные:

o Plane
v 1.000000 -0.000000 1.000000
v -1.000000 0.000000 -1.000000
v -1.000000 -0.000000 1.000000
v 1.000000 0.000000 -1.000000
vt 0.089179 0.089179
vt 0.910821 0.910821
vt 0.089179 0.910821
vt 0.910821 0.089179 
vn 0.0000 1.0000 0.0000
usemtl None
s 1
f 1/1/1 2/2/1 3/3/1
f 1/1/1 4/4/1 2/2/1

Индексы остались в том же порядке, но не ссылаются на те же координаты UV.

Я надеюсь, что это ошибка от меня, а не ошибка от Assimp. Ребята, вы понимаете, что там происходит?Спасибо.

1 Ответ

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

Проблема решена.Ошибка была довольно простой: индексы не правильно указывают на грани, потому что я забыл включить отступы.

...