GLSL Lighting математика запуталась, не могу найти ошибку - PullRequest
0 голосов
/ 13 декабря 2018

Я следовал учебному пособию по освещению от learnopengl.com, но по какой-то причине мое освещение было испорчено, и я не знаю почему.У меня есть естественное освещение, чтобы работать легко, рассеянный свет отчасти искажен, и зеркальный свет повсюду, и я понятия не имею, где искать, чтобы это исправить.https://gyazo.com/f66efc10d41806504e9e34f45415bcfe Я также не уверен, что мои нормы были сделаны правильно.Вот как я генерирую их с std::vector<glm::vec3> позициями и std::vector<unsigned int> индексами.

void ModMesh::generateVertexNormals() {
    if(!positions.empty() || !indices.empty()) {
        normals.clear();
        for(unsigned int i = 0; i < indices.size(); i += 3) {
            auto const a = indices[i + 0];
            auto const b = indices[i + 1];
            auto const c = indices[i + 2];
            auto const verta = positions[a];
            auto const vertb = positions[b];
            auto const vertc = positions[c];
            auto const norm = glm::normalize(glm::cross(verta - vertb, vertc - vertb));
            normals.push_back(norm);
        }
    }
}

Вот как я связываю свои данные:

void ModMesh::generateVBO_Positions() {
    if(positions.empty()) 
        return;
    glBindBuffer(GL_ARRAY_BUFFER, vbo[VBO::POS]);
    std::vector<float> p;
    for(int i = 0; i < positions.size(); i++) {
        p.push_back(positions[i].x);
        p.push_back(positions[i].y);
        p.push_back(positions[i].z);
    }
    glBufferData(GL_ARRAY_BUFFER, p.size() * sizeof(float), &p[0], GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
}

void ModMesh::generateVBO_Normals() {
    if(normals.empty()) 
        return;
    glBindBuffer(GL_ARRAY_BUFFER, vbo[VBO::NORM]);
    std::vector<float> n;
    for(int i = 0; i < positions.size(); i++) {
        n.push_back(positions[i].x);
        n.push_back(positions[i].y);
        n.push_back(positions[i].z);
    }
    glBufferData(GL_ARRAY_BUFFER, n.size() * sizeof(float), &n[0], GL_STATIC_DRAW);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(2);
}

Вот мойкод.

Вершина

#version 330 core

layout(location = 0) in vec3 iPosition;
layout(location = 1) in vec2 iTexcoord;
layout(location = 2) in vec3 iNormal;

uniform mat4 iProjection;
uniform mat4 iView;
uniform mat4 iModel;

out vec2 texcoord;
out vec3 normal;
out vec3 fragpos;

void main() {
   gl_Position = iProjection * iView * iModel * vec4(iPosition, 1.0);
   texcoord = iTexcoord;
   normal = iNormal;
   fragpos = vec3(iModel * vec4(iPosition, 1.0));
}

Фрагмент

#version 330 core

in vec2 texcoord;
in vec3 normal;
in vec3 fragpos;

uniform sampler2D iTexture;
uniform vec3 iCameraView;
uniform int iUseTexture = 0;
out vec4 outputcolor;

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};
uniform Light iLight;

struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};
uniform Material iMaterial;

void main() {

   float ambientstrength = 0.15;
   float specularstrength = 0.75;

   vec3 norm = normalize(normal);
   vec3 lightdir = normalize(iLight.position - fragpos);

   vec3 ambient = iLight.ambient * iMaterial.ambient;
   vec3 viewdir = normalize(iCameraView - fragpos);
   vec3 reflectdir = reflect(-lightdir, norm);

   float diff = max(dot(norm, lightdir), 0.0);
   float spec = pow(max(dot(viewdir, reflectdir), 0.0), iMaterial.shininess);

   vec3 diffuse = (diff * iMaterial.diffuse) * iLight.diffuse;
   vec3 specular = specularstrength * spec * iLight.specular;
   vec4 light = vec4(ambient + diffuse + specular, 1.0);


   outputcolor = mix(vec4(0.0, 1.0, 0.0, 1.0) * light, texture2D(iTexture, texcoord) * light, iUseTexture); 
}

Фрагмент C ++, main.cpp:

olib::Camera cam(0.0f, 0.5, -3.0f); // My camera object, just the position XYZ
glm::mat4 proj(1.0);
glm::mat4 view(1.0);
glm::mat4 model(1.0);
proj = glm::perspective(glm::radians(45.0f), (float)win.getWidth() / (float)win.getHeight(), 0.1f, 500.0f);

while(win.isOpen()) {
    sh.enable();
    sh.uniformMat4("iProjection", proj);
    sh.uniformMat4("iView", view);
    sh.uniformMat4("iModel", model);
    sh.uniform3f("iCameraView", cam.getPosition());

    sh.uniform3f("iLight.position", 0, 0.5, -3);
    sh.uniform3f("iLight.ambient", 0.14, 0.14, 0.14);
    sh.uniform3f("iLight.diffuse", 0.64, 0.64, 0.64);
    sh.uniform3f("iLight.specular", 0.84, 0.84, 0.84);    
    view = cam.getViewMatrix();
    // Then drawing
}

Это столько данных, сколько яверить это важно.Incase это не здесь, GitHub.https://github.com/LoneC/OpenGL-Project/tree/master

1 Ответ

0 голосов
/ 13 декабря 2018

Прежде всего, вы на правильном пути с этой процедурой: "void ModMesh :: generateVertexNormals ()".Вы генерируете лицевую нормаль каждого треугольника для установки Front = CCW в OpenGL.Дело в том, что вы генерируете одну нормаль на треугольник, и в вашем вершинном шейдере нормаль передается на вершину.Но в вашем случае вы генерируете 1 нормаль на треугольник!После этого вам нужно пройти через каждую позицию вершины, и для каждого треугольника, который использует эту позицию, получить их нормаль, а затем усреднить эту нормаль.Таким образом вы сглаживаете нормали треугольников в каждой вершине.Позвольте мне объяснить более графически: enter image description here

Я должен добавить, что вы также в настоящее время загружаете позиции в нормали VBO, но об этом я и говорил вам вкомментарии.

Если вы на самом деле хотите плоское затенение, то, насколько я могу судить прямо сейчас, вы должны отбросить индексы и использовать 3 позиции на треугольник, каждая с нормалями, взятыми из текущего метода нормального генерирования.в каждой позиции, как на втором шаге моего рисунка.Кстати, простите мою краску.

...