2011-06-19 10 views
9

Así que decidí intentar escribir una aplicación OpenGL simple usando Java, solo para ver cómo se comparaba con mis otros esfuerzos, y me encontré con un problema donde mis sombreadores se niegan a compilar. Que realmente no podía conseguir mucho más simple, aquí está mi sombreado de vértices para demostrar lo que quiero decir:Problema de compilación de OpenGL Shader - EOF inesperado

//Minimal vertex shader 

#version 330 

in vec3 in_Position; 
in vec3 in_Color; 
out vec3 var_Color; 

void main(void) 
{ 
    gl_Position = vec4(in_Position, 1.0); 
    var_Color = in_Color; 
} 

El fragmento shader es tan simple, por lo que no se molestan en publicar a menos que alguien lo solicite. Cuando compruebo los registros, que vuelva el siguiente error (tanto para los shaders):

(0) : error C0000: syntax error, unexpected $end at token "<EOF>" 

No estoy seguro de que esto es relevante ... pero estoy desarrollando en Linux (Ubuntu 11.04) utilizando Java. Las únicas bibliotecas que estoy usando son JOGL (para los enlaces de OpenGL) y la biblioteca estándar de Java (si eso cuenta ...) Mi tarjeta gráfica es una Nvidia GeForce 9600M GS, y verifiqué las extensiones y tiene soporte completo para OpenGL 3.3.

Ayuda para Stack Overflow, eres mi única esperanza.

EDIT:

Conforme a lo solicitado, aquí es la función que se encarga de cargar y compilar el código fuente de sombreado. Además, cuando se trata de GLSL, soy un super n00b, así que realmente no sé qué buscar para asegurarme de que las cosas estén formateadas adecuadamente para OpenGL. Se agradecerá un enlace a un tutorial reciente (es decir, que trata sobre OpenGL 3.x) sobre el tema.

private int CreateCompiledShader(File source, int shader, GL3 gl){ 
     int shaderloc = gl.glCreateShader(shader); 

     BufferedReader input = null; 
     ArrayList<String> lines = new ArrayList<String>(); 
     ArrayList<Integer> lengths = new ArrayList<Integer>(); 
     try{ 
      input = new BufferedReader(new FileReader(source)); 
      String buffer; 

      while(input.ready()){ 
       buffer = input.readLine(); 
       lines.add(buffer); 
       lengths.add(buffer.length()); 
      } 
     }catch(Exception e){ 
      e.printStackTrace(); 
     }finally{ 
      if(input != null){ 
       try { 
        input.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

     int[] iLengths = new int[lengths.size()]; 
     for(int i = 0; i < lengths.size(); i++){ 
     iLengths[i] = lengths.get(i).intValue(); 
     } 

     gl.glShaderSource(shaderloc, lines.size(), lines.toArray(new String[0]), iLengths, 0); 
     gl.glCompileShader(shaderloc); 

     int error = gl.glGetError(); 
     if(error != GL3.GL_NO_ERROR){ 
      Logger.log(new GLU().gluErrorString(error), Logger.ERROR, "Shader compilation"); 
     } 

     return shaderloc; 
    } 

Como acotación al margen, la sentencia if hacia el final donde puedo comprobar glGetError() no es en realidad donde el error se ve atrapado, que no se produce hasta la ejecución vuelve a la función de llamada y verifico el sombreador registra. Podría ser relevante, pero también podría estar divagando.

+0

Intente agregar línea vacía después del último corchete, que a veces podría ayudar. – Kromster

+0

Esa fue una de las primeras cosas que intenté, sin embargo, no apareció cuando publiqué el código. – rjacks

Respuesta

13

Bien, ahora veo el problema. Tu código de carga no funciona. Pero no te preocupes; Mucha gente se confunde cuando ve que glShaderSource toma una serie de cadenas. Supongo que viste a alguien escribir sus shaders en C/C++ como esto:

const char *myShader[] = { 
    "#version 330\n", 
    "\n", 
    "in vec3 in_position;\n", 
    ... 
}; 

Y subido el shader con, glShaderSource(shader, ARRAY_COUNT(myShader), myShader, NULL, 0);

Si bien esto es legal, eso no es realmente lo que la característica es para . Como GLSL no tiene un mecanismo #include, glShaderSource puede tomar múltiples cadenas. Cada cadena está destinada a ser un archivo de sombreado. El compilador del sombreador concatena las cadenas a la vez como lo hace #include antes de compilar.

Ahora, debido a esto, puede tener cada línea como una cadena separada. Sin embargo, mira hacia atrás ese código C/C++. ¿Ves lo que está al final de cada línea? Ese '\ n' personaje.

Eso es lo que no al final de las líneas que está cargando. Porque estoy bastante seguro de que BufferedReader.readline hace no mantener el carácter de fin de línea. Así que su sombreador se ve así:

//Minimal vertex shader#version 330in vec3 in_Position;in vec3 in_Color;out vec3 var_Color;... 

Todo su sombreador se ve como un gran comentario de una sola línea. De ahí el inesperado EOF: OpenGL nunca vio nada para compilar;)

No debería leer el archivo línea por línea. Simplemente cargue todo en una sola cuerda. Luego, pásalo a OpenGL. Alternativamente, puede mirar this previous answer sobre JOGL; debería mostrarle cómo hacerlo correctamente (aunque espero que BufferedReader tenga alguna forma de leer todo el archivo como una cadena en lugar de línea por línea.

+0

¡Ajá! Eso tiene sentido. He hecho este proyecto antes en C/C++, así que cuando vi en el javadoc que esta función tomó String [], de alguna manera asumí que char * == String [] (que obviamente no es correcto). Gracias por la respuesta útil. – rjacks

1

Intenta mover el comentario después de la declaración #version. No debería importar, pero puede haber errores en el controlador.

Además, intente poner una línea vacía adicional al final del archivo. De nuevo, solo para estar seguro.

Por último, asegúrese de que de hecho está cargando la cadena correctamente. Verifíquelo en el depurador. Y asegúrese de pasar la cadena a OpenGL correctamente. ¿Cómo se ve ese código?

+1

Es posible que también desee asegurarse de que no haya una lista de materiales al comienzo del archivo. (Eso es algo de 3 bytes que la mayoría de los editores ocultan, que define la codificación Unicode en el archivo, incluso si solo usa caracteres latinos) – Kromster

3

Aunque una respuesta ya se ha proporcionado y aceptado, voy a escribir aquí cómo preferiría que:

// Create shader from one or multiple source files 
private int CreateCompiledShader(File[] source_files, int shader, GL3 gl){ 
    int shaderloc = gl.glCreateShader(shader); 
    int nSources = source_files.size(); 

    // the number of shader sources it known from the beginning 
    // so we can allocate the arrays right here 
    String[] sources = new String[nSources]; 
    int[] sources_lengths = new int[nSources]; 
    for(int i = 0; i < nSources; i++) { 
     // We don't need a buffered reader as we're reading the file as a whole 
     FileReader input = new FileReader(source_file[i]); 
     String buffer; 

     buffer = input.read(); 
     sources[i] = buffer; 
     sources_lengths[i] = buffer.length(); 

     if(input != null){ 
      input.close(); 
     } 
    } 

    // Frankly I really don't understand why you have to pass sources_lengths here 
    // It would take only 3 LOC in the binding's code 
    // to extract that from the sources array, Oh, well... 
    gl.glShaderSource(shaderloc, nSources, sources, sources_lengths, 0); 
    gl.glCompileShader(shaderloc); 

    // Actually if glGetError() returns an error you must call it in a loop 
    // as OpenGL errors can accumulate, and you have to pop them all from the list. 
    int error = gl.glGetError(); 
    if(error != GL3.GL_NO_ERROR){ 
     Logger.log(new GLU().gluErrorString(error), Logger.ERROR, "Shader compilation"); 
    } 

    return shaderloc; 
} 

he tomado la libertad para eliminar todo el try/catch/finally bloques, ya que estaban fuera de lugar un poco: Si la lectura de cualquier archivo de origen falla, la carga de sombreado no se puede completar, por lo que no tiene sentido continuar continuamente con gracia. La forma más adecuada de lidiar con esto sería un gran bloque try/catch alrededor de este, que limpia los objetos OpenGL de la compilación shader no completa.

+0

Si no estuviera programando en Java pero en un lenguaje que tuviera punteros (C, C++, D, Go), entonces otro método viable sería tratar de mapear en memoria el archivo en lugar de leerlo en un buffer. – datenwolf

+0

Este código * es * mejor ... . Una vez mas, Gracias. – rjacks

Cuestiones relacionadas