Можно ли установить начальное значение для шейдерной формы? (Андроид, OpenGL ES 2.0)

редактировать: как было предложено, я пытаюсь установить «начальное» значение для своих шейдеров в своем конструкторе, я включил некоторый код и был бы признателен, если бы кто-нибудь мог объяснить, почему я получаю пустой экран. если я передам значения через свой конструктор - спасибо

Способ загрузки моей текстуры

public void setTexture(GLSurfaceView view, Bitmap imgTexture) {
    this.imgTexture=imgTexture;
    iProgId = Utils.LoadProgram(strVShader, strFShader);
    iBaseMap = GLES20.glGetUniformLocation(iProgId, "u_baseMap");
    iPosition = GLES20.glGetAttribLocation(iProgId, "a_position");
    iTexCoords = GLES20.glGetAttribLocation(iProgId, "a_texCoords");
    texID = Utils.LoadTexture(view, imgTexture);

    //Everything is working if I include the lines as part of my setTexture() method
    GLES20.glUseProgram(iProgId);
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");
    GLES20.glUniform1f(mOpacityHandle, 1.0f);
}

но если я помещу их в свой конструктор, ничего....

public Quad() {
    //iProgId = Utils.LoadProgram(strVShader, strFShader); //I've tried with and without this line - I can confirm that loading / linking is working OK
    GLES20.glUseProgram(iProgId);
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");          
    GLES20.glUniform1f(mOpacityHandle, 1.0f);           
}

На самом деле я скопировал всю свою процедуру загрузки текстуры в свой конструктор и передал ей соответствующие параметры при создании своих четырехугольников, но я все еще ничего не делаю, если не устанавливаю значение через некоторое время после запуска конструктора!

У меня есть фрагментный шейдер, как показано ниже:

String strFShader =
    "precision mediump float;" +
    "uniform float opValue;"+
    "varying vec2 v_texCoords;" +
    "uniform sampler2D u_baseMap;" +
    "void main()" +
    "{" +
    "gl_FragColor = texture2D(u_baseMap, v_texCoords);" +
    "gl_FragColor *= opValue;"+
    "}";

И когда я создаю свои объекты (квадраты), у меня есть метод, в котором я могу установить непрозрачность указанного четырехугольника следующим образом:

public void setOpacity(float op) {  
    GLES20.glUseProgram(iProgId);       
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");
    GLES20.glUniform1f(mOpacityHandle, op);
}

Однако я хочу запускать свой метод setOpacity только в том случае, если я хочу, чтобы мой спрайт (квадрат) имел некоторый уровень прозрачности. Если я не укажу уровень непрозрачности (т.е. если я не запускаю метод setOpacity), я бы хотел, чтобы он использовал значение по умолчанию или «начальное» значение (которое, очевидно, я хотел бы иметь с плавающей запятой 1,0).

Это вообще возможно?


person Zippy    schedule 11.04.2013    source источник


Ответы (1)


Вы не можете инициализировать униформу, используя какой-то uniform opValue = 1.0; внутри шейдера, если это то, что вы имели в виду. Даже если бы вы могли, это не принесло бы вам многого, потому что единые значения сохраняются при использовании программы. Это означает, что если вы активируете другую программу (используя glUseProgram), а затем перепривязываете эту программу, униформа по-прежнему будет иметь то значение, которое вы установили в прошлый раз. Таким образом, вы можете установить юниформу в какое-то начальное значение сразу после компоновки программы, но она потеряет это значение навсегда, как только вы измените его на какой-нибудь прозрачный спрайт.

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

draw_opaque_sprite();

setOpacity(0.5f);
draw_transparent_sprite();

draw_opaque_sprite();

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

Таким образом, вы не обойдетесь правильной настройкой униформы для каждого спрайта. Обычная оптимизация в этом случае — сортировка ваших объектов по их состоянию рендеринга (в вашем случае непрозрачность, но, возможно, какое-то другое состояние еще тяжелее, например, текстура или что-то в этом роде), чтобы уменьшить изменения состояния (например, изменения шейдера, текстуры). привязки или, в данном случае, единые обновления), насколько это возможно.

person Christian Rau    schedule 11.04.2013
comment
Спасибо за это @ChristianRau, но я не хочу сбрасывать непрозрачность после каждого рисования/рендеринга, скорее, когда я создаю свои объекты (например, quad1 = new Quad();), и впоследствии я не устанавливаю непрозрачность , я хотел бы принять стандартную непрозрачность 1,0. - person Zippy; 11.04.2013
comment
@Zippy Ну, установите для него значение по умолчанию 1.0 (используя glUniform, как обычно), и оно останется таким, пока вы его не измените, затем оно сохранит новое значение, пока вы его не измените, как объяснено в ответе. Вы не можете установить значение для каждого объекта, потому что OpenGL не имеет абсолютно никакого понятия о каких-либо объектах. Существует одно единственное значение для каждого юниформа каждой программы, и это значение изменяется только тогда, когда вы вызываете glUniform. Так все работает в OpenGL, это конечный автомат. - person Christian Rau; 11.04.2013
comment
Еще раз спасибо @ChristianRau, я должен признать, что я новичок в OGL, поэтому ваши объяснения очень ценятся. Если я создам 2 четырехугольника из своего пользовательского класса, а затем установлю разные уровни непрозрачности для каждого, если они используют одну и ту же программу и шейдеры, почему они отображают каждый со своим собственным уровнем непрозрачности? Спасибо, у меня проблемы с пониманием этого. Что касается установки уровня «изначально» с помощью glUniform, я пытался сделать это в конструкторе, но это не сработает, я предполагаю, потому что шейдерная программа в точке конструктора еще не была создана/связана . - person Zippy; 11.04.2013
comment
@Ziggy Вы можете изменить юниформ-значение, когда захотите. При рисовании чего-либо (например, с помощью glDrawArrays или glDrawElements) это момент, когда нарисованные объекты будут отправлены через графический конвейер и через шейдеры, а шейдеры будут использовать униформы. Если вы ничего не рисуете, то, конечно, шейдеры ничего не делают. Итак, привяжите программу (glUseProgram), установите состояние (включая его униформы) для первого объекта, нарисуйте его, затем установите состояние для второго объекта, затем нарисуйте его... - person Christian Rau; 12.04.2013
comment
... Вот как работает OpenGL. Он состоит из набора состояний, которые изменяются только тогда, когда вы меняете их, и вступают в силу только тогда, когда вы фактически визуализируете что-либо с помощью команды рисования. В OpenGL нет понятия абстрактных объектов сцены. Когда вы рисуете что-то, его вершины будут проходить через графический конвейер и отображаться на экране с использованием текущего состояния OpenGL (активные текстуры, активная программа, ее униформы, глобальные состояния, ...), и после того, как вершины будут отрисованы, OpenGL полностью забывает о них и следующий кадр все начинается заново. - person Christian Rau; 12.04.2013
comment
Спасибо @ChristianRau, до сих пор не уверен, что понимаю, потому что я устанавливаю непрозрачность (то есть свою униформу) только один раз для каждого экземпляра моего объекта Quad (фактически в onSurfaceCreated) сразу после создания объектов. Не каждый цикл рендеринга. И он сохраняет правильное значение для каждого из четырехугольников, даже если я не устанавливаю значение каждый раз..? И значение, похоже, не попадает в шейдер, когда я отправил его в конструкторе. - person Zippy; 12.04.2013
comment
Я устанавливаю непрозрачность (т.е. свою униформу) только один раз для каждого экземпляра моего объекта Quad после того, как объекты были созданы. Не каждый цикл рендеринга? - Это не сработает. И он сохраняет правильное значение для каждого из четырехугольников, даже если я не устанавливаю значение каждый раз..? - Это может быть совпадением, так как он сохраняет свое значение между кадрами, но не для каждого. -object (поскольку объектов для GL нет) - person Christian Rau; 12.04.2013
comment
Вы говорите, что при использовании OpenGL правила о java-объектах не применяются? (т.е. у меня есть мои шейдеры и программа в моем четырехъядерном классе, но каждый «объект», который я создаю, использует одни и те же? Просто чтобы я понял это, поскольку я нахожу это довольно запутанным! - person Zippy; 12.04.2013
comment
И значение, кажется, не попадает в шейдер, когда я отправил его в конструкторе. - Потому что glUniform работает только в том случае, если активна соответствующая программа (glUseProgram используется с ней). Может быть, в вашем конструкторе его нет (или он еще даже не существует?). - person Christian Rau; 12.04.2013
comment
Я определенно, кажется, работает!! (устанавливая различные значения непрозрачности, размера, поворота) для каждого из моих «объектов», даже если это не предполагается !! Но да, думаю, вы правы в том, что программа недоступна в конструкторе! - person Zippy; 12.04.2013
comment
@Zippy OpenGL не знает Java или каких-либо объектов (ну, у него есть что-то вроде объектов, таких как программы, текстуры, ..., но они работают немного иначе, чем ваши обычные объекты Java). У вас все еще есть ваши объекты, которые могут иметь свои собственные значения непрозрачности (как обычные элементы с плавающей запятой). Но когда вы рисуете их, вы должны установить эти значения непрозрачности в качестве юниформ для активного шейдера. OpenGL — это не библиотека управления сценой, она просто рисует на экране совершенно не связанные между собой простые примитивы (точки, линии и треугольники), используя свое текущее состояние, и ничего больше… - person Christian Rau; 12.04.2013
comment
@Zippy ... Управление любыми дополнительными объектами и сценами полностью зависит от вас. - person Christian Rau; 12.04.2013