Переключить шейдерную программу в WebGL - PullRequest
4 голосов
/ 05 февраля 2012

У меня есть существующий рендерер WebGL (слишком много кода, чтобы его можно было поделиться), который раньше был очень простым: у него был только один вершинный шейдер, один фрагментный шейдер и одна шейдерная программа с обоими. Это было для рендеринга квадов.

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

Кажется, я не могу правильно переключаться между ними: у меня постоянно появляются проблемы с отображением, случайно исчезающие объекты и тому подобное. Вот две функции, которые я должен переключать между ними. Есть идеи, что мне не хватает?

GLWrapProto.switchQuadProgram = function ()
{
    var gl = this.gl;

    gl.useProgram(this.shaderProgramPoint);

    gl.disableVertexAttribArray(this.locAPosPoint);

    gl.useProgram(this.shaderProgram);

    gl.enableVertexAttribArray(this.locAPos);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.vertexAttribPointer(this.locAPos, 2, gl.FLOAT, false, 0, 0);

    gl.enableVertexAttribArray(this.locATex);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.vertexAttribPointer(this.locATex, 2, gl.FLOAT, false, 0, 0);
};

GLWrapProto.switchPointProgram = function ()
{
    var gl = this.gl;

    gl.useProgram(this.shaderProgram);

    gl.disableVertexAttribArray(this.locAPos);
    gl.disableVertexAttribArray(this.locATex);

    gl.useProgram(this.shaderProgramPoint);

    gl.enableVertexAttribArray(this.locAPosPoint);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.pointBuffer);
    gl.vertexAttribPointer(this.locAPosPoint, 4, gl.FLOAT, false, 0, 0);
};

1 Ответ

3 голосов
/ 06 февраля 2012

Трудно сказать, в чем проблема из этого куска кода, но позвольте мне высказать несколько предложений, чтобы попытаться помочь вам найти проблему.

Прежде всего, вы не знаетенужно слишком много беспокоиться о том, чтобы делать disableVertexAttribArray каждый раз, когда вы переключаете шейдеры.Включенные / отключенные массивы - это состояние, связанное с шейдером, и поэтому изменение связанной программы в любом случае делает недействительными ваши ранее включенные массивы.

(На самом деле, кто-нибудь знает, достойную цитату для этого, я пыталсянайти его и не могу в данный момент.)

Имея это в виду, вы можете упростить приведенный выше код до:

GLWrapProto.switchQuadProgram = function ()
{
    var gl = this.gl;

    gl.useProgram(this.shaderProgram);

    gl.enableVertexAttribArray(this.locAPos);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.vertexAttribPointer(this.locAPos, 2, gl.FLOAT, false, 0, 0);

    gl.enableVertexAttribArray(this.locATex);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.vertexAttribPointer(this.locATex, 2, gl.FLOAT, false, 0, 0);
};

GLWrapProto.switchPointProgram = function ()
{
    var gl = this.gl;

    gl.useProgram(this.shaderProgramPoint);

    gl.enableVertexAttribArray(this.locAPosPoint);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.pointBuffer);
    gl.vertexAttribPointer(this.locAPosPoint, 4, gl.FLOAT, false, 0, 0);
};

Мне любопытно, о какой проблеме вы упомянули"глюки дисплея", хотя.Я не могу придумать причину, по которой переключение шейдеров может привести к случайной остановке объектов и началу рендеринга.Попробуйте сначала отрисовать только геометрию, используя один шейдер, затем переключитесь и отрендерируйте только геометрию, которая использует другой.Если у любого из них есть проблема, то вы знаете, что проблема не в переключении шейдеров.Если проблема возникает только при рендеринге обоих наборов геометрии, между ними может быть какая-то ошибка в управлении состоянием.

...