I have an android app in which I use openGL to make some neat image effects.
The base setup is that I continually draw the buffer to one of two textures, then draw on top of that texture the next frame (essentially a simulation), to give the effect that the same image keeps getting manipulated.
I'm trying to add a fade effect to this, in which I darken the background, then draw on top of that, but I'm getting a very strange artifact from this. Here is my fragment shader:
private final String mCompositeFragmentShader =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"varying vec2 bTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform samplerExternalOES sTexture;\n" +
"uniform sampler2D bufferTexture;\n" +
"uniform float gamma; \n" +
"void main() {\n" +
" vec4 camera = texture2D(sTexture, vTextureCoord);\n" +
" camera.r = pow(camera.r, 1.0/gamma);\n" +
" camera.g = pow(camera.g, 1.0/gamma);\n" +
" camera.b = pow(camera.b, 1.0/gamma);\n" +
" vec4 bg = texture2D(bufferTexture, bTextureCoord);\n" +
" vec3 color = max(camera.rgb, bg.rgb -vec3(.02, .02, .02));\n"+
" gl_FragColor = vec4(color,1.0);\n" +
"}\n";
with the relevant bit of code being:
vec3 color = max(camera.rgb, bg.rgb -vec3(.02, .02, .02));
So I would expect light areas to eventually fade to black over time. However, instead of black it's fading to a magenta grid:
You can see that the gridding is different for each triangle being drawn on the screen (I'm only drawing two triangles).
Here is the vertex shader, just in case:
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uSTMatrix;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec4 tempCoords;" +
"varying vec2 vTextureCoord;\n" +
"varying vec2 bTextureCoord;\n" +
"void main() {\n" +
" gl_Position = aPosition;\n" +
" bTextureCoord = aTextureCoord.xy;\n" +
" tempCoords = aTextureCoord;\n" +
" tempCoords.y = aTextureCoord.y * ("+previewSize.height+".0 /"+previewSize.width+".0);\n" +
" vTextureCoord = (uSTMatrix * tempCoords).xy;\n" +
"}\n";
Anyone have any idea what's causing this, and how to fix it?
Related
The code inside my fragment shader is:
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"uniform float Opacity;\n" + // range 0.0 to 1.0
"void main() {\n" +
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n"+
" gl_FragColor.a *= Opacity;\n" +
"}\n";
which works, I tried to add an if inside :
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"uniform float Opacity;\n" + // range 0.0 to 1.0
"void main() {\n" +
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n"+
" gl_FragColor.a *= Opacity;\n" +
" if(gl_FragColor.a < 250){;\n" +
" gl_FragColor.a = 250;\n" +
" }\n" +
"}\n";
and it does not work, I cant figure this one out, I will appreciate some help
I am a freshman with OpenGL. I try to find the solution to my problem. I have recorded a video with alpha mask. The top part of video RGB and bottom is alpha. As I understand need to change my shaders, but I don`t understand how to do this.
Vertex shader
private static final String vertexShaderCode =
"attribute vec4 vPosition;" +
"attribute vec4 vTexCoordinate;" +
"uniform mat4 textureTransform;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" v_TexCoordinate = (textureTransform * vTexCoordinate).xy;" +
" gl_Position = vPosition;" +
"}";
Fragment shader
private static final String fragmentShaderCode =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"uniform samplerExternalOES texture;" +
"varying vec2 v_TexCoordinate;" +
"void main () {" +
" vec4 color = texture2D(texture, v_TexCoordinate);" +
" gl_FragColor = color;" +
"}";
To skip fragments you can use the discard keyword in the fragment shader.
You have to do 2 look ups to the texture. The first one in the upper half, to get the RGB color channels and the 2nd one in the lower half to get the mask from the red color channel:
vec2 c_uv = vec2(texture.x, texture.y*0.5);
vec4 color = texture2D(c_uv, v_TexCoordinate);
vec2 m_uv = vec2(texture.x, 0.5 + texture.y*0.5);
float mask = texture2D(m_uv, v_TexCoordinate).r;
The fragment shader may look like this:
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES texture;
varying vec2 v_TexCoordinate;
void main () {
vec2 m_uv = vec2(v_TexCoordinate.x, 0.5 + v_TexCoordinate.y*0.5);
float mask = texture2D(texture, m_uv).r;
if ( mask < 0.5 )
discard;
vec2 c_uv = vec2(v_TexCoordinate.x, v_TexCoordinate.y*0.5);
vec4 color = texture2D(texture, c_uv);
gl_FragColor = color;
}
For my android application, I want to apply brightness and contrast shader on same image.
At present I am using gpuimage plugin. In that I found two separate program for brightness and contrast as per the following.
public static final String CONTRAST_FRAGMENT_SHADER = "" +
"varying highp vec2 textureCoordinate;\n" +
" \n" +
" uniform sampler2D inputImageTexture;\n" +
" uniform lowp float contrast;\n" +
" \n" +
" void main()\n" +
" {\n" +
" lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" +
" \n" +
" gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\n" +
" }";
public static final String BRIGHTNESS_FRAGMENT_SHADER = ""
+ "varying highp vec2 textureCoordinate;\n"
+ " \n"
+ " uniform sampler2D inputImageTexture;\n"
+ " uniform lowp float brightness;\n"
+ " \n"
+ " void main()\n"
+ " {\n"
+ " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n"
+ " \n"
+ " gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\n"
+ " }";
Now applying both of the effects I write following code
public static final String CONTRAST_BRIGHTNESS_FRAGMENT_SHADER = ""
+ "varying highp vec2 textureCoordinate;\n"
+ " uniform sampler2D inputImageTexture;\n"
+ "varying highp vec2 textureCoordinate2;\n"
+ " uniform sampler2D inputImageTexture2;\n"
+ " uniform lowp float contrast;\n"
+ " uniform lowp float brightness;\n"
+ " \n"
+ " void main()\n"
+ " {\n"
+ " lowp vec4 textureColorForContrast = texture2D(inputImageTexture, textureCoordinate);\n"
+ " \n"
+ " lowp vec4 contastVec4 = vec4(((textureColorForContrast.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColorForContrast.w);\n"
+ " lowp vec4 textureColorForBrightness = texture2D(inputImageTexture2, textureCoordinate2);\n"
+ " \n"
+ " lowp vec4 brightnessVec4 = vec4((textureColorForBrightness.rgb + vec3(brightness)), textureColorForBrightness.w);\n"
+ " gl_FragColor = contastVec4 + brightnessVec4;\n" + " }";
Doesn't able to get desire result. I can't able to figure out what I have to do next?
What program I have to write?
Why would you add the 2 results in the end? What you need to do is fetch a texel and do the 2 mathematical operations on it. Try this:
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
lowp vec3 contrastedColor = ((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5));
gl_FragColor = vec4((contrastedColor + vec3(brightness)), textureColor.w);
Still this can produce a different result then using the 2 separate shaders so let's analyse a bit what goes on:
grab a texture color
apply contrast method
write colour to buffer (at this point the colour values are clamped in range [.0, 1.0])
grab a texture color
apply brightness
write colour to buffer
So what you should add is clamping the contrast colour contrastedColor to [0,1]. As for what M. Coleman said it is true you need to consider the possibility of the result being different because of fetching multiple texels BUT in your specific case that can NOT produce a different result and you are all good to go with it. As for the blending the assumption is being either disabled or (GL_ONE, GL_ZERO) which is the same thing (some other blending types might work as well).
How can I pass a float value to fragment shader ?
This is my code on android:
int aUseTexture = GLES20.glGetAttribLocation(program, "uUseTexture");
GLES20.glUniform1f(aUseTexture, 1.0f);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
Here is my shader:
String verticesShader =
"uniform mat4 uScreen;\n" +
"attribute vec2 aPosition;\n" +
"attribute vec3 aColor;\n" +
"attribute vec2 aTexPos; \n" +
"varying vec2 vTexPos; \n" +
"varying vec3 vColor;\n" +
"void main() {\n" +
" vTexPos = aTexPos; \n" +
" gl_Position = uScreen * vec4(aPosition.xy, 0.0, 1.0);\n" +
" vColor = aColor;\n" +
"}";
// Our fragment shader. Just return vColor.
// If you look at this source and just said 'WTF?', remember
// that all the attributes are defined in the VERTEX shader and
// all the 'varying' vars are considered OUTPUT of vertex shader
// and INPUT of the fragment shader. Here we just use the color
// we received and add a alpha value of 1.
String fragmentShader =
"uniform float uUseTexture; \n" +
"uniform sampler2D uTexture;\n" +
"precision mediump float;\n"+
"varying vec2 vTexPos; \n" +
"varying vec3 vColor;\n" +
"void main(void)\n" +
"{\n" +
" if ( uUseTexture != 1.0 ) \n" +
" gl_FragColor = vec4(vColor.xyz, 1); \n" +
" else \n" +
" gl_FragColor = texture2D(uTexture, vTexPos); \n" +
//" gl_FragColor = vec4(vColor.xyz, 1);\n" +
"}";
You can see the if statement in the fragment shader , that is the one i tried to check if i pass in 1.0 it should do texture else use color.
You are probably using the wrong function call for "uniform variable". Try glGetUniformLocation() as follow:
int aUseTexture = GLES20.glGetUniformLocation(program, "uUseTexture");
Also, the floating point testing (uUseTexture != 1.0) may not be always reliable all the time. You may want to use an integer type.
As far as I know you have to pass the value through the vertex shader before it can get to the fragment shader. e.g. add "uniform float uUseTexture_in; \n" and "varying float uUseTexture; \n" at the top of the vertex shader, in the main function add "uUseTexture = uUseTexture_in;". And your shader should work
our live wallpaper doesn't work properly on Motorola Atrix phone. It has a stock ROM w/ Android 2.3.
It looks like discard command of fragment shader doesn't work resulting image without transparent parts.
The problem doesn't appear on Desire S w/ Android 2.3, Mototola Droid w/ CM9, ASUS Transformer w/ 4.0, Samsung Galaxy Note w/ 4.0. So the problem seems to be very specific to Motorola Atrix phone.
We use ETC1 compressed textures so alpha channel is passed to shader via separate texture sampler - sTexture is used for main diffuse texture and sAlpha has black-and-white alpha channel.
Here is code for fragment and vertex shaders:
private final String mVertexShader = "uniform highp mat4 uMVPMatrix;\n" +
"attribute highp vec4 aPosition;\n" +
"attribute highp vec2 aTextureCoord;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = aTextureCoord;\n" +
"}\n";
private final String mAlphaFragmentShader = "precision mediump float;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"uniform sampler2D sAlpha;\n" +
"void main() {\n" +
" vec4 base = texture2D(sTexture, vTextureCoord);\n" +
" gl_FragColor = base;\n" +
" if(texture2D(sAlpha, vTextureCoord).r < 0.5){ discard; }\n" +
"}";
OK so I've fixed this. Many thanks to #Tim for willing to run test apps on device and providing me screenshots.
I've modified fragment shader the following way:
private final String mAlphaFragmentShader = "precision mediump float;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"uniform sampler2D sAlpha;\n" +
"void main() {\n" +
" vec4 base = texture2D(sTexture, vTextureCoord);\n" +
" vec4 mask = texture2D(sAlpha, vTextureCoord);\n" +
" gl_FragColor = base;\n" +
" if(mask.g < 0.5){ discard; }\n" +
"}";
It seems that Motorola Atrix OpenGL drivers treat compressed textures in wrong way and sample R channel as A channel which is always 1.0 in case of ETC1 compressed textures. It looks like internal format of texture is treated as ARGB instead of RGBA. Since my mask texture is black-and-white I can fetch any other colour. Green works just fine.