2015-07-03 12 views
0

ОбзораИзменение непрозрачности отдельных элементов в OpenGL ES 2.0 Quad Batch

В моем приложении (это игра), я использую группирование элементов, чтобы уменьшить количество вызовов отрисовки. Итак, я создам, например, объект Java под названием платформы, который для всех платформ в игре. Все враги собраны вместе, как и все предметы коллекционирования и т. Д.

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

Дозирование

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

Ниже приводится представление о том, что я делаю - я понимаю, что это может не скомпилировать, это просто дать идею для цели вопроса.

public void draw(){ 

    //Upload vertices 
    for (count = 0;count<numOfSpritesInBatch;count+=1){ 

     vertices[x] = xLeft;   
     vertices[(x+1)] = yPTop;  
     vertices[(x+2)] = 0;  
     vertices[(x+3)] = textureLeft; 
     vertices[(x+4)] = 0; 
     vertices[(x+5)] = xPRight; 
     vertices[(x+6)] = yTop; 
     vertices[(x+7)] = 0; 
     vertices[(x+8)] = textureRight; 
     vertices[x+9] = 0; 
     vertices[x+10] = xLeft; 
     vertices[x+11] = yBottom; 
     vertices[x+12] = 0; 
     vertices[x+13] = textureLeft; 
     vertices[x+14] = 1; 
     vertices[x+15] = xRight; 
     vertices[x+16] = yTop; 
     vertices[x+17] = 0; 
     vertices[x+18] = textureRight; 
     vertices[x+19] = 0; 
     vertices[x+20] = xLeft; 
     vertices[x+21] = yBottom; 
     vertices[x+22] = 0; 
     vertices[x+23] = textureLeft; 
     vertices[x+24] = 1; 
     vertices[x+25] = xRight; 
     vertices[x+26] = yBottom; 
     vertices[x+27] = 0; 
     vertices[x+28] = textureRight; 
     vertices[x+29] = 1; 

     x+=30; 
    } 

    vertexBuf.rewind(); 
    vertexBuf.put(vertices).position(0); 

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID); 

    GLES20.glUseProgram(iProgId); 

    Matrix.multiplyMM(mvpMatrix2, 0, mvpMatrix, 0, mRotationMatrix, 0); 

    mMVPMatrixHandle = GLES20.glGetUniformLocation(iProgId, "uMVPMatrix"); 

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix2, 0); 

    vertexBuf.position(0); 
    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf); 
    GLES20.glEnableVertexAttribArray(iPosition); 
    vertexBuf.position(3); 
    GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf); 
    GLES20.glEnableVertexAttribArray(iTexCoords); 

    //Enable Alpha blending and set blending function 
    GLES20.glEnable(GLES20.GL_BLEND); 
    GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); 

    //Draw it 
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6 * numOfSpritesInBatch); 

    //Disable Alpha blending 
    GLES20.glDisable(GLES20.GL_BLEND); 
} 

шейдеры

String strVShader = 
    "uniform mat4 uMVPMatrix;" + 
    "attribute vec4 a_position;\n"+ 
    "attribute vec2 a_texCoords;" + 
    "varying vec2 v_texCoords;" + 
    "void main()\n" + 
    "{\n" + 
    "gl_Position = uMVPMatrix * a_position;\n"+ 
    "v_texCoords = a_texCoords;" + 
    "}"; 

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

В настоящее время у меня есть метод в моем классе Sprite, который позволяет мне изменить opacty. Например, примерно следующее:

spriteBatch.setOpacity(0.5f); //Half opacity 

Это работает, но меняет всю партию - не то, что мне нужно.

Применение

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

Единственные другие альтернативы:

  • Создание 10 текстур на разных уровнях непрозрачности и просто переключаться между ними, чтобы создать эффект замирания. На самом деле вариант не слишком расточительный.
  • Создайте каждый из этих объектов отдельно и нарисуйте каждый со своим собственным призывом рисования. Будет работать, но с максимальным количеством из 10 этих объектов на экране я могу потенциально рисовать, используя 10 призывов рисования только для этих предметов - в то время как игра в целом в настоящее время использует только 20 призывов рисования, чтобы нарисовать сотни предметов.

Мне нужно посмотреть на будущие использования этого также в системах частиц и т. Д., Поэтому я хотел бы попытаться выяснить, как это сделать (уметь отдельно регулировать непрозрачность каждого предмета). Если мне нужно сделать это в шейдере, я был бы признателен, если бы вы могли показать, как это работает. Альтернативно, возможно ли это сделать за пределами шейдера?

Несомненно, это может быть сделано так или иначе? Все предложения приветствуются ....

+0

Как насчет использования атрибута вершины для непрозрачности? Измените '' '' '' '' '' '' '' '' 'на' атрибут' в вершинном шейдере и передайте в perle-вершины, как и другие атрибуты вершин, которые у вас уже есть. –

+0

Я был в этом весь день @RetoKoradi, я изменил свой opValue на атрибут, как было предложено, но я не могу понять, как отправить эту информацию в шейдер - любые подсказки? На данный момент я устанавливаю свою непрозрачность перед рендерингом с этим: mOpacityHandle = GLES20.glGetUniformLocation (iProgId, «opValue»); а затем GLES20.glUniform1f (mOpacityHandle, op); \t Благодарен за некоторые рекомендации, спасибо – Zippy

+0

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

ответ

2

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

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

Так в вершинном шейдере, то добавьте:

... 
attribute float a_opValue; 
varying float v_opValue; 
... 
    v_opValue = a_opValue; 
... 

В пиксельный шейдер, вы удалите единую декларацию для opValue, и заменить его:

varying float v_opValue; 
... 
    gl_FragColor *= v_opValue; 
... 

В коде Java, вы расширяете данные вершин с дополнительным значением для непрозрачности, чтобы использовать 6 значений на вершину (3 позиции, 2 координаты текстуры, 1 непрозрачность) и обновить настройку состояния соответственно:

vertexBuf.position(0); 
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf); 
GLES20.glEnableVertexAttribArray(iPosition); 
vertexBuf.position(3); 
GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf); 
GLES20.glEnableVertexAttribArray(iTexCoords); 
vertexBuf.position(5); 
GLES20.glVertexAttribPointer(iOpValue, 1, GLES20.GL_FLOAT, false, 6 * 4, vertexBuf); 
GLES20.glEnableVertexAttribArray(iOpValue); 
+0

Спасибо, @RetroKoradi, это именно то, что мне нужно. По какой-то причине я просто не мог опустить голову, не видя ее. Я отдам его и проверю, когда закончится - спасибо. – Zippy