2013-05-17 3 views
11

Ho un programma GLSL estremamente semplice che non riesce ad aggiornare correttamente un valore uniforme dopo la prima chiamata di estrazione. Nessun errore viene ricevuto da glGetError, nessun errore viene riportato nei registri delle informazioni durante la compilazione e il collegamento degli shader e tutte le posizioni uniformi sono valide.GLSL uniforme aggiornata solo da chiamate non collegate

Vertex Shader:

#version 120 

uniform mat4 mvp; 
uniform mat3 nmv; 

attribute vec3 position; 
attribute vec3 normal; 

varying vec3 v_normal; 

void main() 
{ 
    v_normal = normalize(nmv * normal); 
    gl_Position = mvp * vec4(position, 1.0); 
} 

Fragment Shader:

#version 120 

uniform vec3 lightDir; 
uniform vec3 lightColor; 
uniform vec3 materialColor; 

varying vec3 v_normal; 

void main() 
{ 
    vec3 n = normalize(v_normal); 
    float nDotL = max(0.0, dot(n, lightDir)); 

    gl_FragColor = vec4(materialColor * lightColor * nDotL, 1.0); 
} 

codice resa:

glUseProgram(program); 
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp); 
glUniformMatrix3fv(nmvLoc, 1, GL_FALSE, nmv); 
glUniform3fv(lightDirLoc, 1, lightDir); 
glUniform3fv(lightColorLoc, 1, lightColor); 

for (auto mesh: meshes) 
{ 
    glUniform3fv(materialColorLoc, 1, mesh.color); 
    mesh.draw(); 
} 

Le maglie resi sono attratti nel colore della prima maglia, indicando che dopo aver inizialmente impostato l'uniforme materialColor, le successive chiamate a chan l'uniforme è ignorata. Tuttavia, ecco un elenco di condizioni speciali che consentono in modo indipendente di aggiornare correttamente l'uniforme:

  • Chiamare il numero glUseProgram(program) all'interno del ciclo.
  • Impostazione delle uniformi mvp o nmv all'interno del ciclo.
  • Impostazione dell'uniforme lightDir all'interno del ciclo.
  • Rimozione di uno degli uniform vec3 dal programma shader.

prega di notare che l'impostazione della lightColor uniforme all'interno del ciclo sarà non aggiornamento il materialColor uniforme. Ho anche controllato GL_CURRENT_PROGRAM all'interno del ciclo e lo shader rimane vincolato in tutto.

Ho cercato di risolvere questo problema per ore e assolutamente non riesco a trovare il problema. Questa configurazione dello shader è così semplice che non credo sia un errore del driver. Sto usando OpenGL 2.1 su Mac OS X 10.8.3 con una NVIDIA GeForce 9400M.

Ecco una traccia richiamo per un singolo fotogramma:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glUseProgram(1); 
glUniformMatrix4fv(1, 1, 0, 0x7fff55512550); // mvp 
glUniformMatrix3fv(5, 1, 0, 0x7fff55512528); // nmv 
glUniform3fv(0, 1, 0x7fff55512670);   // lightDir 
glUniform3fv(9, 1, 0x7fff555124e8);   // lightColor 

// Mesh 0 
glUniform3fv(8, 1, 0x7fab820cd7ec);   // materialColor 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ARRAY_BUFFER, 1); 
glEnableVertexAttribArray(0); 
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000); 
glEnableVertexAttribArray(2); 
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
glDrawArrays(GL_TRIANGLES, 0, 21); 
glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(2); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

// Mesh 1 
glUniform3fv(8, 1, 0x7fab823000bc);   // materialColor 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ARRAY_BUFFER, 2); 
glEnableVertexAttribArray(0); 
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000); 
glEnableVertexAttribArray(2); 
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
glDrawArrays(GL_TRIANGLES, 0, 24); 
glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(2); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

// Mesh 2 
glUniform3fv(8, 1, 0x7fab8231f8fc);   // materialColor 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ARRAY_BUFFER, 3); 
glEnableVertexAttribArray(0); 
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000); 
glEnableVertexAttribArray(2); 
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
glDrawArrays(GL_TRIANGLES, 0, 21); 
glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(2); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

// Mesh 3 
glUniform3fv(8, 1, 0x7fab820cf41c);   // materialColor 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ARRAY_BUFFER, 4); 
glEnableVertexAttribArray(0); 
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000); 
glEnableVertexAttribArray(2); 
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
glDrawArrays(GL_TRIANGLES, 0, 18); 
glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(2); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

CGLFlushDrawable(); 

EDIT: Ecco il codice utilizzato per ottenere le posizioni uniformi. Viene eseguito dopo che gli shader sono stati compilati e collegati e tutte le uniformi vengono verificate come valide.

GLint mvpLoc = glGetUniformLocation(program, "mvp"); 
GLint nmvLoc = glGetUniformLocation(program, "nmv"); 
GLint lightDirLoc = glGetUniformLocation(program, "lightDir"); 
GLint lightColorLoc = glGetUniformLocation(program, "lightColor"); 
GLint materialColorLoc = glGetUniformLocation(program, "materialColor"); 
+1

Mi sembra che l'unica differenza tra le uniformi lightColor e lightDir sia la loro posizione nello shader. Hai provato a cambiare posizione e vedere se LightColor in effetti attiva il cambiamento? Vorrei anche provare a vedere se una GPU ATI o Intel produce lo stesso comportamento. – Ani

+1

Ho appena provato a cambiare il loro ordine e il comportamento rimane esattamente lo stesso. 'lightColor' continua a non attivare la modifica. Purtroppo non ho accesso a un'altra GPU in questo momento. –

+1

Ho notato che scambiando l'ordine di dichiarazione, o le loro posizioni nelle operazioni, le posizioni uniformi rimanevano invariate. –

risposta

0
  1. volte conducente ottimizzerà alcuni dei vostri divise (anche se non dovrebbe especialy con i vecchi driver). per testare che provi ad usare il tuo colore materiale in vertex shader (copialo in qualche variabile variabile e in shader di frammenti usa quella variabile variabile invece di uniforme, che a volte funziona per me, ... ovviamente diminuisce un po 'le prestazioni)

  2. tenta di utilizzare una versione di profilo diversa. In alcuni casi i driver più recenti non emulano correttamente le versioni precedenti. Hai provato il profilo principale?(So ​​che la sua molto difficile da mettere in atto con il codice più vecchio)

  3. si può provare nvemulate per testare diverse impostazioni del driver

volte dimenticata glEnd(); fa un sacco di problemi tenta di aggiungere questo codice prima della finestra del codice di rendering:

glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
glEnd(); 
... here comes your rendering code 

se questo aiuta di quanto si forgott chiamare glEnd(); da qualche parte o ha glEnd; invece di glEnd();

+1

Un problema 'glEnd' avrebbe innescato un errore GL, che l'OP afferma di aver controllato. – rotoglup

0

Ancora non risolto?

qual è il tipo di mesh.color

guardando gli indirizzi passati nel tracciamento delle chiamate sembrano piuttosto elevato, forse si dovrebbe essere di passaggio in un discorso ai dati non i dati effettivi, 0x7fab823000bc

glUniform3fv (materialColorLoc, 1, & mesh.color); forse prova hard coding e usa glUniform3f()

0

Da tutti gli indirizzi nella traccia immagino che qualsiasi vec3 che invii a GL sia di tipo float name[3], vero? Supponendo che non riesco a individuare un errore nel codice. Come hai affermato, non c'è stato di errore restituito da glGetError, DEVE essere un bug del driver.

Ho visto nella traccia che si avvia ogni mesh facendo un glBindBuffer (GL_ARRAY_BUFFER, 0) - questo non è realmente necessario. Ma comunque, non posso nemmeno immaginare che questa sia la fonte.

Purtroppo, non è possibile testare cose come glBindUniformLocation prima del collegamento, poiché non fa parte di OpenGL.

La mia esperienza mostra: se si emette glUniform3fv e tutti i parametri sono corretti, la divisa viene aggiornata e tale modifica è immediatamente visibile. In questo caso, deve trattarsi di un bug del driver, quindi l'unica cosa che potresti fare è: aggiungere altre chiamate non necessarie al tuo ciclo di rendering per rendere visibile la modifica (che hai già fatto se l'ho letto correttamente) .