2011-06-19 63 views
9

所以我決定嘗試用Java編寫一個簡單的OpenGL應用程序,只是爲了看看它與我的其他工作相比如何,而我遇到了着色器拒絕編譯的問題。他們真的無法得到簡單得多,這是我的頂點着色器來證明我的意思:OpenGL Shader編譯問題 - 意外的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; 
} 

片段着色器也很簡單,所以我不會理會,除非有人問它張貼。當我檢查日誌,我得到以下錯誤(這兩種着色器):

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

我不知道這是相關的......但我使用Java進行開發在Linux(Ubuntu的11.04)。我使用的唯一庫是JOGL(用於openGL綁定)和標準Java庫(如果這甚至可以......)我的顯卡是Nvidia GeForce 9600M GS,我檢查了擴展,它完全支持OpenGL 3.3。

幫助我堆棧溢出,你是我唯一的希望。

編輯:

按照要求,這裏就是負責裝載和編譯着色器源的功能。另外,當談到GLSL時,我是一個超級n00b,所以我真的不知道該如何確保OpenGL的格式正確。最近的一個鏈接(即處理OpenGL 3.x)關於這個主題的教程將不勝感激。

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

順便說一句,if語句駛向何方我檢查glGetError(結束)實際上在錯誤被逮住,這不會發生,直到執行返回到調用函數和我檢查着色器日誌。可能是相關的,但我也可能會散漫。

+0

嘗試在最後一個括號後面添加空行,有時可能會有所幫助。 – Kromster

+0

這是我嘗試的第一件事情之一,但是當我發佈代碼時它並沒有顯示出來。 – rjacks

回答

13

好的,現在我看到了問題。您的加載代碼不起作用。但別擔心,當許多人看到glShaderSource接受一串字符串時會感到困惑。我猜你看見有人寫他們在C/C着色++這樣的:

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

他們上傳的着色器,glShaderSource(shader, ARRAY_COUNT(myShader), myShader, NULL, 0);

雖然這是合法的,這不是真正的功能是什麼。由於GLSL沒有#include機制,因此glShaderSource可以採用多個字符串。每個字符串的打算是着色器文件。着色器編譯器然後有效地將字符串連接在一起,就像#include在編譯之前所做的那樣。

現在,正因爲如此,您可以將每行作爲單獨的字符串。但是,回頭看看那個C/C++代碼。看看每一行的結尾是什麼?那'\ n'字符。

這就是而不是在您正在加載的行的末尾。因爲我非常確定BufferedReader.readline不是而是保留行尾字符。所以你的着色器看起來像:

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

你的整個着色器被視爲一個大的單行註釋。因此,意想不到的EOF:OpenGL從來沒有看到要編譯的東西;)

您不應該逐行讀取文件。只需將整個東西裝入一個字符串即可。然後將其傳遞給OpenGL。或者,您可以查看關於JOGL的this previous answer;它應該告訴你如何正確地做到這一點(儘管我希望BufferedReader能夠以一種字符串而不是一行一行的方式讀取整個文件)

+0

Aha!這就說得通了。我之前在C/C++中完成了這個項目,所以當我在javadoc中看到這個函數使用了String []時,我不知何故就假定char * == String [](顯然不正確)。感謝您的有用答案。 – rjacks

1

嘗試將註釋移至#version聲明之後。這應該不重要,但可能會有驅動程序錯誤。

此外,嘗試在文件末尾添加一個額外的空行。再次,只是爲了確定。

最後,確保您事實上正確加載了字符串。在調試器中檢查它。並確保您正確地將字符串傳遞給OpenGL。代碼是什麼樣的?

+1

您可能還想確保文件開始時沒有BOM。 (這是大多數編輯器會隱藏的3字節內容,它定義了文件中的Unicode編碼,即使它只使用拉丁字符) – Kromster

3

雖然答案已經提供並接受,我就寫到這裏我怎麼會喜歡它:

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

我冒昧地刪除所有的try/catch/finally塊,因爲他們錯放了一下:如果讀取任何源文件失敗,着色器加載無法完成,所以沒有意義繼續優雅地處理這個問題的方式是圍繞這個大的try/catch塊,清理着色器編譯的OpenGL對象沒有完成。

+0

如果你不是用Java編程,而是用指針(C,C++,D,Go)編寫的語言,那麼另一種可行的方法是嘗試將內存映射到文件而不是將其讀入緩衝區。 – datenwolf

+0

此代碼*爲*更好... 。再一次,謝謝你。 – rjacks