Затенение по Фонгу и Горауду - необходимо знать, как фрагменты затеняются - PullRequest
2 голосов
/ 04 апреля 2020

Единственное практическое отличие от затенения Фонга и затенения Гораудо состоит в том, что если вычисление цвета фрагмента выполняется в вершинном шейдере, то это Горауд, иначе это фонг. У меня есть небольшой код кода вершинного шейдера и фрагментного шейдера ниже:

//vertexShader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 FragPos;
out vec3 Normal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;  

    gl_Position = projection * view * vec4(FragPos, 1.0);
}  


//FragmentShader.fs
#version 330 core
out vec4 FragColor;

in vec3 Normal;  
in vec3 FragPos;  

uniform vec3 lightPos; 
uniform vec3 viewPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0),32);
    vec3 specular = specularStrength * spec * lightColor;  

    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
} 

Оказывается, Phong выглядит немного более гладко на объектах с низким поли. Итак, барьер знаний заключается в том, как фрагменты становятся шейдерами. Сначала давайте посмотрим, что уже предоставляет замечательный ресурс learnopenGL .

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

Но, как и модель затенения Фонга , где вычисление выполняется прямо в фрагментном шейдере, что происходит? Как затенены пиксели фрагмента? Скажем, есть три вершины, тогда фрагмент полностью окрашен первым цветом, полностью вторым, а затем третьим, и является ли общая медиана взятых цветов или что-то еще? Как заштриховывается фрагмент при расчете внутри фрагментного шейдера?

Ответы [ 2 ]

2 голосов
/ 04 апреля 2020

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

В вашем особом случае это означает, что Normal и FragPos различны для каждого фрагмента. Каждый треугольник имеет 3 угла. Normal и FragPos вычисляются для каждого угла треугольника в вершинном шейдере. Атрибуты для углов интерполируются для каждого фрагмента, который покрыт треугольником, и эти интерполированные векторы являются входными данными для шейдерного фрагмента.
Поскольку каждый фрагмент имеет различный вход (Normal и FragPos), вычисляемый вывод (FragColor) отличается для каждого фрагмента.
Вывод немного отличается для соседних фрагментов, потому что ввод также отличается незначительно. Это вызывает плавное освещение.

Обратите внимание, что даже если вектор нормали (Normal) является нормалью грани (такой же нормалью для 3 вершин), тогда все равно FragPos отличается.

Кроме того, подсветка сплайса (float spec = pow(max(dot(viewDir, reflectDir), 0.0),32)) не является линейной функцией. Таким образом, зеркальное выделение не может быть правильно рассчитано с помощью линейной интерполяции. Это должно быть вычислено для каждого фрагмента.
На самом деле есть разница, если Normal и FragPos интерполированы и result вычислено в фрагментном шейдере, по сравнению, когда result вычислено в вершинном шейдере и интерполируется по фрагментам.


Атрибуты вершины являются входными данными для вершинного шейдера. Выходные данные вершинного шейдера интерполируются (всегда), а интерполированные значения являются входными данными для фрагментного шейдера ( Растеризация ). Вывод фрагментирующего шейдера записывается в кадровый буфер:

vertex attrtibutes -> vertex shader -> интерполяция / растеризация -> фрагментный шейдер -> framebuffer.

Для получения дополнительной информации о рендеринге трубопровод см. Визуализация конвейера. Обзор .

2 голосов
/ 04 апреля 2020

Разница между штриховкой Фонга и Гуро заключается в том, что:

  • Гуро в среднем цвета . Цвет вычисляется на основе вершинной нормали вершинным шейдером, а затем усредняется между фрагментами одного треугольника на основе расстояния от каждой вершины треугольника.
  • Фонг в среднем нормали . Цвет вычисляется с помощью Fragment Shader на основе усреднения 3 вершинных нормалей треугольника, прошедшего через Vertex Shader.

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

На низкополигональном sh усреднение затененных цветов в Гуро дает худший визуальный результат, потому что усреднение цветов практически не имеет физического смысла.

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

Усреднение выполняется не самой программой Shader, а фиксированной аппаратной функциональностью между этапами шейдера Vertex и Fragment. Таким образом, когда вы вычисляете цвет или проходные нормальные / ультрафиолетовые координаты и т.п. в Vertex Shader, эти значения интерполируются аппаратно между 3 вершинами по всем фрагментам внутри треугольника на основе фрагмента barycentri c координаты .

Цвет, вычисленный в Fragment Shader, является окончательным (до применения теста Blending или Stencil, который также выполняется с помощью фиксированной аппаратной функциональности). Таким образом, размещение вычислений освещения внутри шейдера Vertex of Fragment определяет, что будет интерполироваться, а что вычисляться напрямую.

...