• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders Shader working differently on different hardware

Filkata

Member
upload_2019-8-19_21-0-17.png
I have made a relatively simple fog of war shader as in the above pic. I have created a texture the size of the screen filled with black and draw it as a sprite that moves with the camera. In a pixel shader I check the distance to the player (the ship) and determine the alpha of the pixel to create a transparent circle. Maybe there is a better way to do it and I would appreciate the tips on that but that is not the main point of the topic.

The issue is that on my PC it works perfectly, but it is wrong on my sister's laptop. There the circle is an elipse, it is bigger than it is supposed to and "lags behind" the player to the top and left more and more as you move to the bottom and the right of the screen. My first thought was it must be the resolution - but it works fine on all resolutions on my PC and on none of the ones I tested on her laptop.

The circle (inner one, as there is a second semi-transparent one) should be 290px in diameter, whereas it was approx 390x440px at 1366x768 resolution on her PC. This means 1:1 scaling, as I am using the resolution handling system from Pixelated Pope's tutorial.

This is the shader itself:

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec2 u_vCenter;
uniform float u_radius;
uniform vec2 u_vResoultion;
uniform vec4 u_vUVs;

void main()
{
    float alpha = 1.0;
    float texX = (v_vTexcoord.x - u_vUVs.x) / u_vUVs.z * u_vResoultion.x;
    float texY = (v_vTexcoord.y - u_vUVs.y) / u_vUVs.w * u_vResoultion.y;
    float margin = u_radius * 0.45;
    float dist = distance(vec2(texX, texY), u_vCenter);
    if (dist < u_radius)
    {
        alpha = 0.0;
    }
    else if (dist <= u_radius + margin)
    {
        alpha = 0.35 + sin((dist - u_radius) / margin * 1.57);
    }
    gl_FragColor = vec4(v_vColour.r, v_vColour.g, v_vColour.b, alpha) * texture2D( gm_BaseTexture, v_vTexcoord );
}
One thing I have noticed is that x & y are 0 on the problematic machine and y & z are 1 (of the UVs).

I have double checked the resolution, viewports and coordinated of the circle passed and I am stuck, I need some ideas on what the issue might be/how to debug it. The only method I know of debugging shaders is using the output color to convey info which is rather cumbersome.

My current theory is that the issue might be because the laptop has an integrated Intel graphics card, could this possibly cause the issue? Both computers I tested on use Windows 10. If you would like to help me test this possibility and you have a machine with an integrated graphics card, please check the below files (source and exe). Use the arrow keys to move the ship around and see if the fog of war circle follows it correctly or not.

Source
Windows executable

Many thanks in advance!
 

DBenji

Member
View attachment 26279
I have made a relatively simple fog of war shader as in the above pic. I have created a texture the size of the screen filled with black and draw it as a sprite that moves with the camera. In a pixel shader I check the distance to the player (the ship) and determine the alpha of the pixel to create a transparent circle. Maybe there is a better way to do it and I would appreciate the tips on that but that is not the main point of the topic.

The issue is that on my PC it works perfectly, but it is wrong on my sister's laptop. There the circle is an elipse, it is bigger than it is supposed to and "lags behind" the player to the top and left more and more as you move to the bottom and the right of the screen. My first thought was it must be the resolution - but it works fine on all resolutions on my PC and on none of the ones I tested on her laptop.

The circle (inner one, as there is a second semi-transparent one) should be 290px in diameter, whereas it was approx 390x440px at 1366x768 resolution on her PC. This means 1:1 scaling, as I am using the resolution handling system from Pixelated Pope's tutorial.

This is the shader itself:

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec2 u_vCenter;
uniform float u_radius;
uniform vec2 u_vResoultion;
uniform vec4 u_vUVs;

void main()
{
    float alpha = 1.0;
    float texX = (v_vTexcoord.x - u_vUVs.x) / u_vUVs.z * u_vResoultion.x;
    float texY = (v_vTexcoord.y - u_vUVs.y) / u_vUVs.w * u_vResoultion.y;
    float margin = u_radius * 0.45;
    float dist = distance(vec2(texX, texY), u_vCenter);
    if (dist < u_radius)
    {
        alpha = 0.0;
    }
    else if (dist <= u_radius + margin)
    {
        alpha = 0.35 + sin((dist - u_radius) / margin * 1.57);
    }
    gl_FragColor = vec4(v_vColour.r, v_vColour.g, v_vColour.b, alpha) * texture2D( gm_BaseTexture, v_vTexcoord );
}
One thing I have noticed is that x & y are 0 on the problematic machine and y & z are 1 (of the UVs).

I have double checked the resolution, viewports and coordinated of the circle passed and I am stuck, I need some ideas on what the issue might be/how to debug it. The only method I know of debugging shaders is using the output color to convey info which is rather cumbersome.

My current theory is that the issue might be because the laptop has an integrated Intel graphics card, could this possibly cause the issue? Both computers I tested on use Windows 10. If you would like to help me test this possibility and you have a machine with an integrated graphics card, please check the below files (source and exe). Use the arrow keys to move the ship around and see if the fog of war circle follows it correctly or not.

Source
Windows executable

Many thanks in advance!
Hey FIlkata, can you try changing the shader to output uvs instead and tell me if the resulting image you see is different on your sister's laptop? They should appear different if the problem is indeed with different uvs. I doubt it will be any different, but I'm just curious.

If not then the problem is likely with the code you are using to pass in the uniforms -> u_vResolution or u_vUVs.zw... I tested your shader and the only way you can get an oval/elipse shape is if u_vResolution does not match the real image aspect ratio or u_vUVs.z is not equal to u_vUVs.w.

I'm not familiar with PixelatedPope's resolution management video, but I would suggest you hijack whatever you're inputting as u_vResolution to directly reflect the correct aspect ratio or make the other two uniform values equal to one another.
 
Last edited:

Ido-f

Member
I agree that the u_vResolution is the main suspect here.
I'll add that I've noticed that display_get_gui_width and display_get_gui_height return outright wrong results on my macbook air: the width and height of the screen, instead of the game's gui layer.
I replaced those functions with surface_get_width(application_surface) to get the correct gui dimensions when there are black bars.

Anyways, besides the point, you might want to consider replacing:
Code:
 if (dist < u_radius)
    {
        alpha = 0.0;
    }
    else if (dist <= u_radius + margin)
    {
        alpha = 0.35 + sin((dist - u_radius) / margin * 1.57);
    }
with:
Code:
alpha = smoothstep(u_radius, u_radius+margin, dist);
that would result in alpha 0 when dist is below u_radius, alpha 1 when dist is above u_radius+margin, and a smooth transition from 0 to 1 in between them.
It would also be more shader friendly, as it's best to avoid condition statements in shaders (as it obstructs with its parallel execution method),
and, when possible, use built in glsl functions, as those often have hardware optimisations.
 
Last edited:

DBenji

Member
I agree that the u_vResolution is the main suspect here.
I'll add that I've noticed that display_get_gui_width and display_get_gui_height return outright wrong results on my macbook air: the width and height of the screen, instead of the game's gui layer.
I replaced those functions with surface_get_width(application_surface) to get the correct gui dimensions when there are black bars.
Useful to know. Are you getting the same result on gms2 by any chance? I would request you to file a bug if that's the case.
 

Filkata

Member
@DBenji the colors of the v_vTexcoord came out exactly the same. And I am pretty sure u_vUVs.z and w are both 1, could it possibly be anything else?
 

DBenji

Member
Well then it has to be with whatever the code you got from the tutorial and inputting as uniforms. I would recommend before you consider other possible causes (I can't see any at this point), store whatever you are putting into "shader_set_uniform_f" for u_vUVs and u_vResolution in variables and either use the debugger to see what their values are or use draw_text(x, y, string(var)) in the gui event to show their values on screen. Please also report back as I'm curious if your theory about it being a graphics card bug is correct.
 

Filkata

Member
I am pretty sure the uniform values I am sending the shader are correct, but I will double-check next time I have access to that machine.
Is there a way to save a texture to a file, so I could rule out it is the viewport perhaps?
 

Filkata

Member
@DBenji I have checked that what is drawn on the surface is already streched, but I double checked all the values and did not get any new ideas in several hours, so I ended up using blend modes instead to recreate the effect, it now works on both machines.
Still it would be good to know what might have caused the issue, this will put me off from using texture coordinates in shaders in games I plan on releasing for now :(
 
Top