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 .
Related
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;
}
This should really be a simple task, but I fail miserably. First a confession: I know very little about OpenGL and the few things I've learned come from various tutorials (some of which are probably outdated and deprecated)
I'm trying to draw a quad using a single color defined at runtime. The quad is drawn in the correct size and position but with the wrong color. This is my vertex and fragment shader:
public static final String VS_SOLIDCOLOR =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 aPosition;" +
"attribute vec4 aColor;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_Position = uMVPMatrix * aPosition;" +
" vColor = aColor;" +
"}";
public static final String FS_SOLIDCOLOR =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
The color is set like this (I have removed gl error check and check for colorHandle == -1):
float r = 1.0f;
float g = 0.0f;
float b = 0.0f;
float a = 1.0f;
final int colorHandle = GLES20.glGetAttribLocation(shaderProgramSolidColor, "aColor");
GLES20.glVertexAttrib4f(colorHandle, r, g, b, a);
I would have expected the above code to result in solid red triangles, but they end up as solid yellow. From what I've read the fragment shader will interpolate the vColor vector, but I don't want that (and I'm not sure why it ends up as yellow). How do I set a color at runtime and get that drawn unchanged on my triangles?
PS If I were to do this in the fragment shader I would get a solid red color for my entire quad:
gl_FragColor = vec4(1,0,0,1);
Let me know if you need me to post more code.
I found what I did wrong. I was under the impression that I could only set variables in the vertex shader at runtime, but it's possible to manipulate the fragment shader as well. My shader should look like this:
public static final String VS_SOLIDCOLOR =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 aPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * aPosition;" +
"}";
public static final String FS_SOLIDCOLOR =
"precision mediump float;" +
"uniform vec4 uColor;" +
"void main() {" +
" gl_FragColor = uColor;" +
"}";
And set like this:
final int colorHandle = GLES20.glGetUniformLocation(shaderProgramSolidColor, "uColor");
GLES20.glUniform4f(colorHandle, r, g, b, a);
I am doing yuv to rgb conversion using opengl shaders. But its only show green and pink colors. I am using ffmpeg to decode movie. I am beginner in this, so have no idea how to solve it. ffmpeg give me three buffers of yuv. I am directly assigning these buffers to three textures.
Here are shaders I am using.
static const char* VERTEX_SHADER =
"attribute vec4 vPosition; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 tc; \n"
"uniform mat4 u_mvpMat; \n"
"void main() \n"
"{ \n"
" gl_Position = u_mvpMat * vPosition; \n"
" tc = a_texCoord; \n"
"} \n";
static const char* YUV_FRAG_SHADER =
"#ifdef GL_ES \n"
"precision highp float; \n"
"#endif \n"
"varying vec2 tc; \n"
"uniform sampler2D TextureY; \n"
"uniform sampler2D TextureU; \n"
"uniform sampler2D TextureV; \n"
"uniform float imageWidth; \n"
"uniform float imageHeight; \n"
"void main(void) \n"
"{ \n"
"float nx, ny; \n"
"vec3 yuv; \n"
"vec3 rgb; \n"
"nx = tc.x; \n"
"ny = tc.y; \n"
"yuv.x = texture2D(TextureY, tc).r; \n"
"yuv.y = texture2D(TextureU, vec2(nx/2.0, ny/2.0)).r - 0.5; \n"
"yuv.z = texture2D(TextureV, vec2(nx/2.0, ny/2.0)).r - 0.5; \n"
// Using BT.709 which is the standard for HDTV
"rgb = mat3( 1, 1, 1, \n"
"0, -0.18732, 1.8556, \n"
"1.57481, -0.46813, 0)*yuv;\n"
// BT.601, which is the standard for SDTV is provided as a reference
//"rgb = mat3( 1, 1, 1, \n"
// "0, -0.34413, 1.772, \n"
// "1.402, -0.71414, 0) * yuv; \n"
"gl_FragColor = vec4(rgb, 1.0); \n"
"} \n";
Output:
What wrong am I doing? Please help me out with this.
Thank You.
UPDATE:
While debugging ffmpeg decoding, I found that ffmpeg decoder give PIX_FMT_YUV420P output format. Do I have to make some tweaks to get correct image colors?
I'm not sure about this transformation:
"rgb = mat3( 1, 1, 1, \n"
"0, -0.18732, 1.8556, \n"
"1.57481, -0.46813, 0)*yuv;\n"
In refreshing my memory on matrix * vector operations in GLSL using this page as reference, I think you either need to transpose the coefficient matrix, or move yuv to the front of the operation, i.e., yuv * mat3(...). Performing the operation as mat3(...) * yuv means:
r = y * 1 + u * 1 + v * 1
g = y * 0 + u * -0.18732 + v * 1.8556
b = y * 1.57481 + u * -0.46813 + v * 0
And these conversions are very incorrect.
As another reference, here's a small, complete, sample GLSL shader program that converts YUV -> RGB that may be of some guidance: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
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.