Изменение непрозрачности отдельных элементов в 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, который позволяет мне изменить непрозрачность. Например, что-то вроде этого:

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

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

заявка

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

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

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

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

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

1 ответ

Решение

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

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

Итак, в вершинный шейдер вы добавляете:

...
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);
Другие вопросы по тегам