Подтвердить что ты не робот

Почему мой OpenGL Phong shader ведет себя как плоский шейдер?

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

Vertex Shader:

#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);
 }

}

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

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

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

edit2:

Решение

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

4b9b3361

Ответ 1

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

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

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

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

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

normals

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

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

Ответ 2

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

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

normals for the Stanford bunny

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

Vertex shader:

#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;
}