2011-06-19 17 views
9

Postanowiłem więc spróbować napisać prostą aplikację OpenGL przy użyciu Javy, tylko po to, aby zobaczyć, jak to jest w porównaniu do innych moich wysiłków, i napotykam problem, w którym moje shadery odmawiają kompilacji. Oni naprawdę nie mógł się o wiele prostsze, oto moja vertex shader w celu wykazania, co mam na myśli:Problem kompilacji Shader OpenGL - nieoczekiwany EOF

//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; 
} 

Fragment shader jest tak samo proste, więc nie przeszkadza umieszczenie go chyba, że ​​ktoś o to poprosi. Kiedy sprawdzić dzienniki, wrócę następujący błąd (zarówno dla shaderów):

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

nie jestem pewien, że to ma znaczenie ... ale Zajmuję na Linux (Ubuntu 11.04) przy użyciu języka Java. Jedyne biblioteki, których używam to JOGL (dla wiązań OpenGL) i standardowa biblioteka Java (jeśli to się jeszcze liczy ...) Moja karta graficzna to Nvidia GeForce 9600M GS, a ja sprawdziłem rozszerzenia i mam pełne wsparcie dla OpenGL 3.3.

Pomóż mi przepełnić stos, jesteś moją jedyną nadzieją.

EDIT:

Zgodnie z wnioskiem, o to funkcja, która jest odpowiedzialna za załadunek i kompilowania shaderów źródła. Ponadto, jeśli chodzi o GLSL, jestem super n00b, więc naprawdę nie wiem, czego szukać, jeśli chodzi o upewnienie się, że rzeczy są poprawnie sformatowane dla OpenGL. Chciałbym docenić link do niedawnego (tj. Zajmującego się OpenGL 3.x) samouczka na ten temat.

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; 
    } 

Tak na marginesie, if ku końcowi, gdzie mogę sprawdzić glGetError() nie jest faktycznie gdzie błąd zostanie złapany, że nie zdarza się aż powróci do realizacji funkcji wywołującej i sprawdzić dzienniki modułu cieniującego. To może być istotne, ale znowu mógłbym być chaotyczny.

+0

Spróbuj dodać pustą linię za ostatnim nawiasem, co może czasem pomóc. – Kromster

+0

To była jedna z pierwszych rzeczy, które wypróbowałem, ale nie pojawiły się, kiedy opublikowałem kod. – rjacks

Odpowiedz

13

OK, teraz widzę problem. Twój kod ładujący nie działa. Ale nie martw się; wiele osób wpada w pomieszanie, gdy widzą, że glShaderSource przyjmuje tablicę łańcuchów. Zgaduję, że widział ktoś napisać swoje shadery w języku C/C++ tak:

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

I uploaded shader z, glShaderSource(shader, ARRAY_COUNT(myShader), myShader, NULL, 0);

Chociaż jest to legalne, to nie jest to, co ta funkcja jest dla . Ponieważ GLSL nie ma mechanizmu #include, glShaderSource może przyjmować wiele ciągów. Każdy ciąg ma być plikiem cieniującym. Następnie kompilator shaderów skutecznie łączy ciągi razem, tak jak #include przed kompilacją.

Teraz, dzięki temu, każdy wiersz może być oddzielny. Jednak spójrz wstecz, że ten kod C/C++. Zobacz, co jest na końcu każdego wiersza? Ta "\ n" postać.

To jest nie na końcu linii, które ładujesz. Ponieważ jestem całkiem pewny, że BufferedReader.readline nie ma wartości , a nie zachować znaku końca wiersza. Twój shader wygląda następująco:

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

Twój cały moduł cieniujący jest postrzegany jako jeden duży komentarz jednolinijkowy. Stąd nieoczekiwany EOF: OpenGL nigdy nie widział niczego do skompilowania;)

Nie powinieneś czytać pliku wiersz po linii. Po prostu załaduj całość w jeden ciąg. Następnie przekaż go do OpenGL. Alternatywnie możesz spojrzeć na this previous answer o JOGL; powinien pokazać ci, jak to zrobić poprawnie (choć mam nadzieję, że BufferedReader będzie miał jakiś sposób, aby odczytać cały plik jako ciąg, a nie wiersz po linii.)

+0

Aha! To ma sens. Zrobiłem ten projekt wcześniej w C/C++, więc kiedy zobaczyłem w javadoc, że funkcja ta wzięła String [], jakoś założyłem, że char * == String [] (co oczywiście nie jest poprawne). Dziękuję za pomocną odpowiedź. – rjacks

1

Spróbuj przenieść komentarz do po deklaracji #version. To nie powinno mieć znaczenia, ale mogą istnieć błędy sterownika.

Spróbuj również umieścić dodatkowy pusty wiersz na końcu pliku. Ponownie, tylko dla pewności.

Wreszcie, upewnij się, że faktycznie ładujesz ciąg poprawnie. Sprawdź to w debugerze. Upewnij się, że poprawnie przekazujesz ciąg do OpenGL. Jak wygląda ten kod?

+1

Możesz również chcieć upewnić się, że na początku pliku nie ma LM. (To jest 3 bajty, które większość edytorów ukryłaby przed tobą, która definiuje kodowanie Unicode w pliku, nawet jeśli używa tylko znaków łacińskich) – Kromster

3

Mimo że odpowiedź już została dodana i zaakceptowana, ja po prostu napisać tutaj jak bym go wolą:

// 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; 
} 

pozwoliłem sobie usunąć wszystkie try/catch/finally bloków, jak zostały one niewłaściwie kawałek: Jeżeli odczyt dowolnego pliku źródłowego nie cieniowania, załadunek nie można go ukończyć, więc nie ma sensu trwać z wdziękiem.Możliwym sposobem radzenia sobie z tym byłby duży blok try/catch, który czyści obiekty OpenGL z kompilacji shaderów, które nie kończą się.

+0

Jeśli nie programowałeś w Javie, ale w języku, który miał wskaźniki (C, C++, D, Go), to inną realną metodą byłoby próba zapamiętywania pliku, zamiast czytania go do bufora. – datenwolf

+0

Ten kod * jest * lepszy ... . Jeszcze raz Ci dziękuję. – rjacks

Powiązane problemy