Is glsl step function continuous?

I’ve tried to write custom shader with sophisticated texture coordinates processing implementing some kind of texture atlas. I encountered very strange kind of error. glsl step function (built-in as well as manually wrote one via if statement) gives artefacts and seem to be discontinuous.

Here is the screenshot:http://rghost.ru/37964789.view

Here is all souece files packed in one archive: http://rghost.ru/37964811



Standart vertex shader:


uniform mat4 g_WorldViewProjectionMatrix;
uniform mat4 g_WorldViewMatrix;
uniform mat3 g_NormalMatrix;
uniform mat4 g_ViewMatrix;

uniform vec4 g_LightColor;
uniform vec4 g_LightPosition;
uniform vec4 g_AmbientLightColor;

varying vec2 texCoord;

attribute vec3 inPosition;
attribute vec2 inTexCoord;
attribute vec3 inNormal;

varying vec3 vLightDir;
varying vec3 wvNormal;

void lightComputeDir(in vec3 worldPos, in vec4 color, in vec3 position, out vec3 lightDir) {
float posLight = step(0.5, color.w);
vec3 tempVec = position * sign(posLight - 0.5) - (worldPos * posLight);
lightDir = normalize(tempVec);
}

void main() {
// Vertex transformation
vec4 pos = vec4(inPosition, 1.0);
gl_Position = g_WorldViewProjectionMatrix * pos;
texCoord = inTexCoord;

// direction transformations
vec3 wvPosition = (g_WorldViewMatrix * pos).xyz;
vec4 tmp_wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz, clamp(g_LightColor.w,0.0,1.0 )) );
lightComputeDir(wvPosition, g_LightColor, tmp_wvLightPos.xyz, vLightDir );

wvNormal = normalize(g_NormalMatrix * inNormal);
}


Custom frag shader, step function used unnatural to show effect

varying vec2 texCoord;

uniform vec4 g_LightDirection;
varying vec3 vLightDir;
varying vec3 wvNormal;

uniform sampler2D m_BaseTex;

float lightComputeDiffuse(in vec3 norm, in vec3 lightdir) {
return max(0.0, dot(norm, lightdir));
}

void main() {
vec2 realCoord = texCoord;
realCoord = step(0.6,realCoord)*realCoord;
vec4 data = texture2D(m_BaseTex, realCoord);

float spotFallOff=1.0;
if (g_LightDirection.w != 0.0) {
vec3 L = normalize(vLightDir);
vec3 spotDir = normalize(g_LightDirection.xyz);
float curAngleCos = dot(-L, spotDir);
float innerAngleCos = floor(g_LightDirection.w) * 0.001;
float outerAngleCos = fract(g_LightDirection.w);
float subInnerOuter = innerAngleCos - outerAngleCos;
spotFallOff = (curAngleCos - outerAngleCos) / subInnerOuter;
if (spotFallOff <= 0.0) {
gl_FragColor.rgb = vec3(0.0);
gl_FragColor.a = 1.0;
return;
} else {
spotFallOff = clamp(spotFallOff, 0.0, 1.0);
}
}
spotFallOff = clamp(spotFallOff, step(g_LightDirection.w, 0.001), 1.0);

vec3 lightdir = normalize(vLightDir);
vec3 normal = normalize(wvNormal);

gl_FragColor.a = 1.0;
gl_FragColor.rgb = data.rgb * lightComputeDiffuse(normal, lightdir) * spotFallOff;
}


I'm using nvidia card on ubuntu GNU/Linux. Is this behaviour standard or depend on OS and video card? I'm very confused with it and don't know what to do with such artefacts. All methods leads to the same result: step function, if statement, clamp function. I'm doubt if a workaround ever exist.

Might be a bug in the Linux drivers implementation. Have you tried it on a different platform?

Not yet.

What does your geometry look like?



I can assure you the step function is just fine and that it must be something else.



Edit: actually there is other math going on that could be leading to this also. My recommendation is to create a simple unshaded material with a step function on texture coordinate on a quad.

Geometry is a plane. All needed files are in the archive (second link on the topic)

Do you try to run the shader code on your computer?

@ayvango said:
Do you try to run the shader code on your computer?


I will let you trouble-shoot your own code. I use the step function all the time without issue. See my edit above.

For example, it could be the clamp that surrounds the step that is causing this if spot fall off is weird.

I’ve simplified example as much as possible. I’ve tried to comment diffuse light calculations, the error remains.

I may publish other code variants with manual if functions and so on. All their have same appearance.



edit: to summarize I’ve tested different version of code for about 4 hours. I’m confused and interested in community experience, have anyone challenged same errors before?

If you want to test the step function then you are still doing way too much.



A quad using a shader with something as simple as:

gl_FragColor.r = step( texCoord.x, 0.1 );



Would be enough to prove step works fine and then you can start debugging the problem in your math.

@ayvango said:
I may publish other code variants with manual if functions and so on. All their have same appearance.


Yeah, that's because step() is doing exactly what your if statements do... and step works fine. The error is in your math somewhere.

I’ve print debug output to colour values already, (rg components, r only component for x only). The color jumps around step remains.

Actually, if m_BaseTex is a mip-mapped texture then you might just be getting bleed when the texture coordinates wrap… if they wrap.

vec4 data = texture2D(m_BaseTex, realCoord);

@ayvango said:
I've print debug output to colour values already, (rg components, r only component for x only). The color jumps around step remains.


Your test is still flawed, then. step() works fine.

If when debugging you are still doing a texture lookup instead of setting the color directly like I did in my test then you are still making too many assumptions. Set the frag color directly from the result of step, not a texture lookup.

I’ve set rg components directly, overwriting ones that I got from texture lookup.

data.rg = realCoord

There was jumping around step values. It was harder to notice, but It was.

Paste the latest test code.

@ayvango said:
There was jumping around step values. It was harder to notice, but It was.

Listen, you are doing yourself no favor not believing him and I guess at the same time get on his nerves big time. step() is the most basic loop function and used on about all of jme's shaders. It does work! The problem is in your code!
@normen said:
Listen, you are doing yourself no favor not believing him and I guess at the same time get on his nerves big time. step() is the most basic loop function and used on about all of jme's shaders. It does work! The problem is in your code!


...or in understanding.

To the original poster, post your super-simplified test shader and the output you see.

@ayvango Do yourself a favor and try it; keep an open mind. At best you prove @pspeed wrong, at worse you found a bug in step() nobody ever encountered.

The pure step function code is Ok. (where data.rg=realCoords,data.b=0). If ommited data.b the color jumps as expected. So the main problem is texture2D, not step.

Is there some kind of optimizations?

Look up mip-mapping and filtering and read all about it. I suspect that near the texture edge you are seeing bleeding from the other edge because of mip-mapping/filtering.