Войти
OpenGL communityФорумВопросы по программированию

Загрузка .obj модели через assimp

#0
22:50, 12 июня 2020

Добрый день! Я использую OpenGL v.3.3. и примеры кода для загрузки модели с сайта learnopengl.com.У меня получилось загрузить текстурную модель из туториала (nanosuit.obj),но когда я пробую загрузить другие модели .obj без текстур, но в комплекте с .mtl файлами результат отрисовки получается не понятный, модель темная без цветов. Мне кажется что то не так с кодом шейдеров, но не уверен в этом и не знаю как решить проблему.. Прошу помощи. Строго не судите с openGL начал работать как 3-й день только., с разработкой игр я никак не связан. Задача просто загрузить 3d модель на форму MFC C++, чтобы цвета нормально отображались

Здесь код основных функций отрисовки:

     void COpenGLControl::oglInitialize(void)
        {
          
          static PIXELFORMATDESCRIPTOR pfd =
          {
            sizeof(PIXELFORMATDESCRIPTOR),
            1,
            PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
            PFD_TYPE_RGBA,
            32, // bit depth
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            16, // z-buffer depth
            0, 0, 0, 0, 0, 0, 0,
          };
          
          // Get device context only once.
          hdc = GetDC()->m_hDC;
          
          // Pixel format.
          m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
          SetPixelFormat(hdc, m_nPixelFormat, &pfd);
    
          // Create the OpenGL Rendering Context.
          hrc = wglCreateContext(hdc);
          wglMakeCurrent(hdc, hrc);
          
          if (!gladLoadGL())
          {
            AfxMessageBox(L"Error loading glad");
            return;
          }
          // configure global opengl state
          // -----------------------------
          glEnable(GL_DEPTH_TEST);
    
          // build and compile shaders
          ourShader = Shader("resource/shaders/modelLoading.vs", "resource/shaders/modelLoading.frag");
    
          // load models
          ourModel = Model("resource/models/car12/LaFerrari.obj");
          
          
          
          // Send draw request
          OnDraw(NULL);
        }
    
        void COpenGLControl::oglDrawScene(void)
        {
          
          // render
          // ------
          glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
          // don't forget to enable shader before setting uniforms
          ourShader.use();
    
          // view/projection transformations
          glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)900 / (float)900, 0.1f, 100.0f);
          glm::mat4 view = camera.GetViewMatrix();
          ourShader.setMat4("projection", projection);
          ourShader.setMat4("view", view);
    
          // render the loaded model
          glm::mat4 model = glm::mat4(1.0f);
          model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
          model = glm::scale(model, glm::vec3(0.010f, 0.010f, 0.010f));
          model = glm::rotate(model, glm::radians(-30.0f), glm::vec3(0.0f, 1.0f, 0.0f));
          model = glm::rotate(model, glm::radians(20.0f), glm::vec3(1.0f, 0.0f, 0.0f));
          ourShader.setMat4("model", model);
          ourModel.Draw(ourShader);
        }

Во вложении прикрепил весь остальной код проекта + скриншоты 3d модели (темная это которая получается в результате работы моей программы, цветная это так выглядит модель в Obj просмотршиках пробовал стандартный Windows и Ab Viewer)

Файлы для скачивания:

https://gamedev.ru/files/?id=147328


#1
8:06, 13 июня 2020

mtl файл в студию. А еще не понятно, как у Вас работает шейдер с

#version 330 core
ез инициализации профиля ядра. Насколько я помню, без WGL_CONTEXT_PROFILE_MASK_ARB или GLX_CONTEXT_PROFILE_MASK_ARB, становленной в WGL_CONTEXT_CORE_PROFILE_BIT_ARB или GLX_CONTEXT_CORE_PROFILE_BIT_ARB ни такой заголовок шейдера, ни лэйауты работать не должны.

#2
11:54, 13 июня 2020
uniform sampler2D texture_diffuse;
void main( )
{
    color = vec4( texture( texture_diffuse, TexCoords ));
}

Боюсь "просто" поправить не получится - шейдер просто выводит цвет текстуры.
Когда текстуры в модели нет, то шейдер пытается читать из не привязанной текстуры - поэтому и получается чёрный цвет.

Если избавиться от чтения из несуществующей текстуры, то всю модель можно нарисовать каким-то общим цветом - например, прочитанным материалом из MTL файла, переданным через uniform'у. Но тогда модель будет равномерно одного цвета, без различимого объёма.

Поэтому обязательно необходимо добавить формулы вычисления освещения - хотя бы по Фонгу, - а так же источники света.

В общем лучше читайте дальше уроки по OpenGL и вернитесь на форум с более конкретными вопросами, нежели "я скопировал какой-то код, который не понимаю, но он почему-то не работает для других моделей".

#3
13:24, 13 июня 2020

DimaO
> mtl файл в студию. А еще не понятно, как у Вас работает шейдер с
>
> #version 330 core
> ез инициализации профиля ядра. Насколько я помню, без
> WGL_CONTEXT_PROFILE_MASK_ARB или GLX_CONTEXT_PROFILE_MASK_ARB, становленной в
> WGL_CONTEXT_CORE_PROFILE_BIT_ARB или GLX_CONTEXT_CORE_PROFILE_BIT_ARB ни такой
> заголовок шейдера, ни лэйауты работать не должны.

Добрый день! Спасибо за комментарии, но с текстурами видимо как-то работает и без этих макросов...

.mtl файл выложил по ссылке: https://gamedev.ru/files/?id=147337

саму модель выложил здесь: https://ru.files.fm/u/76565smh

#4
13:51, 13 июня 2020

gkv311
> Боюсь "просто" поправить не получится - шейдер просто выводит цвет текстуры.
> Когда текстуры в модели нет, то шейдер пытается читать из не привязанной
> текстуры - поэтому и получается чёрный цвет.
>
> Если избавиться от чтения из несуществующей текстуры, то всю модель можно
> нарисовать каким-то общим цветом - например, прочитанным материалом из MTL
> файла, переданным через uniform'у. Но тогда модель будет равномерно одного
> цвета, без различимого объёма.
>
> Поэтому обязательно необходимо добавить формулы вычисления освещения - хотя бы
> по Фонгу, - а так же источники света.
>
> В общем лучше читайте дальше уроки по OpenGL и вернитесь на форум с более
> конкретными вопросами, нежели "я скопировал какой-то код, который не понимаю,
> но он почему-то не работает для других моделей".

Благодарю Вас за подробный развернутый ответ, не судите строго но изучать Open GL начал как неделю назад. Уроки learnopengl прочитал до конца, но там есть примеры как привязать источники света к простой геометрической фигуре куб., я пробовал запустить шейдеры phong из примера применительно к моей модели., но к сожалению положительного результата добиться не смог.. в примерах этих уроков не нашел объяснений каким образом нужно доработать код model.h, shader.h и что необходимо доработать в самих шейдерах (вершинный + фрагментный).

Вопрос еще раз постараюсь конкретизировать:

Не знаю как передать материалы из файла .mtl (цвета, свет, прозрачность, и т.д.) в вершинный и фрагментный шейдеры для того чтобы модель корректно отображалась без текстур, а именно:

1. Прошу  помочь с примерами кода шейдеров (вершинный + фрагментный) и если требуется корректировка в существующем коде model.h shader.h подсказать в какую сторону копать...

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

VS

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

// declare an interface block; see 'Advanced GLSL' for what these are.
out VS_OUT {
    vec3 FragPos;
    vec3 Normal;
    vec2 TexCoords;
} vs_out;

uniform mat4 projection;
uniform mat4 view;

void main()
{
    vs_out.FragPos = aPos;
    vs_out.Normal = aNormal;
    vs_out.TexCoords = aTexCoords;
    gl_Position = projection * view * vec4(aPos, 1.0);
}

FS

#version 330 core
out vec4 FragColor;

in VS_OUT {
    vec3 FragPos;
    vec3 Normal;
    vec2 TexCoords;
} fs_in;

uniform sampler2D floorTexture;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform bool blinn;

void main()
{           
    vec3 color = texture(floorTexture, fs_in.TexCoords).rgb;
    // ambient
    vec3 ambient = 0.05 * color;
    // diffuse
    vec3 lightDir = normalize(lightPos - fs_in.FragPos);
    vec3 normal = normalize(fs_in.Normal);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * color;
    // specular
    vec3 viewDir = normalize(viewPos - fs_in.FragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    if(blinn)
    {
        vec3 halfwayDir = normalize(lightDir + viewDir);  
        spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
    }
    else
    {
        vec3 reflectDir = reflect(-lightDir, normal);
        spec = pow(max(dot(viewDir, reflectDir), 0.0), 8.0);
    }
    vec3 specular = vec3(0.3) * spec; // assuming bright white light color
    FragColor = vec4(ambient + diffuse + specular, 1.0);
}

Прошу помочь разобраться. Спасибо.

#5
(Правка: 14:06) 14:04, 13 июня 2020

Материалы из файла .mtl считываю в классе модели model.cpp с помощью assimp следующим образом:

  aiColor3D color;
    Material mat;
    // Read mtl file vertex data
    material->Get(AI_MATKEY_COLOR_AMBIENT, color);
    mat.Ka = glm::vec4(color.r, color.g, color.b, 1.0);
    material->Get(AI_MATKEY_COLOR_DIFFUSE, color);
    mat.Kd = glm::vec4(color.r, color.g, color.b, 1.0);
    material->Get(AI_MATKEY_COLOR_SPECULAR, color);
    mat.Ks = glm::vec4(color.r, color.g, color.b, 1.0);


model.cpp
 

 Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
{
    // data to fill
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;

    // Walk through each of the mesh's vertices
    for (unsigned int i = 0; i < mesh->mNumVertices; i++)
    {
        Vertex vertex;
        glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
        
        // positions
        if (!mesh->mVertices == NULL)
        {
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;
        }
        else
        {
            vertex.Position = glm::vec3(0.0f, 0.0f, 0.0f);
            //AfxMessageBox(L"Positions is NULL");
        }

        // normals
        if (!mesh->mNormals == NULL)
        {
            vector.x = mesh->mNormals[i].x;
            vector.y = mesh->mNormals[i].y;
            vector.z = mesh->mNormals[i].z;
            vertex.Normal = vector;
        }
        else
        {
            vertex.Normal = glm::vec3(0.0f, 0.0f, 0.0f);
            //AfxMessageBox(L"Normals is NULL");
        }

        // texture coordinates
        if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
        {
            glm::vec2 vec;
            // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't 
            // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
            vec.x = mesh->mTextureCoords[0][i].x;
            vec.y = mesh->mTextureCoords[0][i].y;
            vertex.TexCoords = vec;
        }
        else
        {
            vertex.TexCoords = glm::vec2(0.0f, 0.0f);
            //AfxMessageBox(L"TextCoords is NULL");
        }

        // tangent
        if (!mesh->mTangents == NULL)
        {
            vector.x = mesh->mTangents[i].x;
            vector.y = mesh->mTangents[i].y;
            vector.z = mesh->mTangents[i].z;
            vertex.Tangent = vector;
        }
        else
        {
            vertex.Tangent = glm::vec3(0.0f, 0.0f, 0.0f);
            //AfxMessageBox(L"TextCoords is NULL");
        }

        // bitangent
        if (!mesh->mBitangents == NULL)
        {
            vector.x = mesh->mBitangents[i].x;
            vector.y = mesh->mBitangents[i].y;
            vector.z = mesh->mBitangents[i].z;
            vertex.Bitangent = vector;
        }
        else
        {
            vertex.Bitangent = glm::vec3(0.0f, 0.0f, 0.0f);
            //AfxMessageBox(L"Bitangent is NULL");
        }

        vertices.push_back(vertex);
    }
    // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
    for (unsigned int i = 0; i < mesh->mNumFaces; i++)
    {
        aiFace face = mesh->mFaces[i];
        // retrieve all indices of the face and store them in the indices vector
        for (unsigned int j = 0; j < face.mNumIndices; j++)
            indices.push_back(face.mIndices[j]);
    }
    // process materials
    aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

   
    aiColor3D color;
    Material mat;
    // Read mtl file vertex data
    material->Get(AI_MATKEY_COLOR_AMBIENT, color);
    mat.Ka = glm::vec4(color.r, color.g, color.b, 1.0);
    material->Get(AI_MATKEY_COLOR_DIFFUSE, color);
    mat.Kd = glm::vec4(color.r, color.g, color.b, 1.0);
    material->Get(AI_MATKEY_COLOR_SPECULAR, color);
    mat.Ks = glm::vec4(color.r, color.g, color.b, 1.0);

    // we assume a convention for sampler names in the shaders. Each diffuse texture should be named
    // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. 
    // Same applies to other texture as the following list summarizes:
    // diffuse: texture_diffuseN
    // specular: texture_specularN
    // normal: texture_normalN

    // 1. diffuse maps
    vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
    textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
    // 2. specular maps
    vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
    textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    // 3. normal maps
    std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
    textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
    // 4. height maps
    std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
    textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());

    // return a mesh object created from the extracted mesh data
    return Mesh(vertices, indices, textures, mat);
}

Как их правильно передать и привязать во фрагментном шейдере вместе со светом blinn-phong не могу разобраться.

#6
16:32, 13 июня 2020

Тебе нужно завести в шейдере еще uniform vec3 или vec4 в которые передавать цвета материала загруженные из mtl

#7
(Правка: 11:14) 11:13, 14 июня 2020

Ваши материалы лежат в mat.Ka, mat.Kd и mat.Ks. Это Ваши цвета фоновый, диффузный и отраженный. Смотрите освещение по Фонгу:
1) \(diffuse=K_d\cdot max\left(\left[\vec{N}\cdot \vec{L}\right],0\right)\)
2) \(specular=Ks\cdot max\left(\left[\vec{L}\cdot \vec{R}\right],0\right)^{sp}\),
    где \(R=reflect\left(-V\cdot N\right)\),
    N - преобразованный вектор нормали,
    L - вектор направления на источник света,
    V - вектор взгляда,
    sp - коэффициент отражения.
В конце надо сложить составляющие.
То есть, грубо говоря, диффузный свет пропорционален углу между нормалью и направлением света, а отраженный -- углу между направлением взгляда и отраженным через нормаль вектором направления на источник.
Ваш шейдер цвета поверхности не учитывает. Тов. RmzVoid Вам правильно советует: добавьте в шейдер униформы, которые я указал в начале, и проинициализируйте их. Если надо учитывать фоновую составляющую, просто сложите ее с результатом.
А, вообще, загляните еще сюда: модели освещения.

OpenGL communityФорумВопросы по программированию