Проблема компиляции шейдеров OpenGL - неожиданный EOF - PullRequest
9 голосов
/ 19 июня 2011

Поэтому я решил попробовать написать простое приложение OpenGL с использованием Java, просто чтобы увидеть, как оно сравнивается с другими моими усилиями, и я столкнулся с проблемой, когда мои шейдеры отказываются компилироваться.Они действительно не могли стать намного проще, вот мой вершинный шейдер, чтобы продемонстрировать, что я имею в виду:

//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>"

Я не уверен, что это актуально ... но я разрабатываю для 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 () не на самом деле, где ошибка обнаружена, это не происходит, пока выполнение не возвращается к вызывающей функции, и я не проверяю журналы шейдеров.Может быть уместно, но опять же я мог бы быть бессвязным.

Ответы [ 3 ]

13 голосов
/ 19 июня 2011

ОК, теперь я вижу проблему. Ваш код загрузки не работает. Но не волнуйся; Многие люди запутываются, когда видят, что 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; он должен показать вам, как это сделать правильно (хотя я надеюсь, что BufferedReader сможет каким-то образом прочитать весь файл как строку, а не построчно.

3 голосов
/ 19 июня 2011

Несмотря на то, что ответ уже предоставлен и принят, я просто напишу здесь, как предпочитаю:

// 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, поскольку компиляция шейдеров не завершается.

1 голос
/ 19 июня 2011

Попробуйте переместить комментарий после объявления #version. Это не должно иметь значения, но могут быть ошибки драйвера.

Также попробуйте добавить дополнительную пустую строку в конец файла. Опять же, просто чтобы быть уверенным.

Наконец, убедитесь, что вы действительно правильно загружаете строку. Проверьте это в отладчике. И убедитесь, что вы правильно передаете строку в OpenGL. Как выглядит этот код?

...