2016-04-03 9 views
0

Ich reiße mir die Haare bei diesem Problem aus! Ich habe einen einfachen Vertex- und Fragment-Shader, der perfekt auf einem alten Vaio-Laptop funktioniert (und immer noch funktioniert). Es ist für ein Partikelsystem und verwendet Punktsprites und eine einzelne Textur, um Partikel zu rendern.Einfacher GL Fragment Shader verhält sich seltsamerweise auf neueren GPU

Das Problem beginnt, wenn ich das Programm auf meinem Desktop mit einer viel neueren Grafikkarte (Nvidia GTX 660) ausführen. Ich bin mir ziemlich sicher, dass ich es auf den Fragment-Shader beschränkt habe, als würde ich die Textur ignorieren und Color einfach wieder auslassen, alles funktioniert wie erwartet.

Wenn ich die Textur in die Shader-Berechnungen einfüge, wie unten dargestellt, erscheinen alle Punkte, die während der Verwendung dieses Shaders gezeichnet werden, in der Mitte des Bildschirms, unabhängig von der Kameraposition.

Example screenshot attached

Sie können ein ganzes Durcheinander von Partikeln Totpunkt der Verdächtigen Shader verwendet, und nicht texturierte Partikel sehen korrekt auf den rechten Seite zu machen.

Vertex Shader, sicher zu sein:

#version 150 core 
in vec3 position; 
in vec4 color; 

out vec4 Color; 

uniform mat4 view; 
uniform mat4 proj; 
uniform float pointSize; 

void main() { 
    Color = color; 
    gl_Position = proj * view * vec4(position, 1.0); 
    gl_PointSize = pointSize; 
} 

und das Fragment-Shader Ich vermute, das Problem zu sein, aber kann es wirklich nicht sehen, warum:

#version 150 core 
in vec4 Color; 
out vec4 outColor; 
uniform sampler2D tex; 

void main() { 
    vec4 t = texture(tex, gl_PointCoord); 

    outColor = vec4(Color.r * t.r, Color.g * t.g, Color.b * t.b, Color.a * t.a); 
} 

untextured Teilchen den gleichen Vertex-Shader verwenden , aber der folgende Fragmentshader:

#version 150 core 
in vec4 Color; 
out vec4 outColor; 
void main() { 
    outColor = Color; 
} 

Hauptprogramm hat eine Schleife, die SFML w verarbeitet indow events und 2 Funktionen aufrufen, zeichnen und updaten. Update nicht GL an jedem Punkt berühren, sieht Unentschieden wie folgt aus:

void draw(sf::Window* window) 
{ 
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    sf::Texture::bind(&particleTexture); 

    for (ParticleEmitter* emitter : emitters) 
    { 
     emitter->useShader(); 
     camera.applyMatrix(shaderProgram, window); 
     emitter->draw(); 
    } 

} 

Emitter-> useShader() ist nur einen Anruf zu glUseShader() mit einem GLuint zu einem Shader-Programm zeigt, die in dem Sender gespeichert ist, Objekt bei der Erstellung.

camera.applyMatrix():

GLuint projUniform = glGetUniformLocation(program, "proj"); 
glUniformMatrix4fv(projUniform, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); 
... 
GLint viewUniform = glGetUniformLocation(program, "view"); 
glUniformMatrix4fv(viewUniform, 1, GL_FALSE, glm::value_ptr(viewMatrix)); 

Emitter-> zeichnen() in seiner entirity:

glGenVertexArrays(1, &vao); 
    glBindVertexArray(vao); 

    // Build a new vertex buffer object 
    int vboSize = particles.size() * vboEntriesPerParticle; 
    std::vector<float> vertices; 
    vertices.reserve(vboSize); 

    for (unsigned int particleIndex = 0; particleIndex < particles.size(); particleIndex++) 
    { 
     Particle* particle = particles[particleIndex]; 
     particle->enterVertexInfo(&vertices); 
    } 

    // Bind this emitter's Vertex Buffer 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 

    // Send vertex data to GPU 
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), &vertices[0], GL_STREAM_DRAW); 

    GLint positionAttribute = glGetAttribLocation(shaderProgram, "position"); 
    glEnableVertexAttribArray(positionAttribute); 
    glVertexAttribPointer(positionAttribute, 
     3, 
     GL_FLOAT, 
     GL_FALSE, 
     7 * sizeof(float), 
     0); 

    GLint colorAttribute = glGetAttribLocation(shaderProgram, "color"); 
    glEnableVertexAttribArray(colorAttribute); 
    glVertexAttribPointer(colorAttribute, 
     4, 
     GL_FLOAT, 
     GL_FALSE, 
     7 * sizeof(float), 
     (void*)(3 * sizeof(float))); 

    GLuint sizePointer = glGetUniformLocation(shaderProgram, "pointSize"); 
    glUniform1fv(sizePointer, 1, &pointSize); 

    // Draw 
    glDrawArrays(GL_POINTS, 0, particles.size()); 

Und schließlich Partikel-> enterVertexInfo()

vertices->push_back(x); 
vertices->push_back(y); 
vertices->push_back(z); 
vertices->push_back(r); 
vertices->push_back(g); 
vertices->push_back(b); 
vertices->push_back(a); 

Ich bin mir ziemlich sicher, dass dies kein effizienter Weg ist, um all dies zu tun, aber das war ein Teil der Kursarbeit, die ich vor einem Semester geschrieben habe. Ich besuche es nur, um ein Video davon in Aktion aufzunehmen.

Alle Shader kompilieren und verknüpfen ohne Fehler. Durch das Spielen mit dem Fragment-Shader habe ich bestätigt, dass ich gl_PointCoord verwenden kann, um eine feste Farbe über Partikel hinweg zu variieren, so dass sie wie erwartet funktioniert. Wenn Partikel in der Mitte des Bildschirms gezeichnet werden, wird die Textur korrekt gezeichnet, wenn auch an der falschen Stelle, so dass sie auch korrekt geladen und gebunden wird. Ich bin keineswegs ein GL-Experte, also ist das so viel Debugging, wie ich selbst denken könnte.

Das würde mich nicht so sehr stören, wenn es nicht perfekt auf einem alten Laptop funktioniert!

Edit: inklusive eine Tonne Code

+0

Meine Wette wäre immer noch auf undefiniertes Verhalten auf der Client-Seite. Ihre Änderungen im Fragment-Shader können auch dazu führen, dass sich die Standortzustände und möglicherweise auch die Standortattribute ändern. Sie sollten den Code für die Uniform- und Attribut-Einrichtung ebenfalls veröffentlichen. – derhass

+0

Ich denke, ich habe den gesamten relevanten Code für Attribute und Uniformen eingefügt, aber während ich mit den Shadern gespielt habe, habe ich keine Eingabe- oder Ausgabevariablen berührt, die ich in den Berechnungen hatte, in einem Versuch, keine neuen Bugs einzuführen. Ich gebe zu, dass ich mich nicht genau erinnern kann, was alle Argumente in dem Code, den ich gepostet habe, tun, also könnte ich etwas wichtiges verpasst haben. –

+0

Dieser Code sieht soweit OK aus. Sie sagen jedoch, dass Sie für die untexturierten und die texturierten Varianten unterschiedliche Shader verwenden, was bedeutet, dass Sie das Attribut und die einheitlichen Positionen zwischen beiden Programmen immer noch durcheinander bringen könnten. – derhass

Antwort

1

Wie in den Kommentaren stellte sich heraus, die shaderProgram Variable, die für die Einstellung der Kamerabezogenen Uniformen verwendet wurde nicht in Gebrauch auf dem tatsächlichen Programm abhing. Als Ergebnis wurden die einheitlichen Stellen für ein anderes Programm abgefragt, wenn die texturierten Partikel gezeichnet wurden.

Die einheitliche Lage Zuordnung völlig implementierungsspezifisch ist, nvidia beispielsweise dazu neigt, sich von der alphabetischen Reihenfolge des einheitlichen Namen zuweisen, so view ‚s je nach Lage würde ich ändern, wenn tex tatsächlich vorhanden ist (und acttively verwendet wird) oder nicht. Wenn die andere Implementierung ihnen nur die Reihenfolge zuweist, in der sie im Code oder einem anderen Schema erscheinen, können die Dinge zufällig funktionieren.

Verwandte Themen