OpenGL ES 2.0:如何实现同时多色gl_FragColor?

问题描述:

我有一个OpenGL ES Android应用程序,我想找到一种方法使屏幕的多个部分同时以不同的颜色发光。应用程序本身将屏幕分为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; 
} 

渲染

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我可以但我不想。多点触控是应用程序正常行为的一部分,着色器需要能够处理它。 – Cody

+0

在这种情况下,我会提出这个问题,希望有更多着色器经验的人会回答你的问题。 –

可能解决您的问题的最简单方法是设置每个方格的颜色,而不必对色彩的单个统一。您已经完成了列的位置和大小,您可以轻松地将其扩展为记录每列的颜色。

在你的着色器,你会改变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 GLES扩展。然而,这不是你想要做的,因为我假设你没有多个帧缓冲器。

+0

我不熟悉如何改变我的着色器来实现这种每平方的颜色功能(我是OpenGL ES的新手)。你能提供一些示例代码吗?编辑 – Cody

+0

以添加特定说明。 – MuertoExcobito

+0

谢谢。我编辑了我的帖子,以包含generateGlow()方法逻辑。你是正确的,我从这个方法返回一个强度值。我怎么能确定在这个方法中返回哪个颜色值?一个if-else块根据x轴触摸位置选择一种颜色?我不知道如何从这个范围中确定屏幕的宽度,所以我不知道如何轻松测试touchPosition.x中的6个屏幕列中的哪一列。 – Cody