我有一个 OpenGL ES Android 应用程序,我想找到一种方法让屏幕的多个部分同时以不同颜色发光。该应用程序本身将屏幕分为 6 列,当用户触摸该列时,该列会以独特的颜色亮起。
我遇到的问题是,当用户多次触摸屏幕时,所有列都会发出相同的颜色,而不是它们独特的颜色。原因是每次在列中检测到触摸时,我的渲染器逻辑都会覆盖 gl_FragColor。由于所有列都使用相同的着色器,因此在多点触摸情况下,所有列都以最近设置的颜色发光。
当用户一次触摸多个列时,我如何才能使每一列在触摸时都发出独特的颜色?由于 gl_FragColor 是一个自动生成的变量,我不确定如何添加更多 gl_FragColors,假设这有助于解决问题。
fragment 着色器
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);
}
}
}
...
}
最佳答案
解决问题的最简单方法可能是为每个网格正方形设置颜色,而不是为颜色设置一个统一的颜色。您已经为列的位置和大小完成了此操作,您可以轻松地扩展它以记录每列的颜色。
在您的着色器中,您可以将 ColumnGlowColor
更改为一个数组(比拥有 6 个单独的变量更容易,就像您的位置和比例变量一样):
uniform vec4 ColumnGlowColor[6]; // color of the Column
如何实际将其应用到输出颜色很难说,因为您没有显示关于如何实际计算辉光的代码。假设 generateGlow
函数返回输入位置的辉光强度似乎是合理的。您可以让它返回一个 float4,而不是返回一个强度,它是颜色(在 RGB 分量中)和强度在 alpha 中。然后,您可以将像素着色器的最后一行更改为:
gl_FragColor = fromTexture + sumOfReturnsFromGenerateGlow;
当您获得制服的位置时,您可能需要添加数组运算符以正确绑定(bind)它(一些驱动程序允许这样做,而另一些则不允许)。您的原始名称是 stringGlowColor
,但它应该与统一名称相匹配:
mGlowColorHandle = GLES20.glGetUniformLocation(programHandle, "ColumnGlowColor[]");
当您设置mGlowColorHandle
值时,您将设置每个数组条目,方法是将索引添加到uniform。例如,对于第一列集将更改为:
GLES20.glUniform4f(mGlowColorHandle+i,.0f, .0f, 1.0f, 1.0f);
注意:如果使用 EXT_draw_buffers,您可以从着色器输出多种颜色。 GLES 扩展。但是,这不是您想要做的,因为我假设您没有多个帧缓冲区。
关于android - OpenGL ES 2.0 : How to Implement Simultaneous Multi-Color gl_FragColor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42183684/