Отложенный конвейер рендеринга, не работающий на графических картах ноутбуков, и странные проблемы с "Model Ghosting" (glBlendFunc)

РЕДАКТИРОВАТЬ: Изменение фрагмента шейдера так, чтобы был возможен только один свет за цикл, решил мою первую проблему. Моя вторая проблема остается в силе.

заранее спасибо за любую помощь, которую вы можете предложить. Я работаю над отложенным конвейером затенения для моего движка рендеринга LWJGL уже пару недель. Хотя я и сумел заставить все работать так, как я ожидал, но после распространения программы среди нескольких знакомых людей у ​​меня начались проблемы. Я постараюсь сделать это как можно короче. Спасибо, что остаетесь со мной.

Я начну с первой из двух проблем в моем названии. На моей машине (AMD Phenom II 965 и Nvidia GTX 480) конечный продукт моего рендерера оказался точно таким, как ожидалось. (Я собирался опубликовать ссылку на изображение, но, поскольку я новый пользователь, я не смог опубликовать более 3 гиперссылок. Но достаточно сказать, что это выглядело так, как и должно быть.)

Это именно то, что я намеревался, так что я, хотя рендер был в порядке. Я отослал это другу (который использовал GT 440), и у них были те же самые результаты.

Вскоре после этого я дал сборку двигателя моему другу, у которого есть ноутбук (с GT 540M). Это было то, что произвел рендерер (игнорируйте счетчик FPS, он не работает):

http://i.imgur.com/DxxFEpy.png

Очевидно, что это совсем не тот результат, которого я ожидал. Я испытывал те же результаты на каждой другой мобильной видеокарте, на которой смог протестировать. После более чем недели, пока я стучал головой по столу, я смог сузить проблему до прохода освещения, где вызывается glBlendFunc. Мой код выглядит следующим образом:

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    List<Float[]>[] listArray = LightData.getInstance().updateLights();
    List<Float[]> lightsColor = listArray[1];
    List<Float[]> lightsPos = listArray[0];
    viewMatrix.setViewMatrix(camera.getTranslation(), camera.getRotation());


    glDisable(GL_DEPTH_TEST);
    glUseProgram(0);
    glCallList(quadList);
    FBO.useShader();
    FBO.passTextures(); //Just sets the shader uniform values to the correct textures
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_BLEND);
    glLoadIdentity();
    glBlendFunc(GL_ONE, GL_ONE) ; //using GL_ONE and GL_ONE_MINUS_SRC_ALPHA have the same effect
    for (int i = 0; i < lightsPos.size(); i++) {
        glClear(GL_DEPTH_BUFFER_BIT);
        int uniformLightPosition = glGetUniformLocation(FBO.getShaderID(), "uniformLightPosition");
        int uniformLightColor = glGetUniformLocation(FBO.getShaderID(), "uniformLightColor");
        int uniformViewMatrix = glGetUniformLocation(FBO.getShaderID(), "uniformViewMatrix");
        int uniformAmbient = glGetUniformLocation(FBO.getShaderID(), "uniformAmbient");
        glUniform1(uniformLightPosition, Tools.asFloatBuffer(lightsPos.get(i)));
        glUniform1(uniformLightColor, Tools.asFloatBuffer(lightsColor.get(i)));
        glUniform1f(uniformAmbient, 0.01f);
        glUniformMatrix4(uniformViewMatrix, true, viewMatrix.asFloatBuffer());

        glCallList(quadList); //is just a display list for a fullscreen quad (using GL_QUADS)
    } 
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);

Первое, что вы можете заметить, это то, что я рисую квад, а затем очищаю буферы глубины и цвета. Это будет рассмотрено в моем следующем вопросе, хотя я не удивлюсь, если проблема в моем следующем вопросе будет тесно связана с проблемой в этом вопросе. Я почти уверен (99%), что проблема в этом методе, потому что при тестировании с более старой сборкой движка, который поддерживал только один источник света, но все еще использовал отложенный конвейер, я смог получить отличные результаты на каждом компьютере, на котором я тестировал, Еще раз, рендерер работает на каждой настольной видеокарте, которую я тестировал, но не на любой видеокарте ноутбука. Я исключил почти все, кроме этого метода. Возможно, стоит отметить, что мне не удалось использовать текстуру с внутренним форматом, который не GL_RGBA32f или же GL_RGBA16f как цель рендеринга. Кто-нибудь видел это раньше, или кто-нибудь может предложить помощь? Я был бы рад, если бы у кого-то была идея, с чего начать искать проблемы на этом этапе, потому что у меня ничего нет. Я был совершенно не в состоянии найти решение самостоятельно.

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

glDisable(GL_DEPTH_TEST);
    glUseProgram(0);
    glCallList(quadList);
    FBO.useShader();
    FBO.passTextures(); //Just sets the shader uniform values to the correct textures
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_BLEND);

Насколько я могу судить, этот код не должен делать абсолютно ничего. Но когда я удаляю рисунок четырехугольника, окно отображает это:

http://i.imgur.com/mkMsP0F.png

Я не знал, как еще это назвать, кроме "призраков", потому что это похоже на призрачное изображение (по крайней мере, так, как мне кажется). Когда я поворачиваю матрицу MV, она искажается в направлении, в котором я вращаюсь, и первый набор источников света (я использую массив из 7) освещает ее, а затем остальные освещают фактическую модель. Я не могу объяснить, почему это происходит, потому что код, который генерирует это изображение, точно такой же, как код выше без glCallList(quadList); Это означает, что буферы глубины и цвета все еще очищаются прямо перед тем, как я вхожу в цикл. Я не могу объяснить эту проблему вообще. У кого-нибудь есть идея, что не так и как это исправить, или хотя бы идея о том, что не так?

РЕДАКТИРОВАТЬ Я обнаружил, что это происходит только с моделями, которые имеют координаты текстуры. Я не знаю почему.

РЕДАКТИРОВАТЬ Похоже, что когда я ограничиваю количество источников света, разрешенных в каждом шейдере, до 1, двоение изображения становится намного менее заметным, но все еще присутствует, поэтому я предполагаю, что это означает, что один запуск фрагментного шейдера приводит к этим призракам.

Спасибо за ЛЮБУЮ помощь любому из этих двух проблем, это очень ценится. Если у вас есть какие-либо вопросы для меня, просто задавайте, хотя мне может потребоваться некоторое время, чтобы вернуться к вам, я постараюсь вернуться как можно быстрее.

РЕДАКТИРОВАТЬ Сори, я забыл свой код шейдера: вершина GeometryPass:

uniform sampler2D tex;

varying vec3 surfaceNormal;
varying vec3 varyingVertex;

void main() {
    vec4 color = vec4(texture2D(tex, gl_TexCoord[1].st));
    gl_FragColor = color;

}

Фрагмент GeometryPass:

uniform sampler2D tex;

varying vec3 surfaceNormal;
varying vec3 varyingVertex;

uniform float materialValue;
uniform float specValue; 

void main() {
    vec4 color = vec4(texture2D(tex, gl_TexCoord[1].st)) ;//vec4(0.25,0.25,0.25,1);
    vec4 vertex = vec4(varyingVertex, materialValue);
    vec4 normal = vec4(surfaceNormal, specValue);
    gl_FragData[0] = color;
    gl_FragData[1] = vertex;
    gl_FragData[2] = normal;

}

Вершина LightPass Phong:

void main() {
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = gl_ModelViewMatrix * gl_Vertex;
}

Фрагмент фонаря LightPass

uniform sampler2D location;
uniform sampler2D normal;
uniform sampler2D color;

uniform float uniformLightPosition[21];
uniform mat4 uniformViewMatrix;
uniform float uniformLightColor[28];


void main() {
    vec4 color = texture2D(color, gl_TexCoord[0].st);
    vec4 locationAndMat = texture2D(location, gl_TexCoord[0].st);
    vec4 normalAndSpec = texture2D(normal, gl_TexCoord[0].st);  

    vec3 vertexPosition = locationAndMat.xyz;
    vec3 surfaceNormal = normalAndSpec.xyz;
    float spec = normalAndSpec.a;
    float specA = locationAndMat.a;

    vec4 lightColor[7];
    int iterator = 0;
    for (int i = 0; i<28; i = i+4) {
        lightColor[iterator] = vec4(uniformLightColor[i], uniformLightColor[i+1], uniformLightColor[i+2], uniformLightColor[i+3]);
        iterator = iterator + 1;
    }
    vec3 lightPos[7];
    iterator = 0;
    for (int i = 0; i<21; i = i+3) {
        lightPos[iterator] = vec3(uniformLightPosition[i], uniformLightPosition[i+1], uniformLightPosition[i+2]);
        lightPos[iterator] =  (uniformViewMatrix * vec4(lightPos[iterator],1)).xyz ;
        iterator = iterator + 1;
    }

    vec4 fragData[7];
    vec4 endColor;
    for (int i = 0; i<7 ; i++) {
        if (lightColor[i] != vec4(0,0,0,0) && color != vec4(0,0,0,0)) {
            vec3 lightDistance = lightPos[i]-vertexPosition;
            float distance = pow((pow(lightDistance.x, 2) + pow(lightDistance.y, 2) + pow(lightDistance.z, 2)), 0.5);
            if (distance < lightColor[i].a) { 
                float att = 1/((-3/800*(lightColor[i].a) + 0.225)*pow(distance, 2));
                vec3 lightDirection = normalize(lightDistance);    

                float diffuseLightIntensity = max(0.0, dot(surfaceNormal, lightDirection));
                fragData[i] += (vec4(diffuseLightIntensity,diffuseLightIntensity,diffuseLightIntensity,1));    

                vec3 reflectionDirection = normalize(reflect(-lightDirection, surfaceNormal));

                float specular = max(0.0, dot(reflectionDirection,  -normalize(vertexPosition)));

                if (diffuseLightIntensity != 0) {
                    float fspecular = pow(specular, spec);
                    vec4 fspec = vec4(fspecular*specA, fspecular*specA, fspecular*specA,1);
                    fragData[i] += fspec;
                }
                fragData[i] *= lightColor[i]; 
                fragData[i] *= 0.1;
                fragData[i].a = 0;
                fragData[i] *= att;
                endColor += fragData[i];
            }
        }  

    } 

    gl_FragData[0] = endColor * color;

}

1 ответ

Я решил основную проблему! Это было достаточно хорошо для меня. Похоже, проблема, с которой я столкнулся, заключалась в том, что на фрагментный шейдер приходилось много инструкций (из-за цикла for). Когда я настроил шейдер только на один свет, он работал как положено! Я просто использую смешивание, чтобы позаботиться обо всем, как раньше, но больше запускаю шейдер. Недостатком является то, что требуется больше фильтрата, но с другой стороны, он работает на старом оборудовании и ноутбуках.

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

Другие вопросы по тегам