Почему мои нормали не интерполируются между вершинами, создавая эффект плоского затенения? - PullRequest
0 голосов
/ 01 июня 2019

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

Я реализую отложенный рендеринг, поэтому в моем проходе геометрии я сохраняю положение вершины и нормали в текстурах.На этапе освещения я выводил нормали в виде цвета, чтобы проверить их «значения».
РЕДАКТИРОВАТЬ 1 Мой Gbuffer использует две текстуры для хранения позиций и нормалей.Обе текстуры используют формат GL_RGB16F.

РЕДАКТИРОВАТЬ 5 Как вы можете видеть на этом изображении enter image description here Я не получаю элегантного цветового перехода.Голова слева - результат моего двигателя, справа вы можете увидеть ту же модель в Blender.В Blender нормали (синим цветом) выглядят корректно (без дубликатов и т. Д.), Но в моем движке они ведут себя как нормаль лица (каждые 4 показывают в одном направлении).Я использую Assimp для загрузки моделей и при импорте их включаю флаг aiProcess_GenSmoothNormals.

Вершинный шейдер с геометрическим проходом:

#version 440 core

layout (location = 0) in vec4 positionOS;
layout (location = 1) in vec3 normalOS;
layout (location = 2) in vec2 uv;

out VertexData
{
    vec3 PositionVS;
    vec3 NormalVS;
    vec2 UV;
} vs_out;

uniform mat3 normalViewMatrix;
uniform mat4 modelViewMatrix;

struct Camera
{
    mat4 viewMatrix;
    mat4 projMatrix;
};

layout(std140, binding = 0) uniform CameraBlock
{
    Camera cam;
};

void main()
{
    vec4 positionVS = modelViewMatrix * positionOS;
    vs_out.PositionVS = positionVS.xyz;
    vs_out.NormalVS = normalViewMatrix * normalOS;
    vs_out.UV = uv;

    gl_Position = cam.projMatrix * positionVS;
}

Фрагментный шейдер с геометрическим проходом:

#version 440 core

layout (location = 0) out vec3 PositionVS;
layout (location = 1) out vec3 NormalVS;

in VertexData
{
    vec3 PositionVS;
    vec3 NormalVS;
    vec2 UV;
} vs_in;

void main()
{
    PositionVS = vs_in.PositionVS;
    NormalVS = normalize(vs_in.NormalVS);
}

РЕДАКТИРОВАТЬ 4 Чтение значений вершин из Assimp (aiMesh)

void MeshLoader::prepareMesh(const aiMesh & mesh)
{
    { // vertices

        for (int i = 0; i < mesh.mNumVertices; i++) {
            if (mesh.HasPositions()) {
                glm::vec3 position = glm::vec3(mesh.mVertices[i].x, mesh.mVertices[i].y, mesh.mVertices[i].z);

                positions.emplace_back(position.x, position.y, position.z, 1);
            }

            if (mesh.HasNormals()) {
                normals.emplace_back(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z);
            }

            if (mesh.HasTangentsAndBitangents()) {
                tangents.emplace_back(mesh.mTangents[i].x, mesh.mTangents[i].y, mesh.mTangents[i].z);
                bitangents.emplace_back(mesh.mBitangents[i].x, mesh.mBitangents[i].y, mesh.mBitangents[i].z);
            }

            if (mesh.HasTextureCoords(0)) {
                uvs.emplace_back(mesh.mTextureCoords[0][i].x, mesh.mTextureCoords[0][i].y);
            }

        }
    }

    { // polygons
        numFaces = mesh.mNumFaces;

        for (int i = 0; i < numFaces; i++) {
            indices.push_back(mesh.mFaces[i].mIndices[0]);
            indices.push_back(mesh.mFaces[i].mIndices[1]);
            indices.push_back(mesh.mFaces[i].mIndices[2]);
        }
    }
}

Я хотел бы найти решение для этого беспорядка.Я знаю, что нормали - это проблема, но я не могу понять, почему.
РЕДАКТИРОВАТЬ 2 По виду сферы это похоже на проблему интерполяции, отсюда и код шейдера выше.Если шейдеры верны, то, возможно, проблема связана с классом импорта?
РЕДАКТИРОВАТЬ 3 Я также реализовал версию рендеринга вперед и отображаю нормали в цвете, но я получаю тот же результат, что и вотложенная версия.

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Я использую Assimp для загрузки моделей и включаю флаг aiProcess_GenSmoothNormals при их импорте.

Из документации :

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

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

  1. Экспорт модели с правильными гладкими нормами.(Лучший вариант, потому что это дает вам полный контроль над нормалями, сохранение нужных резких граней и т. Д. Также при необходимости уменьшается вычисление.)
  2. Принудительное использование ассимпа для пересчета нормалей.Посмотрите на флаг aiProcess_RemoveComponent:

    Этот шаг также полезен, если вы хотите заставить Assimp пересчитать нормали или касательные.Соответствующие шаги не пересчитывают их, если они уже там (загружены из исходного ресурса).Используя этот шаг, вы можете убедиться, что их там нет.

0 голосов
/ 01 июня 2019

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

Второе, на что вам следует обратить внимание, это то, что в glsl отрицательные значения цвета будут вырезаны при записи в буфер текстур, так как буферы текстур не подписаны. Попробуйте использовать какой-либо метод конвертации для преобразования цветовых данных в векторные, и наоборот. Методы

vec4 toCoord(vec4 color) {
    return vec4(2.0 * color.xyz - vec3(1, 1, 1), color.w);
}

vec4 toColor(vec4 coord) {
    return vec4(0.5 * coord.xyz + vec3(0.5, 0.5, 0.5), coord.w);
}

должно работать просто отлично для этого. Если вы еще не сделали одну из этих двух вещей, попробуйте:)

Если это не сработает, некоторые полезные способы записи и чтения обычных данных в фрагментных шейдерах в буферы текстур и из них будут полезны:)

...