Почему мой шейдер OpenGL Phong ведет себя как плоский шейдер? - PullRequest
46 голосов
/ 16 января 2011

Последние пару недель я изучал OpenGL и столкнулся с некоторыми проблемами при внедрении шейдера Phong. Кажется, он не выполняет интерполяцию между вершинами, несмотря на то, что я использовал квалификатор smooth. Я что-то здесь упускаю? Чтобы отдать должное должному, код вершинного и фрагментного шейдеров сильно искажен из OpenGL SuperBible пятого издания. Я очень рекомендую эту книгу!

Вершинный шейдер:

#version 330
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;  // mvp = ModelViewProjection
uniform mat4 mvMatrix; // mv = ModelView
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;

void main(void) {
 vVaryingNormal = normalMatrix * vNormal;
 vec4 vPosition4 = mvMatrix * vVertex;
 vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
 vVaryingLightDir = normalize(vLightPosition - vPosition3);
 gl_Position = mvpMatrix * vVertex;
}

Фрагмент шейдера:

#version 330
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;

void main(void) {
 float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
 vFragColor = diff * diffuseColor;
 vFragColor += ambientColor;
 vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir),normalize(vVaryingNormal)));
 float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));

 if(diff != 0) {
   float fSpec = pow(spec, 32.0);
   vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
 }

}

Это (общедоступное) изображение из Википедии точно показывает, какое изображение я получаю и к чему стремлюсь - я получаю "плоское" изображение, но мне нужно изображение "Фонг". image

Любая помощь будет принята с благодарностью. Спасибо!

edit: Если это имеет значение, я использую PyOpenGL 3.0.1 и Python 2.6.

edit2:

Решение

Оказывается, проблема была в моей геометрии; Кос был прав. Кос указал на то, что для всех, у кого есть такая проблема с моделями Blender, выполнение Edit->Faces->Set Smooth делает свое дело. Я обнаружил, что Wings 3D работает "из коробки".

Ответы [ 2 ]

64 голосов
/ 28 февраля 2011

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

Но сначала приведем изображение гигантской головы кролика от нашего друга, кролика из Стэнфорда, в качестве примера результата!*

normals for the Stanford bunny

Главное предупреждение: обратите внимание, что мне не нужно преобразовывать нормали с помощью матрицы вида модели вместо правильной матрицы нормалей.Это не будет работать правильно, если ваше представление модели содержит неравномерное масштабирование.Кроме того, длина ваших нормалей не будет правильной, но это мало что значит, если вы просто хотите проверить их направление.

Вершинный шейдер:

#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec4 normal;
layout(location = 2) in mat4 mv;

out Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata;

uniform mat4 projection;

void main()
{
    vdata.mvp = projection * mv;
    vdata.position = position;
    vdata.normal = normal;
}

Геометрический шейдер:

#version 330
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;

in Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata[3];

out Data
{
    vec4 color;
} gdata;

void main()
{
    const vec4 green = vec4(0.0f, 1.0f, 0.0f, 1.0f);
    const vec4 blue = vec4(0.0f, 0.0f, 1.0f, 1.0f);

    for (int i = 0; i < 3; i++)
    {
        gl_Position = vdata[i].mvp * vdata[i].position;
        gdata.color = green;
        EmitVertex();

        gl_Position = vdata[i].mvp * (vdata[i].position + vdata[i].normal);
        gdata.color = blue;
        EmitVertex();

        EndPrimitive();
    }
}

Фрагмент шейдера:

#version 330

in Data
{
    vec4 color;
} gdata;

out vec4 outputColor;

void main()
{
    outputColor = gdata.color;
}
48 голосов
/ 16 января 2011

Хмм ... Вы интерполируете нормаль как переменную varying, поэтому фрагментный шейдер должен получить правильную нормаль на пиксель.

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

void main() {
   vFragColor = normalize(vVaryingNormal);
}

Если это так, то остается вопрос: почему?Вершинный шейдер выглядит хорошо.

Так, может, что-то не так в вашей геометрии ?Какие данные вы отправляете в шейдер?Вы уверены, что правильно рассчитали нормали для каждой вершины, а не только нормали для каждой грани?

normals

Оранжевые линии являются нормалями диагональной грани, красные линии - нормалямигоризонтальное лицо.

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

...