Error in Compiling Fragment Shader Program in OpenGL es , Android - 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!

Related

Alternative for glBlitFrameBuffer() in OpenGL ES 2.0

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.

How to implement simple 2D translation on OpenGL ES 2.0 using OpenTK for android

I am trying to add the translation to a simple example of drawing a triangle using OpenGL ES 2.0 for Android. I have created translation matrix with 0 translation in all directions which should be the identity matrix. When I remove the multiplication from vertex shader triangle renders fine. However when I try to add some transformation(even identity) nothing is rendered. I think it is something about sending matrix data to the shader. GL.UniformMatrix 4 only takes float as attributes and I cant convert Matrix4 to float array. At the end I desperately created float array for identity matrix and passed it using GL.UniformMAtrix4 however nothing is rendered again.
Can anyone with the experience help me out please.
Matrix4 uvMat = Matrix4.CreateTranslation(0.0f,0.0f,0.0f);
// Vertex and fragment shaders
string vertexShaderSrc = "attribute vec4 vPosition; \n" +
"uniform mat4 uvMat; \n" +
"void main() \n" +
"{ \n" +
" gl_Position = uvMat*vPosition; \n" +
"} \n";
string fragmentShaderSrc = "precision mediump float;\n" +
"void main() \n" +
"{ \n" +
" gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0); \n" +
"} \n";
int vertexShader = LoadShader (All.VertexShader, vertexShaderSrc );
int fragmentShader = LoadShader (All.FragmentShader, fragmentShaderSrc );
program = GL.CreateProgram();
if (program == 0)
throw new InvalidOperationException ("Unable to create program");
GL.AttachShader (program, vertexShader);
GL.AttachShader (program, fragmentShader);
GL.BindAttribLocation (program, 0, "vPosition");
GL.LinkProgram (program);
float[] matTrans = new float[] {1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1};
int uniMatLoc = GL.GetUniformLocation (program, "uvMat");
Console.WriteLine (uniMatLoc.ToString());
GL.UniformMatrix4 (uniMatLoc, 16, false, matTrans);
The second argument to UniformMatrix4 is the number of matrices, not the number of elements in the matrix. So the call should be:
GL.UniformMatrix4(uniMatLoc, 1, false, matTrans);

libgdx - shader ignores blending/alpha in first frame

I'm rendering a libgdx mesh using shader with alpha color less than 1.0.
When rendering the first frame, the alpha value set in shader is being ignored and rendered as 1.0. All following rendering frames are fine.
The same happened to me in previous project drawing lines and shapes using glDrawArrays and I haven't found the solution yet.
Code in libgdx render() loop:
Gdx.gl20.glClearColor(0, 0, 0, 1);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_BLEND);
MeshManager_colorFill.meshShader.begin();
MeshManager_colorFill.meshShader.setUniformMatrix("u_worldView", Snappr.camMatrix);
meshArray_colorFill.render(MeshManager_colorFill.meshShader, GL20.GL_TRIANGLE_FAN, 0, meshArray_colorFill.get(i).getNumVertices());
MeshManager_colorFill.meshShader.end();
Gdx.gl20.glDisable(GL20.GL_BLEND);
My shader (compiled in create(){}):
public static final String meshVertexShader_colorFill =
"attribute vec2 a_position; \n" +
"uniform mat4 u_worldView;\n" +
"void main() \n" +
"{ \n" +
" gl_Position = u_worldView * vec4(a_position.xy, 0, 1); \n" +
"} \n" ;
public static final String meshFragmentShader_colorFill =
"precision mediump float;\n" +
"void main() \n" +
"{ \n" +
" gl_FragColor = vec4(1,1,1,0.2);\n" +
"}";
How do I render the very first frame as it should be?
Thanks
glBlendFunc in create() does the trick, specifically: "Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, L20.GL_ONE_MINUS_SRC_ALPHA);" I'm using SpriteBatch to render a font, right after the mesh. glBlendFunc is contained internally within the SpriteBatch, looks like that's why all the other frames were fine.
I found that ModelBatch.begin(...) will disable Blending by calling Gdx.gl.glDisable(GL20.GL_BLEND). So make sure to enable blending AFTER calling ModelBatch.begin().
modelBatch.begin(camera); // resets Blending to false
// enable Blending
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
// draw mesh
mesh.render(shader, GL20.GL_TRIANGLES);
modelBatch.end();
Source https://stackoverflow.com/a/66820414/2413469

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 .

Categories

Resources