Артефакты освещения ландшафта OpenGL 3D

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

Я получаю странные темные линии по краям треугольников, где их быть не должно. http://imgur.com/L2kj4ca

Я проверил правильность нормалей, используя геометрический шейдер для рисования нормалей на местности, и они кажутся правильными. http://imgur.com/FrJpdXI

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

Я не знаю, как это решить. Я не мог найти никакого рабочего решения в Интернете.

Вершинный шейдер ландшафта:

#version 330 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 textureCoords;

out vec2 pass_textureCoords;
out vec3 surfaceNormal;
out vec3 toLightVector;
out float visibility;

uniform mat4 transformationMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

uniform vec3 lightPosition;

const float density = 0.0035;
const float gradient = 5.0;

void main()
{
    vec4 worldPosition = transformationMatrix * vec4(position, 1.0f);
    vec4 positionRelativeToCam = viewMatrix * worldPosition;

    gl_Position = projectionMatrix * positionRelativeToCam;
    pass_textureCoords = textureCoords;

    surfaceNormal = (transformationMatrix * vec4(normal, 0.0f)).xyz;
    toLightVector = lightPosition - worldPosition.xyz;

    float distance = length(positionRelativeToCam.xyz);
    visibility = exp(-pow((distance * density), gradient));
    visibility = clamp(visibility, 0.0, 1.0);
}

Шейдер фрагментов ландшафта:

#version 330 core

in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
in float visibility;

out vec4 colour;

uniform vec3 lightColour;
uniform vec3 fogColour;

uniform sampler2DArray blendMap;
uniform sampler2DArray diffuseMap;

void main()
{
    vec4 blendMapColour = texture(blendMap, vec3(pass_textureCoords, 0));

    float backTextureAmount = 1 - (blendMapColour.r + blendMapColour.g + blendMapColour.b);
    vec2 tiledCoords = pass_textureCoords * 255.0;
    vec4 backgroundTextureColour = texture(diffuseMap, vec3(tiledCoords, 0)) * backTextureAmount;
    vec4 rTextureColour = texture(diffuseMap, vec3(tiledCoords, 1)) * blendMapColour.r;
    vec4 gTextureColour = texture(diffuseMap, vec3(tiledCoords, 2)) * blendMapColour.g;
    vec4 bTextureColour = texture(diffuseMap, vec3(tiledCoords, 3)) * blendMapColour.b;

    vec4 diffuseColour = backgroundTextureColour + rTextureColour + gTextureColour + bTextureColour;

    vec3 unitSurfaceNormal = normalize(surfaceNormal);
    vec3 unitToLightVector = normalize(toLightVector);

    float brightness = dot(unitSurfaceNormal, unitToLightVector);
    float ambient = 0.2;
    brightness = max(brightness, ambient);
    vec3 diffuse = brightness * lightColour;

    colour = vec4(diffuse, 1.0) * diffuseColour;
    colour = mix(vec4(fogColour, 1.0), colour, visibility);
}

person Simon Mathay    schedule 24.02.2016    source источник
comment
Триангуляция моих тайлов ландшафта выглядит следующим образом: imgur.com/t8DOkTJ получил различные темные линии возле краев треугольников. Эффект, который я ищу на своем ландшафте, выглядит следующим образом: imgur.com/9Jx2g24 .   -  person Simon Mathay    schedule 24.02.2016
comment
Предоставьте еще два изображения: каркас геометрии + нормали, закодированные в цвет из пиксельного шейдера. Это должно приблизить нас к решению.   -  person mrVoid    schedule 24.02.2016
comment
Простите, mrVoid, что вы имеете в виду? Код геометрического шейдера и фрагментного шейдера для рисования векторов нормалей?   -  person Simon Mathay    schedule 25.02.2016
comment
Он хочет превратить нормали вершин в компонент цвета, используя surfaceNormal в качестве значения color.   -  person Colin Basnett    schedule 25.02.2016
comment
Я использовал этот код для визуализации векторов нормалей: learnopengl.com/#!Advanced-OpenGL/ Geometry-Shader Прокрутите вниз до раздела Визуализация векторов нормалей.   -  person Simon Mathay    schedule 25.02.2016
comment
Я подозреваю, что проблема в неправильном расчете нормалей. Вот почему я хотел, чтобы они кодировались цветом. Обычно вы хотите получить средневзвешенное значение от соседних граней, чтобы оно соответствовало выбранной схеме тирангуляции.   -  person mrVoid    schedule 25.02.2016
comment
Я использую этот метод: stackoverflow.com/questions/13983189/ Чтобы вычислить нормали, я даже использовал другой метод с перекрестными произведениями, и я получаю точно такой же результат, я бы не публиковал этот вопрос, если бы не не уверен, что мои нормы были правильными.   -  person Simon Mathay    schedule 25.02.2016


Ответы (2)


Это может быть либо две проблемы:

<сильный>1. Неверные нормали: Существуют различные типы затенения: плоское затенение, затенение по Гуро и затенение по Фонгу (отличное от отражения по Фонгу) пример :

Обычно вы хотите сделать затенение Фонга. Чтобы сделать это, OpenGL упрощает вашу жизнь и интерполирует для вас нормали между каждой вершиной каждого треугольника, так что в каждом пикселе у вас есть правильная нормаль для этой точки: но вам все равно нужно передать ему правильные значения нормалей, которые являются средними нормалей каждого треугольника, присоединенного к этой вершине. Таким образом, в вашей функции, которая создает вершину, нормали и UV, вам нужно вычислить нормаль в каждой вершине, усредняя каждую нормаль треугольника, прикрепленную к этой вершине. иллюстрация

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

Может быть, если вы можете предоставить свой код и шейдеры, может быть, даже карту высот, чтобы мы могли точно определить, что происходит в вашем случае.

person jubertal    schedule 24.02.2016
comment
Да, я делаю затенение по Фонгу, однако я пока не использую никакого зеркального освещения, я сделаю это позже, это не сложно. Чтобы вычислить вектор нормалей, я использую этот метод: stackoverflow.com/questions/13983189/ - person Simon Mathay; 25.02.2016
comment
Я использую карту высот размером 256x256: imgur.com/GHm9GbD Один пиксель на карте высот соответствует одной вершине на местности. поэтому мой ландшафт имеет 256x256 вершин. У меня размер плитки 3.0, поэтому ширина и высота ландшафта будут 256 x 3. - person Simon Mathay; 25.02.2016
comment
Я определил максимальное значение высоты 50, поэтому самая высокая точка (полностью белая) равна 50, а самая низкая точка (полностью черная) равна -50. Это означает, что разница в высоте одного цвета пикселя составляет 0,39. Таким образом, высота пикселя с цветом (128, 128, 128) равна 0, а (129 129 129) равна 0,39. - person Simon Mathay; 25.02.2016
comment
Кстати, этот метод расчета нормалей: stackoverflow.com/questions/13983189/ Они поменяли ось y на ось z, чтобы вы знали... поначалу это может сбивать с толку, поэтому в основном я использую : vertices[i].normal = glm::normalize(glm::vec3(heightL - heightR, 2.0f, heightB - heightF)); - person Simon Mathay; 25.02.2016
comment
Хорошо, возможно, попробуйте другую карту высот с более высоким размером (1024x1024), чтобы увидеть, есть ли у вас та же проблема. - person jubertal; 25.02.2016
comment
И уменьшить размер плитки, я думаю? Или же использование большей карты высот просто сделает местность больше. Ок попробую. - person Simon Mathay; 25.02.2016
comment
У меня все та же проблема, но с этой картой высот 1024x1024 я просто получаю большую разницу в высоте между одним пикселем. imgur.com/JJLjWiz - person Simon Mathay; 25.02.2016

Это старо, но я подозреваю, что вы не преобразуете свою нормаль, используя транспонированную инверсию верхней части 3x3 вашей матрицы просмотра модели. См. это. Не уверен, что находится в «transformationMatrix», но если вы используете его для преобразования вершины и нормали, что-то, вероятно, подозрительно...

person Bim    schedule 02.06.2017