Why same fragment shader gives different results on different android phones? - android

I am trying to implement a blur filter with OpenGL ES 2.0 on Android.
Here is the code i am using:
varying highp vec2 fragTexCoord;
highp vec2 u_Scale;
uniform sampler2D s_texture;
highp vec2 gaussFilter[7];
uniform highp float radius;
highp vec4 boxVerBlur(){
gaussFilter[0] = vec2( -3.0,0.015625);
gaussFilter[1] = vec2(-2.0, 0.09375);
gaussFilter[2] = vec2(-1.0, 0.234375);
gaussFilter[3] = vec2(0.0, 0.3125);
gaussFilter[4] = vec2(1.0, 0.234375);
gaussFilter[5] = vec2(2.0, 0.09375);
gaussFilter[6] = vec2(3.0, 0.015625);
highp vec4 color = vec4(0,0,0,1);
u_Scale = vec2( 1.0/radius, 0 );
for( int i = 0; i < 7; i++ )
{
color += texture2D( s_texture, vec2(
fragTexCoord.x + gaussFilter[i].x*u_Scale.x,
fragTexCoord.y + gaussFilter[i].x*u_Scale.y )) * gaussFilter[i].y;
}
return color;
}
void main(void)
{
gl_FragColor = boxVerBlur();
}
On "Samsung Galaxy S" it works as expected. However when i run same app on "Samsung Galaxy Ace," it results a brighter texture without blur effect.
Result from Galaxy S:
Result from Galaxy ACE:

I'll assume that by gaussFilter1 and gaussFilter2 you meant gaussFilter[1] and gaussFilter[2].
The only problem with your code I noticed is that you are adding the alpha, try adding only the rgb:
color.rgb += texture2D( s_texture, vec2(
fragTexCoord.x + gaussFilter[i].x*u_Scale.x,
fragTexCoord.y + gaussFilter[i].x*u_Scale.y )).rgb * gaussFilter[i].y;
It shouldn't cause your problem, but imho it worth a try, and even if it don't solve the problem, you will be saving an unnecessary sum for each texture access.

Related

After call glLinkProgram the app freezes

UPDATED
I'm trying to draw texture with openGL ES3 and used instanced drawing for my drawing application. This is my vertex shader
#version 300 es
precision highp float;
uniform mat3 u_Matrix;
in vec2 Position;
in vec2 TexPosition;
struct Data {
vec2 pos;
vec2 scale;
uint color;
float rotation;
};
layout(std140) uniform InstanceData {
Data data[256];
};
out vec4 v_Color;
out vec2 v_TexPosition;
void main() {
vec2 endPos = Position * data[gl_InstanceID].scale;
if (data[gl_InstanceID].rotation != 0.0) {
float cos = cos(data[gl_InstanceID].rotation);
float sin = sin(data[gl_InstanceID].rotation);
endPos = vec2(endPos.x * cos - endPos.y * sin, endPos.x * sin +
endPos.y * cos) + data[gl_InstanceID].pos;
} else {
endPos = endPos + data[gl_InstanceID].pos;
}
uint fColor = data[gl_InstanceID].color;
v_Color.r = float((fColor & 0x00FF0000U) >> 16) / 255.0;
v_Color.g = float((fColor & 0x0000FF00U) >> 8) / 255.0;
v_Color.b = float(fColor & 0x000000FFU) / 255.0;
v_Color.a = float((fColor & 0xFF000000U) >> 24) / 255.0;
v_TexPosition = TexPosition;
gl_Position = vec4(u_Matrix * vec3(endPos, 1.0), 1.0);
}
and this is my fragment_shader
#version 300 es
precision highp float;
in vec2 v_TexPosition;
in vec4 v_Color;
uniform sampler2D u_Texture2D;
out vec4 fragColor;
void main() {
vec4 color = texture(u_Texture2D, v_TexPosition);
fragColor = vec4(v_Color.rgb, color.a * v_Color.a);
}
When I created the program, attached shaders and try to link to program, the app is freezes on line glLinkProgram. Shaders and program have normal id.
This work normal on some devices (sony xperia Z -android 5.0, smasung s7 edge android 7, nexus 5x - android 7, nexus 6p - android 7) but this doesn't work on other part of devices(motX- android 5.1, smasung s5 android 6.0). All devices have android version greater then 5.0, and in code I checked for opengl ES3 supporting.
Is there some reason for this? Is it from device(how to check it)? or did I did something wrong?
I'm passed data to instanceBuffer with this way :
instanceBuffer.putFloat(posX);
instanceBuffer.putFloat(posY);
instanceBuffer.putFloat(scaleX);
instanceBuffer.putFloat(scaleY);
instanceBuffer.putInt(colorARGB);
instanceBuffer.putFloat((float) Math.toRadians(rotate));
instanceBuffer.position(instanceBuffer.position() + 8);
used +8 offsets because struct data read elements with vec4 size (16byte)
When I write my struct only with one vec4 :
struct Data {
vec4 posAndScale;
};
and pass data:
instanceBuffer.putFloat(posX);
instanceBuffer.putFloat(posY);
instanceBuffer.putFloat(scaleX);
instanceBuffer.putFloat(scaleY);
This works on all devices,
But when I added one more vec4 :
struct Data {
vec4 posAndScale;
vec4 color;
};
and pass data
instanceBuffer.putFloat(posX);
instanceBuffer.putFloat(posY);
instanceBuffer.putFloat(scaleX);
instanceBuffer.putFloat(scaleY);
instanceBuffer.putFloat(color.r);
instanceBuffer.putFloat(color.g);
instanceBuffer.putFloat(color.b);
instanceBuffer.putFloat(color.a);
app not freezes but nothing happened when I try to draw. It's seems like on some devices std140 work with different way or like data not passed to shader when wrote struct with 2 vec4-s
Ok I found some solution. This work normally since opengl es versionl 3.1. I think 3.0 version doesn't support struct data which contains float or int element.
I experienced the same issue. The Nexus 7 (2013) was freezing when I called gllinkprogram(). I found that this only happened when I had 'if statements' in my shader. I was able to change both of my 'if statements' into 'conditional operators' and it worked.
E.g. (cond)? cond1:cond2

GLES20 - Fragment Shader with two float uniforms, works on some devices, only affects change in one in some others

The following is the GLSL Fragment Shader code I'm concerned about:
#extension GL_OES_EGL_image_external : require
precision lowp float;
varying highp vec2 v_TexCoordinate;
uniform samplerExternalOES u_Texture;
uniform float uParamValue1; // hue
uniform float uParamValue2; // hue of replacing color
const float delta = 0.1;
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);
vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main()
{
vec3 texel = texture2D(u_Texture, v_TexCoordinate).rgb;
vec3 texelHsv = rgb2hsv(texel);
if(!(abs(texelHsv.x - uParamValue1) < delta))
{
texel = vec3(dot(vec3(0.299, 0.587, 0.114), texel));
//texel = vec3(texture2D(inputImageTexture2, vec2(texel.r, .16666)).r);
}
else
{
texelHsv.x = uParamValue2;
texel = hsv2rgb(texelHsv);
}
gl_FragColor = vec4(texel, 1.0);
}
The value of uParamValue1 and uParamValue2 is changed via two seekbars.
When I checked the uniform locations of uParamValue1 and uParamValue2, they returned valid uniforms on both my Galaxy S6 and Xiaomi Mi 3W, 1 and 2 respectively.
However, when I move the slider that corresponds to uParamValue1, the shader doesn't seem to respond to the changes in Xiaomi Mi 3W, whereas in the Galaxy S6, it works fine.
Why is this, and how can I prevent it from happening?

Warp shader behaves itself differently on mobile and desktop

I try to implement warp shader (black hole). It works great on desktop, but it looks wrong on mobile devices. The problem is in its size. When I increase the size of black hole the warped edges disappear. If it has very small size it looks as I want. I am using LibGDX.
How it should look like (Desktop):
How it looks on mobile device with the same size:
When I decrease the size the warped edges appears:
Vertex shader:
attribute vec2 a_position;
void main()
{
gl_Position = vec4(a_position.xy, 0.0, 1.0);
}
Fragment shader:
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_texture;
uniform vec2 u_res;
uniform float u_size;
// Gravitational field at
// position pos, given a black hole
// of mass m at position center
// (ignoring G constant)
vec2 Fgrav(float m, vec2 center, vec2 pos)
{
vec2 dir = center - pos;
float distance = length(dir);
dir /= distance;
return dir * (m / (distance*distance));
}
void main(void)
{
vec2 texCoord = gl_FragCoord.xy / u_res.xy;
vec4 sceneColor;
vec2 blackHoleCenters = vec2(u_res.xy*.5);
vec2 netGrav = Fgrav( (50. - u_size) * 500., blackHoleCenters, gl_FragCoord.xy);
float netGravMag = length(netGrav);
if(netGravMag < 1.0)
{
texCoord = (gl_FragCoord.xy + netGrav*((50. - u_size) * 15.0))/u_res.xy;
}
else texCoord.xy=vec2(.5,.5);
sceneColor = texture2D(u_texture, texCoord);
gl_FragColor = sceneColor;
}
How to fix this issue? Thanks.
UPDATE:
That's how I get u_size parameter:
public float getDistance(Camera cam){
return (float) Math.sqrt(Math.pow(cam.position.x, 2) + Math.pow(cam.position.y, 2) + Math.pow(cam.position.z, 2));
}
public void render(Camera cam, Mesh quad) {
program.begin();
program.setUniformf(u_size, getDistance(cam));
...
Initializing of camera:
cam = new PerspectiveCamera(64, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0f, 0.0f, 30.0f);
cam.lookAt(0,0.0f,0);
cam.near = 0.1f;
cam.far = 450f;
cam.update();
So, the initial value of u_size is 30.

GLSL ES fragment shader produces very different results on different devices

I am developing a game for Android using OpenGL ES 2.0 and have a problem with a fragment shader for drawing stars in the background. I've got the following code:
precision mediump float;
varying vec2 transformed_position;
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
void main(void) {
float distance = 10.0;
float quantization_strength = 4.0;
vec3 background_color = vec3(0.09, 0.0, 0.288);
vec2 zero = vec2(0.0, 0.0);
vec2 distance_vec = vec2(distance, distance);
vec2 quantization_vec = vec2(quantization_strength, quantization_strength);
vec2 new_vec = floor(transformed_position / quantization_vec) * quantization_vec;
if(all(equal(mod(new_vec, distance_vec), zero))) {
float rand_val = rand(new_vec);
vec3 current_color = background_color * (1.0 + rand_val);
gl_FragColor = vec4(current_color.x, current_color.y, current_color.z, 1.0);
} else {
gl_FragColor = vec4(background_color.x, background_color.y, background_color.z, 1.0 );
}
}
My aim is to 'quantize' the fragment coordinates, so 'stars' are not 1px in size, and then light up quantized pixels that are distant enough by a random amount. This code, however, produces different results depending on where it is executed. I have used GLSL Sandbox (http://glsl.heroku.com), Nexus 7 and HTC Desire S to create comparison:
As you can see, GLSL Sandbox produces dense grid with many stars visible. On Nexus 7 stars are much fewer and distributed along lines (which may be not obvious on this small image) - the rand function does not work as expected. Desire S draws no stars at all.
Why does the rand function work so strangely on Nexus 7 (if I modify the vector used for dot product, stars are distributed along lines at different angle)? And what might cause Desire S not to render the stars?
I would also appreciate any optimization tips for this shader, as I am very inexperienced with GLSL. Or perhaps there is better way to draw 'stars' via fragment shader?
UPDATE
I changed the code to this (I used http://glsl.heroku.com/e#9364.0 as reference):
precision mediump float;
varying highp vec2 transformed_position;
highp float rand(vec2 co) {
highp float a = 1e3;
highp float b = 1e-3;
highp float c = 1e5;
return fract(sin((co.x+co.y*a)*b)*c);
}
void main(void) {
float size = 15.0;
float prob = 0.97;
lowp vec3 background_color = vec3(0.09, 0.0, 0.288);
highp vec2 world_pos = transformed_position;
vec2 pos = floor(1.0 / size * world_pos);
float color = 0.0;
highp float starValue = rand(pos);
if(starValue > prob) {
vec2 center = size * pos + vec2(size, size) * 0.5;
float xy_dist = abs(world_pos.x - center.x) * abs(world_pos.y - center.y) / 5.0;
color = 0.6 - distance(world_pos, center) / (0.5 * size) * xy_dist;
}
if(starValue < prob || color < 0.0) {
gl_FragColor = vec4(background_color, 1.0);
} else {
float starIntensity = fract(100.0 * starValue);
gl_FragColor = vec4(background_color * (1.0 + color * 3.0 * starIntensity), 1.0);
}
}
Desire S now gives me very nice, uniformly distributed stars. But the problem with Nexus 7 is still there. With prob = 0.97, no stars are displayed, and with very low prob = 0.01, they appear very sparsely placed along horizontal lines. Why does Tegra 3 behave so strangely?

shader producing wrong results on tablets

ive only been working with shaders for a few days and have written a simple edge detection shader that adds a drop shadow and an inner shadow. It works great on my galaxy s2 and iphone 4, but the galaxy tab and ipad2 produce only a very thin and rough looking shadow on both sides of the edge. Ive spent hours trying to figure out why but had no joy, please help! If i simulate an ipad2 resolution in the simulator, the effect is correct.
The shader works on the same size off screen buffer on all devices (640x480 pixels).
vertex shader:
{
attribute highp vec4 inVert; //vertex stream
uniform highp mat4 inPMVMat; //transform to projected space
attribute mediump vec2 inUV0;
attribute lowp vec4 inCol;
uniform mediump vec2 inUVOffset;
uniform mediump vec2 inUVScale;
varying mediump vec2 vTexCoord;
varying mediump float FragColor;
void main(void)
{
gl_Position = inPMVMat * inVert;//set vertex position in projected space
vTexCoord = inUV0*inUVScale;// + inUVOffset;//pass texture to fragment shader
FragColor = inCol.a;
}
}
fragment shader:
{
uniform sampler2D myTexture;
varying mediump vec2 vTexCoord;
varying mediump float FragColor;
lowp float MaxDistance, Distance;
lowp float Shift;
void main(void)
{
gl_FragColor = texture2D(myTexture, vTexCoord);
mediump vec2 PixelSize = vec2(1.0 / 640.0, 1.0 / 480.0);
mediump vec2 Direction = vec2(PixelSize.x*0.5,PixelSize.y*0.5);
if(gl_FragColor.a >= 0.5)
{
//inner shadow
MaxDistance = 15.0;
} else {
//drop shadow
MaxDistance = 12.0;
Direction = -Direction;
}
mediump vec2 Position = vTexCoord;
mediump float c;
for(Distance = MaxDistance; Distance > 0.0;Distance -= 1.0)
{
Position += Direction;
c = texture2D(myTexture,Position).a;
if(c < 0.5)
{
if(gl_FragColor.a >= 0.5)
{
//found transparent edge - do inner shadow
Shift = 1.0-((0.5/MaxDistance)*Distance);
gl_FragColor.r *= Shift;
gl_FragColor.g *= Shift;
gl_FragColor.b *= Shift;
break;
}
} else {
if(gl_FragColor.a < 0.5)
{
//found opaque edge - do dropshadow
gl_FragColor.a = ((0.8/MaxDistance)*Distance);
break;
}
}
}
gl_FragColor.a *= FragColor;
}
}
images:
I eventually found the solution to this after a lot of experimenting.
The lowp MaxDistance, Distance and Shift variables were the culprits - it works fine after on all devices after changing to mediump. I guess there is some variation in precision between devices

Categories

Resources