Autor Wątek: [SOLVED] Problem z oświetleniem lamberta  (Przeczytany 1792 razy)

Offline Mergul

  • Użytkownik

# Lipiec 06, 2017, 15:41:32
vec3(modelMatrix) - takie cos nie istnieje :P Chodzi i to że jak zrobisz z macierzy obiektu macierz 3x3 to dostaniesz macierz samego obrotu (i skali). Wtedy zobaczymy, czy nie jest wadliwa macierz normalnych :) Dla pewności też w shaderze jako wektor światła użyj vec3(0,0,-1) zamiast tego uniform.

EDIT:
I jeżeli możesz (jak dalej nie będzie działać) to wyeksportuj z blendera model kuli. Na kuli najlepiej widać jak się oświetla.
« Ostatnia zmiana: Lipiec 06, 2017, 15:58:30 wysłana przez Mergul »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline DezerteR

  • Użytkownik

# Lipiec 06, 2017, 17:26:25
Jeśli na ostatnich screenach są same normalki to wczytywanie jest zepsute. Assimp powinien pomóc, z tym że sestawnienie assimpa to straszny ból. Na począrtek sample z neta wystarczą, ale ponieważ dokumentacja jest słaba to bardziej skomplikowane rzeczy wymagają dużo eksperymentowania. Ale warto.

Jako format pośredni polecę colladę, chyba najlepiej działa.

Offline Mergul

  • Użytkownik

# Lipiec 06, 2017, 17:45:39
Potwierdzam. Collada działa z Assimpem chyba najlepiej. Najgorsze chyba jest wyciąganie dzieci z mesha, czy wczytywanie szkieletu z uwzględnieniem tych bez wag w wierzchołkach (z tym chyba był problem z tego co pamiętam, wtedy musisz już przeszukać drzewo sceny). Ja mam nadzieję nigdy nie wracać do kodu wczytywania assimpa-em :D

Offline ekicam2

  • Użytkownik

# Lipiec 06, 2017, 18:17:30
@Mergul
:D no no, chodziło mi o mat3(modelMatrix)
A przypadkiem nie dostanę samego przesunięcia z rotacją?
W sensie wektorów normalnych nie można skalować, jak to mówiła moja matematyczka "grozi śmiercią tragiczną".

@DezerteR
Ostatni screen fragColor = vec4abs(normalInWorld), 1.0f);

A po takim opisie to ja chyba tego assimpa ruszę jutro :P
« Ostatnia zmiana: Lipiec 06, 2017, 18:24:41 wysłana przez ekicam2 »

Offline Mergul

  • Użytkownik

  • +1
# Lipiec 06, 2017, 20:10:56
Można normalki skalowac tylko są wtedy błędy. Jeżeli nie skalujesz obiektu, bądź skalujesz zawsze identycznie we wszystkich osiach to nie robi to problemu. A chodziło mi o to żeby sprawdzić czy to nie jest może wina macierzy normalnych :) Jak nie to już nie widzę nic innego jak wina daty wierzchołków :D

Cytuj
A przypadkiem nie dostanę samego przesunięcia z rotacją?
Nie. Dostaniesz przeskalowane wektory nowego układu współżędnych, czyli sam obrót.

Offline mihu

  • Użytkownik
    • mihu

  • +2
# Lipiec 07, 2017, 13:48:36
A przypadkiem nie dostanę samego przesunięcia z rotacją?
W sensie wektorów normalnych nie można skalować, jak to mówiła moja matematyczka "grozi śmiercią tragiczną".
Translacja jest w czwartej kolumnie, więc przycięcie macierzy 4x4 do 3x3 pomija translację. Generalnie lewa górna podmacierz 3x3 zawiera sumaryczne przekształcenie liniowe R^3 -> R^3 (przestrzeni wektorów w 3D). Translacja nie jest przekształceniem liniowym wektorów w 3D i dopiero użycie współrzędnych jednorodnych i rozszerzenie macierzy do 4x4 pozwala wyrazić translację jako przekształcenie liniowe (czyli macierz).

Wektory normalne traktuje się szczególnie nie przez przypadek: są one przykładem "kowektorów" albo "wektorów kowariantnych" ( https://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors ) czyli obiektów geometrycznych podobnych do zwyczajnych wektorów, ale podlegających innym regułom transformacji. Dopóki transformacja jest obrotem, to okazuje się że nie ma między nimi różnicy. Skalowanie działa inaczej dla wektorów i kowektorów, ale ponieważ w przypadku "wektorów" normalnych interesuje nas tylko postać znormalizowana, to skalowanie jednorodne też okazuje się nie stanowić problemu. Dopiero skalowanie niejednorodne (i potencjalnie inne transformacje liniowe, ale ich już rzadko się używa w grafice) powodują, że trzeba zastosować odwrotność transpozycji macierzy transformacji (słynny inverse-transpose).

Offline ekicam2

  • Użytkownik

# Lipiec 12, 2017, 21:30:07
Niestety w chwili obecnej binarki assimpa są pod msvc2015 a gdy chce je budować sam cmake ma jakieś problemy z zlibem. Mogę albo czekać aż pojawi się nowa wersja albo wybrać inny loader. Ma ktoś może jakieś propozycje? Czy może lepiej poczekać na assimpa? ;)

Offline Mergul

  • Użytkownik

# Lipiec 12, 2017, 21:32:24
Assimp chyba od dłuższego czasu stoi w miejscu, więc raczej nie bedzie nowej wersji :D Ja używałem assimpa na MinGW.

Offline karol57

  • Użytkownik

# Lipiec 13, 2017, 17:11:15
Zbuduj zliba, a potem assimpa. Chociaż z tego co pamiętam to w assimp miał opcje aby użyć swojego zliba, poczytaj co ci tam cmake wywala.

Offline karol57

  • Użytkownik

  • +2
# Lipiec 14, 2017, 20:36:13
Miałem chwilę wolnego i rozwiązałem twój problem (chyba warte osobnego posta, aby autor dostał powiadomienie).

Zacznijmy od tego jak w OpenGL działa indeksowanie. Bazując na twoim przypadku masz 3 bufory:
vec3 postion_vbo[n1];
vec3 normal_vbo[n2];
vec2 texcoord_vbo[n3];
ushort indices_vbo[n4];
Teraz każdy indeks generuje następujący wierzchołek, więc dla każdego i z przedziału [0;n4):
ushort idx = indices_vbo[i];
{
  vec3 vertexPosition = postion_vbo[idx];
  vec2 vertexST = texcoord_vbo[idx];
  vec3 vertexNormal = normal_vbo[idx];
};
Już wiesz gdzie popełniłeś błąd? Jeżeli nie to lecimy dalej.

Musisz wiedzieć jak działają indeksy w pliku *.obj, ponieważ tiny_obj przechowuje je w identyczny sposób.
Ogólnie masz podobnie jak u siebie, ale nie do końca. Są 3 bufory:
vec3 postions[n1];
vec3 normals[n2];
vec2 texcoords[n3];

A następnie masz jedną(co założyłeś u siebie)/kilka siatek z których każda składa się z materiału i listy indeksów. Problem w tym, że indeks jest zdefiniowany w następujący sposób (include\tiny_obj_loader.h:207)
typedef struct {
  int vertex_index;
  int normal_index;
  int texcoord_index;
} index_t;

I każdy wierzchołek jest zdefiniowany w następujący sposób:
Teraz każdy indeks generuje następujący wierzchołek:
[code]
index_t idx = indices[i];
{
  vec3 vertexPosition = postions[idx.vertex_index];
  vec2 vertexST = texcoords[idx.texcoord_index];
  vec3 vertexNormal = normals[idx.normal_index];
};

Ty ładując model zakładasz, że vertex_index == normal_index == texcoord_index (Mesh.cpp:158).

Oczywiście w przypadku tekstur ci się udało, bo akurat texcoordy są w miarę unikalne i ich indeksy się pokryły.

To co musisz zrobić to przy ładowaniu przekonwertować model z jednego formatu OBJowego na taki który będzie pasował OpenGLowi.

BTW. Assimp robi takie rzeczy automatycznie, więc może powalcz ze zbudowaniem go (HINT: ASSIMP_BUILD_ZLIB) :)

BTW2. Wiem, że może Ci się wydawać to mordęgą, ale polecam zacząć czytać specyfikację OpenGL i GLSL. Od deski do deski. I nie chodzi tu o to, abyś recytował wszystkie funkcje na pamięć, tylko abyś wiedział mniej/więcej co i jak działa oraz co i jak robić. Googlowanie za rozwiązaniami i pisanie kodu jest potem 10x łatwiejsze.

Offline ekicam2

  • Użytkownik

# Lipiec 15, 2017, 01:30:18
@karol57
Dzięki za rozwinięcie tematu i wyczerpującą odpowiedź. Przejdę na assimpa tak czy siak ponieważ tinyobj wspiera jak sama nazwa wskazuje tylko *.obj co nie do końca mi odpowiada :)

Aczkolwiek w roli ćwiczenia naklepałem coś na kolanie, przydałaby się tu jeszcze jakaś optymalizacja :)
    bool Mesh::LoadFromFile(const string & FilePath)
    {
        //Assimp::Importer importer;
        //const aiScene* scene = importer.ReadFile(FilePath.c_str(), 0);
        //
        //for (unsigned i = 0; i < scene->mNumMeshes; ++i)
        //{
        //    auto mesh = scene->mMeshes[i];
        //   
        //    mesh->mNumVertices;
        //   
        //    mesh->mVertices;
        //    mesh->mTextureCoords;
        //    mesh->mNormals;
        //}
           
        PathToFile = FilePath;
 
        tinyobj::attrib_t attrib;
        std::vector<tinyobj::shape_t> shapes;
        std::vector<tinyobj::material_t> materials;
        std::string err;
 
        if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, PathToFile.c_str()))
        {
            cerr << err << endl;
            return false;
        }
 
        for (const auto& shape : shapes)
        {
            vector<glm::vec3> positions;
            vector<glm::vec2> uvs;
            vector<glm::vec3> normals;
            vector<uint16_t> indices;

            for (const auto& index : shape.mesh.indices)
            {
                positions.push_back({
                    attrib.vertices.at(3 * index.vertex_index + 0),
                    attrib.vertices.at(3 * index.vertex_index + 1),
                    attrib.vertices.at(3 * index.vertex_index + 2)
                });

                uvs.push_back({
                    attrib.texcoords.at(2 * index.texcoord_index + 0),
                    attrib.texcoords.at(2 * index.texcoord_index + 1)
                });

                normals.push_back({
                    attrib.normals.at(3 * index.normal_index + 0),
                    attrib.normals.at(3 * index.normal_index + 1),
                    attrib.normals.at(3 * index.normal_index + 2)
                });

                indices.push_back(indices.size());
            }

            Vertices = (std::move(positions));
            TextureCoords = std::move(uvs);
            Normals = std::move(normals);
            Indices = std::move(indices);
        }
 
 
        return true;
    }

W załączniku screen.

Dzięki wszystkim za pomoc i do usłyszenia!!