Alternative for glBlitFrameBuffer() in OpenGL ES 2.0 - android

My Android program must use glBlitFrameBuffer() function to copy FrameBuffer object. But glBlitFrameBuffer() function is only supported on OpenGL ES 3.0+ devices. I want to support OpenGL ES 2.0+ devices.
Is there any solution/alternative for this function?

Bind texture that used as collor attachment on source frame buffer
Bind destination framebuffer
Draw full screen quad (if you need stretch or offseted reading manipulate with vertex/tex coordinates)
Fetch data from bound texture in frament shader and put it to gl_FragColor

I've created a CopyShader that simply uses a shader to copy from a texture to a framebuffer.
private static final String SHADER_VERTEX = ""
+ "attribute vec4 a_Position;\n"
+ "varying highp vec2 v_TexCoordinate;\n"
+ "void main() {\n"
+ " v_TexCoordinate = a_Position.xy * 0.5 + 0.5;\n"
+ " gl_Position = a_Position;\n"
+ "}\n";
private static final String SHADER_FRAGMENT = ""
+ ""
+ "uniform sampler2D u_Texture;\n"
+ "varying highp vec2 v_TexCoordinate;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(u_Texture, v_TexCoordinate);\n"
+ "}\n”;
Use these as your shaders, and then just set u_Texture to the texture you want to copy from, and bind the framebuffer you want to write to, and you should be set.

Related

Error in Compiling Fragment Shader Program in OpenGL es , Android

I'm new to OpenGL and today I was trying to compile some shader programs for GPGPU usage of OpenGL in android OS.
I have two questions:
1) I only want to program fragment shader, Is it necessary to program the vertex shader too?
2) I face some Errors while compiling my shader source code.
My source code is defined as :
final String src = "#version 310 es\n" +
"uniform sampler2D texUnit;\n" +
"uniform int sequence;\n" +
"void main(void)\n" +
"{\n" +
"const vec3 DotValue = {0.299f , 0.587f , 0.114f};\n" +
"vec2 texCoord = gl_TexCoord[0].xy;\n" +
"vec4 CurrentPixelData = texture2D(texUnit, texCoord);\n" +
"float temp = CurrentPixelData.x * DotValue.x + CurrentPixelData.y * DotValue.y + CurrentPixelData.z * DotValue.z;\n" +
"vec4 result = {temp,temp,temp,CurrentPixelData.w};\n" +
"gl_FragColor = result;\n" +
"}\n";
and the code for creating the shader is:
int fragment = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragment,src);
GLES20.glCompileShader(fragment);
int[] compiled = new int[1];
GLES20.glGetShaderiv(fragment, GLES20.GL_COMPILE_STATUS, compiled, 0); //compile[0] != 0 : compiled successfully
if (compiled[0] == 0) {
Log.e(TAG, "Could not compile shader: ");
Log.e(TAG, GLES20.glGetShaderInfoLog(fragment));
GLES20.glDeleteShader(fragment);
fragment = 0;
} else {
Log.i(TAG, "Compiled shader with source length " + src.length());
}
But when i try to debug my application, there are several errors about shader compilation in the logcat:
0:6: L0001: Expected token ';', found '{'
0:7: L0002: Undeclared variable 'gl_TexCoord'
0:8: L0002: No matching function for call to 'texture2D'
0:9: L0002: Undeclared variable 'CurrentPixelData'
0:10: L0001: Expected token ';', found '{'
0:11: L0002: Undeclared variable 'gl_FragColor'
Can anyone help me what is wrong with my code?
Thanks in advance.
You do need both a vertex shader and a fragment shader.
The syntax errors are already highlighted by the shader compilation log you captured. Providing some more detail on them:
You need to use constructor syntax to initialize vectors:
const vec3 DotValue = vec3(0.299 , 0.587, 0.114);
gl_TexCoord is not a built-in variable. You may have seen it in code samples for desktop OpenGL, where it used to exist. But it's deprecated even there, and never was present in OpenGL ES. You need to pass the texture coordinates into the shader yourself.
texture2D() is not a built-in function. The function for sampling a 2D texture used to be named like this in older GLSL version, but is now overloaded for various sampler types under the name texture():
vec4 CurrentPixelData = texture(texUnit, texCoord);
Looks like just a follow-up error from the previous one.
Same as error 1:
vec4 result = vec4(temp, temp, temp, CurrentPixelData.w);
gl_FragColor used to be a built-in variable in older GLSL versions, but is now deprecated and removed. You need to define your own variable with the qualifier out to define the variable(s) used as shader outputs.
You must write a vertex shader. gl_Position must be assigned values to create triangles and then pixels (fragments).
If you're using texture mapping, you need to assign a varying variable with the texture coordinate assigned to the vertex.
Later, these coordinates are interpolated for each fragment.
The most basic vertex shader would be:
const char* simpleVertexShader=
"attribute vec4 position;"
"attribute vec4 inputTextureCoordinate;
"varying vec2 textureCoordinate;"
"void main(){"
"gl_Position = position;"
"textureCoordinate = inputTextureCoordinate.xy;"
"}";
In you're fragment shader you have syntax error in vec3 and vec4 init.
It should be done like this:
"const vec3 DotValue = vec3(0.299 , 0.587 , 0.114);\n"
and
"vec4 result = vec4(temp,temp,temp,CurrentPixelData.w);\n"
Notice the float literals don't need the 'f' postfix in glsl.
Your fixed code:
final String src = "#version 310 es\n" +
"precision highp float;"
"uniform sampler2D texUnit;\n" +
"varying vec2 textureCoordinate" +
"void main(void)\n" +
"{\n" +
"const vec3 DotValue = vec3(0.299 , 0.587 , 0.114);\n" +
"vec2 texCoord = textureCoordinate;\n" +
"vec4 CurrentPixelData = texture2D(texUnit, texCoord);\n" +
"float temp = CurrentPixelData.x * DotValue.x + CurrentPixelData.y * DotValue.y + CurrentPixelData.z * DotValue.z;\n" +
"vec4 result = vec4(temp,temp,temp,CurrentPixelData.w);\n" +
"gl_FragColor = result;\n" +
"}\n";
It would be a lot easier for you if you start with a good openGL tutorial.
Good Luck!

Android - Change Texture of Bitmap GLES20 - Fragment Shader

I want to change a pixel color of the Bitmap with OpenGLES, by picking it with e.g. coordinates. What do I have to do? Any advices?
fragmentShader = riGraphicTools.loadShader(GLES20.GL_FRAGMENT_SHADER, riGraphicTools.test_Image);
riGraphicTools.sp_Image = GLES20.glCreateProgram();
GLES20.glAttachShader(riGraphicTools.sp_Image, fragmentShader);
public static final String test_Image =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
"}";
i don't think ES 2.0 supports writeable textures, so instead of modifying sp_image on the fly, just render to texture with an FBO and use that texture in place of your original sp_image.

Texture grayscale in libgdx

Is there a way to transform a libgdx's Texture to a grayscale image? So far I had duplicate the images that I want to grayscale and I did it manually, but I think it is not the best solution because my game is using more and more images and it uses a lot of disk space.
Thought I'd share this for anyone wanting to use some copy/paste code.
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class GrayscaleShader {
static String vertexShader = "attribute vec4 a_position;\n" +
"attribute vec4 a_color;\n" +
"attribute vec2 a_texCoord0;\n" +
"\n" +
"uniform mat4 u_projTrans;\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"\n" +
"void main() {\n" +
" v_color = a_color;\n" +
" v_texCoords = a_texCoord0;\n" +
" gl_Position = u_projTrans * a_position;\n" +
"}";
static String fragmentShader = "#ifdef GL_ES\n" +
" precision mediump float;\n" +
"#endif\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"uniform sampler2D u_texture;\n" +
"\n" +
"void main() {\n" +
" vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" +
" float grey = (c.r + c.g + c.b) / 3.0;\n" +
" gl_FragColor = vec4(grey, grey, grey, c.a);\n" +
"}";
public static ShaderProgram grayscaleShader = new ShaderProgram(vertexShader,
fragmentShader);
}
To use it call
spriteBatch.setShader(GrayscaleShader.grayscaleShader)
And when you're done with grayscale don't forget to call
spriteBatch.setShader(null);
You should be able to write a GLSL shader that renders a texture in grayscale. This requires OpenGL 2.x, and doesn't really "transform" a texture, but just renders it to the display as grayscale.
For a detailed tutorial on shaders that includes a grayscale shader check out: https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson3
(Libgdx doesn't really define the GLSL shader API, that's passed through from OpenGL, so most tutorials or code you find on the web for regular OpenGL should work.)
For a more direct hack, just take the Libgdx SpriteBatch shader and change the fragment shader so it averages the rgb components. (You can define your own ShaderProgram and provide it to a SpriteBatch to use.)
Change body of the fragment shader to something like this (untested, so may not compile):
+ " vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" //
+ " float grey = (c.r + c.g + c.b) / 3.0;\n" //
+ " gl_FragColor = vec4(grey, grey, grey, c.a);\n" //
You can load up textures as luminance only, or luminance and alpha in GLES (see glTexImage2D). In libgdx you can specify PixFormat.Intensity (luminance) or LuminanceAlpha (luminance and alpha) when instantiating the Texture. This will generate a grayscale texture.
You still need to have two textures (one color, one grayscale) loaded up, but they can use the same source, and the luminance only uses only 1 byte per pixel in memory.
A more efficient solution is to implement a shader as suggested by P.T., but is only available from GLES 2.

Strange OpenGL ES 2.0 bug on Galaxy Note 2

This vertex shader code works on every device except for the Galaxy Note 2.
gl_Position = uMVPMatrix * vPosition;
where if I reverse the matrix multiplication to:
gl_Position = vPosition * uMVPMatrix; I can actually get things to appear.
Unfortunately, the reverse would require me to completely rewrite my transformations library.
Does anyone have any insight on what could be causing this, is this an opengl driver error with the device?
Shader code
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
"v_TexCoordinate = a_TexCoordinate;" +
"gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" +
//" gl_FragColor = vec4(v_TexCoordinate, 0, 1);" +
"}";
This is not about only a galaxy note 2 platform.
This is a mathematical question. Because both glsl/hlsl uses column major order,
It is a right way to multiply MATRIX x VECTOR
or
you can transpose the matrix using a option in
glUniformMatrix4fv( h_Uniforms[UNIFORMS_PROJECTION], 1, GL_FALSE or GL_TRUE, g_proxtrans.s);
Apparently, It can be a problem not to call this function with the option ( GL_TRUE is to use transposing ) each every frame just try .

ETC1 compressed textures not working on Motorola Atrix

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.

Categories

Resources