2017-02-12 12 views
2

У меня есть приложение Android OpenGL ES, и я хочу найти способ сделать несколько разделов экрана свечением разных цветов одновременно. Само приложение делит экран на 6 столбцов, и этот столбец подсвечивается с уникальным цветом, когда пользователь прикасается к нему.OpenGL ES 2.0: Как реализовать одновременный многоцветный gl_FragColor?

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

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

fragment_shader

precision mediump float;   // Set the default precision to medium. We don't need as high of a 
// precision in the fragment shader. 
uniform sampler2D u_Texture;    // The input texture. 

varying vec2 v_TexCoordinate; // Interpolated texture coordinate per fragment. 
varying vec3 v_Position;   // Interpolated position for this fragment. 
varying vec4 v_Color;   // This is the color from the vertex shader interpolated across the triangle per fragment. 
varying vec3 v_Normal;   // Interpolated normal for this fragment. 

uniform vec4 ColumnGlowColor;   // color of the Column 

uniform vec2 eColumnGlowPosition; // where the Column is 
uniform float eColumnGlowSizeScale; // the size to scale the glow 
uniform vec2 aColumnGlowPosition; 
uniform float aColumnGlowSizeScale; 
uniform vec2 dColumnGlowPosition; 
uniform float dColumnGlowSizeScale; 
uniform vec2 gColumnGlowPosition; 
uniform float gColumnGlowSizeScale; 
uniform vec2 bColumnGlowPosition; 
uniform float bColumnGlowSizeScale; 
uniform vec2 eeColumnGlowPosition; 
uniform float eeColumnGlowSizeScale; 

float generateGlow(vec2 pixelPosition, float ColumnGlowScale, vec2 touchPosition){ 
if(stringGlowScale == 0.0) { 
    return 0.0; 
} 
else if (touchPosition.y > pixelPosition.y){ 
    highp float distance = length(touchPosition-pixelPosition); // the horizontal distance from the current pixel and the light source 
    highp float threshold = .5*stringGlowScale;        //defines the effect width 
    highp float effectScale = sin((max(threshold-distance, .0))/threshold); // using sin function smooth the effect 
    return effectScale; 
} 
else{ 
    highp float distance = abs(touchPosition.x-pixelPosition.x); // the horizontal distance from the current pixel and the light source 
    highp float threshold = .5*stringGlowScale;        //defines the effect width 
    highp float effectScale = sin((max(threshold-distance, .0))/threshold); // using sin function smooth the effect 
    return effectScale; 
} 
} 

// The entry point for our fragment shader. 
void main(){ 
    highp float effectScale = 0.0; 
    effectScale += generateGlow(v_Position.xy, eColumnGlowSizeScale, eColumnGlowPosition); 
    effectScale += generateGlow(v_Position.xy, aColumnGlowSizeScale, aColumnGlowPosition); 
    effectScale += generateGlow(v_Position.xy, dColumnGlowSizeScale, dColumnGlowPosition); 
    effectScale += generateGlow(v_Position.xy, gColumnGlowSizeScale, gColumnGlowPosition); 
    effectScale += generateGlow(v_Position.xy, bColumnGlowSizeScale, bColumnGlowPosition); 
    effectScale += generateGlow(v_Position.xy, eeColumnGlowSizeScale, eeColumnGlowPosition); 

    lowp vec4 fromTexture = texture2D(u_Texture, v_TexCoordinate); 

    gl_FragColor = fromTexture + ColumnGlowColor*effectScale; 
} 

Renderer

public class OpenGL_GLRenderer implements GLSurfaceView.Renderer { 
    ... 

    private void setUniforms(int programHandle){ 
      ... 
      mGlowColorHandle = GLES20.glGetUniformLocation(programHandle, "stringGlowColor");   //glow color 
      mStringID = GLES20.glGetUniformLocation(programHandle, "stringNum"); 
      mGlowPosHandles[0] = GLES20.glGetUniformLocation(programHandle, "eStringGlowPosition");  //glow effect position on neck 
      mGlowScaleHandles[0] = GLES20.glGetUniformLocation(programHandle, "eStringGlowSizeScale"); //glow effect strength 
      mGlowPosHandles[1] = GLES20.glGetUniformLocation(programHandle, "aStringGlowPosition"); 
      mGlowScaleHandles[1] = GLES20.glGetUniformLocation(programHandle, "aStringGlowSizeScale"); 
      mGlowPosHandles[2] = GLES20.glGetUniformLocation(programHandle, "dStringGlowPosition"); 
      mGlowScaleHandles[2] = GLES20.glGetUniformLocation(programHandle, "dStringGlowSizeScale"); 
      mGlowPosHandles[3] = GLES20.glGetUniformLocation(programHandle, "gStringGlowPosition"); 
      mGlowScaleHandles[3] = GLES20.glGetUniformLocation(programHandle, "gStringGlowSizeScale"); 
      mGlowPosHandles[4] = GLES20.glGetUniformLocation(programHandle, "bStringGlowPosition"); 
      mGlowScaleHandles[4] = GLES20.glGetUniformLocation(programHandle, "bStringGlowSizeScale"); 
      mGlowPosHandles[5] = GLES20.glGetUniformLocation(programHandle, "eeStringGlowPosition"); 
      mGlowScaleHandles[5] = GLES20.glGetUniformLocation(programHandle, "eeStringGlowSizeScale"); 

      //************************Column Glow code******************************* 
      //if user's touching the screen, make nearest string glow 
      for (int i = 0; i< 6; i++) { 
       if (stringGlowEffects[i] != null) { 
        float top = orthoTop + (orthoBottom-orthoTop)*stringGlowEffects[i].y + scroller.getCurrentValue(); 
        GLES20.glUniform2f(mGlowPosHandles[i], stringGlowEffects[i].x, top); 
        float glowEffectScale = 1.0f + (50.0f)/300.0f; 
        GLES20.glUniform1f(mGlowScaleHandles[i], glowEffectScale);  //TODO: allow multiple colors simultaneously 
        switch (i){ 
         case 0: 
          GLES20.glUniform4f(mGlowColorHandle,.0f, .0f, 1.0f, 1.0f); 
          break; 
         case 1: 
          GLES20.glUniform4f(mGlowColorHandle,.0f, 1.0f, .0f, 1.0f); 
          break; 
         case 2: 
          GLES20.glUniform4f(mGlowColorHandle,1.0f, .0f, .0f, 1.0f); 
          break; 
         case 3: 
          GLES20.glUniform4f(mGlowColorHandle,.0f, 1.0f, 1.0f, 1.0f); 
          break; 
         case 4: 
          GLES20.glUniform4f(mGlowColorHandle,1.0f, 1.0f, .0f, 1.0f); 
          break; 
         case 5: 
          GLES20.glUniform4f(mGlowColorHandle,1.0f, .0f, 1.0f, 1.0f); 
          break; 
        } 
       } 
       else{ 
        GLES20.glUniform1f(mGlowScaleHandles[i], 0.0f); 
       } 
      } 
     } 
    ... 
} 
+0

Вы не можете отказаться от событий с несколькими касаниями? –

+0

@UtsavShrestha Я мог, но я этого не хочу. Multi-touch является частью обычного поведения приложения, и шейдер должен уметь это обрабатывать. – Cody

+0

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

ответ

1

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

В вашем шейдере, вы бы изменить ColumnGlowColor на массив (проще, чем 6 отдельных переменных, а с позиции и масштаба переменных):

uniform vec4 ColumnGlowColor[6];   // color of the Column 

Как на самом деле применить это к выходу цвета трудно сказать, так как вы не показываете этот код о том, как действительно вычисляется свечение. Представляется разумным предположить, что функция generateGlow возвращает интенсивность свечения во входном местоположении. Вместо того, чтобы возвращать интенсивность, вы должны вернуть ему float4, который является цветом (в компонентах RGB) и интенсивностью в alpha. Затем вы изменили бы вашу последнюю строку вашего пиксельных шейдеров просто:

gl_FragColor = fromTexture + sumOfReturnsFromGenerateGlow; 

Когда вы получите расположение униформы вам могут понадобиться, чтобы добавить оператор массива, чтобы правильно привязать его (некоторые водители разрешительные об этом, другие - нет). Ваше первоначальное название было stringGlowColor, но оно должно соответствовать единообразное имя:

mGlowColorHandle = GLES20.glGetUniformLocation(programHandle, "ColumnGlowColor[]"); 

При установке значения mGlowColorHandle, вы бы установить каждый элемент массива, установив при добавлении индекса к форме. Например, для первого набора столбцов изменятся на:

GLES20.glUniform4f(mGlowColorHandle+i,.0f, .0f, 1.0f, 1.0f); 

ПРИМЕЧАНИЕ: Вы можете выводить несколько цветов из вашего шейдера, если вы используете расширение EXT_draw_buffers Глеса. Однако это не то, что вы хотите сделать, поскольку я предполагаю, что у вас нет нескольких фреймбуферов.

+0

Я не знаком с тем, как я изменил бы свой шейдер, чтобы реализовать эту функцию цвета на квадрат (я новичок в OpenGL ES). Не могли бы вы предоставить пример кода? – Cody

+0

, отредактированный для добавления определенных инструкций. – MuertoExcobito

+0

Спасибо. Я редактировал сообщение, чтобы включить логику метода generateGlow(). Вы правы, что я возвращаю значение интенсивности из этого метода. Как я могу определить, какие значения цвета возвращаются в этом методе? Блок if-else, который выбирает цвет, основанный на позиции касания оси x? Я не уверен, как определить ширину экрана из этой области, поэтому я не знаю, как я могу легко проверить, какая из 6 столбцов экрана touchPosition.x находится. – Cody