GLSL / OpenGL 2.1: зеркальное освещение с использованием униформы - PullRequest
1 голос
/ 12 ноября 2011

Итак, я начал квест на реализацию потрясающего освещения без использования системы освещения OpenGL. Я успешно реализовал диффузное освещение Phong. Specular доставляет мне неприятности.

Мне нужно знать, какие места занимают используемые мной константы OpenGL, потому что кажется, что они неправильно преобразованы, и это приводит к сбоям освещения.

Я подтвердил, что с моим кодом C ++ нет проблем, успешно загрузив и запустив диффузный шейдер Phong. Однако код C ++ может передавать недопустимые данные шейдерам, что меня беспокоит. Я буду вставлять свои шейдеры с комментариями, а также весь код C ++, непосредственно относящийся к шейдерам (хотя я на 90% уверен, что проблема в шейдерах).

На этих изображениях источники света представляют собой большие точки и показаны оси. Огни вращаются при и = 0 вокруг икосферы.

Вот разброс, так что вы получите представление о модели ... Note I haven't done per-pixel yet... Обратите внимание, что я еще не сделал для каждого пикселя ...

Вот освещение Френеля, как показано в источнике ... Note how the lit faces are facing the light, not somewhere between the light and the camera Обратите внимание, что освещенные лица обращены к свету, а не где-то между светом и камерой

Вот Блинн-Фонг, который мне пришлось умножить на 30 ... Note again how the lit faces point towards the light source Обратите внимание еще раз, как освещенные лица указывают на источник света, а также тот факт, что мне пришлось умножить коэффициент зеркальности (S) на 30, чтобы достичь этого

Источник вершинного шейдера (загружается из "dirlight.vs")

const int MAXLIGHTS = 4;

uniform bool justcolor = false;

uniform int lightcount;
uniform vec4 lightposs[MAXLIGHTS];
uniform vec4 lightdirs[MAXLIGHTS];
uniform vec4 lightdifs[MAXLIGHTS];
uniform vec4 lightambs[MAXLIGHTS];

//diffuse
vec4 D;
//specular, normaldotlight
float S, NdotL[MAXLIGHTS];
//normal, eyevec, lightvecs, halfvecs
vec3 N, E, L[MAXLIGHTS], H[MAXLIGHTS];

void main() {
    //if(lightcount > MAXLIGHTS) lightcount = MAXLIGHTS;
    D = vec4(0.0, 0.0, 0.0, 0.0);
    S = 0.0;

    N = gl_Normal;
    E = normalize(vec3(-gl_Vertex));

    for(int i = 0; i < lightcount; i++)
    {
        //calculating direction to light source
        L[i] = normalize(vec3(lightposs[i] - gl_Vertex));

        //normal dotted with direction to light source
        NdotL[i] = max(dot(N, L[i]), 0.0);

        //diffuse term, works just fine
        D += gl_Color * lightdifs[i] * NdotL[i];

        if(NdotL[i] >= 0.0)
        {
            //halfvector = normalize(lightdir + eyedir)
            H[i] = normalize(L[i] + E);

            //Blinn-Phong, only lights up faces whose normals 
            //point directly to the light source for some reason...
            //S += max(0.0, dot(H[i], N));

            //Fresnel, lights up more than Blinn-Phong 
            //but the faces still point directly to the light source, 
            //not somewhere between the lightsource and myself, like they should.
            S += pow(max(0.0, dot(reflect(L[i], N), E)), 50.0);
        }
        else
        {
            H[i] = vec3(0.0, 0.0, 0.0);
        }
    }

    //currently only showing specular. To show diffuse add D.
    gl_FrontColor = justcolor ? gl_Color : vec4(S * 0.3, S * 0.3, S * 0.3, 1.0);

    gl_Position = ftransform();
}

Источник шейдера фрагмента (загружен из "dirlight.fs")

void main()
{
    gl_FragColor = gl_Color;
}

Выдержка из основной инициализации C ++ ...

//class program manages shaders
Program shaders = Program();
//attach a vertex shader, compiled from source in dirlight.vs
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs");
//attach a fragment shader compiled from source in dirlight.fs
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs");
//link program
shaders.link();
//use program
shaders.use();

//Program::getUniformLoc(const char* name) grabs the location
//of the uniform specified
GLint sTime = shaders.getUniformLoc("time");
GLint lightcount = shaders.getUniformLoc("lightcount");
GLint lightdir = shaders.getUniformLoc("lightdirs");
GLint lightdif = shaders.getUniformLoc("lightdifs");
GLint lightamb = shaders.getUniformLoc("lightambs");
GLint lightpos = shaders.getUniformLoc("lightposs");
GLint justcolor = shaders.getUniformLoc("justcolor");

glUniform1i(justcolor, 0);
glUniform1i(lightcount, 2);
//diffuse light colors
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f,
                      1.f, 1.f, 1.f, 1.f};
glUniform4fv(lightdif, 2, lightdifs);
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f);

Выдержка из основного цикла C ++ ...

//My lights rotate around the origin, where I have placed an icosphere
GLfloat lightposs[] = {-4 * sinf(newTime), lighth, -4 * cosf(newTime), 0.0f,
                       -4 * sinf(newTime + M_PI), lighth, -4 * cosf(newTime + M_PI), 0.0f};
glUniform4fv(lightpos, 2, lightposs);

1 Ответ

4 голосов
/ 12 ноября 2011

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

...