ColorOP (difference) result is wrong

Godot Version

4.2.1

Question

i am trying to create a shader using IDmap in the visual shader, however, i’m running into a strange issue, which doesn’t make sense.
when using colorop(difference), the preview, and the final results doesn’t match.
what am i doing wrong?
i am inputting a texture2D, and colorconstant, and connecting directly into diffuse.
here is a comparison pic of photoshop original, and output from godot and photoshop using a (0.5 , 0.5 ,0.5) colour as the difference

1 Like

And you don’t post pictures or code? That’s gonna be a really tough one to crack, then.

1 Like

ah. well, i did some more testing. and it seems like basic subtraction in godot shader is broken.
e.g

1 Like

in other words, 1-0.5 = ~0.9 according to godot

1 Like

No, you’re using a spatial material. I am not sure why spatial materials do not render as you expect, but I believe they use a logarithmic lightness model.
image

1 Like

i found a workaround.
instead of using a color constant, i’m now inputting a texture2D of that color, and it finally works perfectly. i’m guessing it was some jank between SRGB->linear conversion.

1 Like

yeah, I mean, it’s not jank, it’s that you’re using a spatial shader, designed for 3D, with a calculation that would work on a canvas shader; it’s just different concepts you’re mixing up

1 Like

not sure how it isn’t jank when i’m literally unable to use color constants in 3d, and trying to use them has caused me a week of headache…

1 Like

What I mean is you’re trying to do the difference in a spatial shader, when you could just be doing this in the viewport shader which is a canvas shader which is the equivalent to photoshop in godot.

2 Likes

In shader code you can use the source_color hint for your color or texture uniform. It makes sure the texture or color values are converted to linear when necessary for output (spatial shader, and canvas shader when 2D HDR is enabled). If your texture is already linear then don’t use that flag. see here Shading language — Godot Engine (stable) documentation in English

In Visual Shaders you can set it for textures by picking Color instead of Data in the third input thingy. For colors it looks like using a color uniform with ColorParameter automatically adds the source_color flag so a value in there is already converted when necessary, but there doesn’t seem to be a way to automatically convert a ColorConstant node from sRGB to linear, so you can either use a uniform or do the math yourself to convert it, there is an input bool output_is_srgb that should help if you want your conversions to work in either case.

Doing the subtraction in sRGB space will give different results to linear space, so assuming the photoshop effect is simply difference in sRGB space and output_is_srgb is true, then you’ll actually want to convert from linear to sRGB before doing the difference and then back to linear for output. But I don’t know if that’s what photoshop is doing so you’ll have to figure that out.

Unfortunately it seems like the internal shader functions to convert between linear and srgb aren’t exposed but here’s what the conversions look like in the godot glsl source:

vec3 linear_to_srgb(vec3 color) {
	// If going to srgb, clamp from 0 to 1.
	color = clamp(color, vec3(0.0), vec3(1.0));
	const vec3 a = vec3(0.055f);
	return mix(
		(vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a,
		12.92f * color.rgb,
		lessThan(color.rgb, vec3(0.0031308f))
	);
}

vec3 srgb_to_linear(vec3 color) {
	return mix(
		pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)),
		color.rgb * (1.0 / 12.92),
		lessThan(color.rgb, vec3(0.04045))
	);
}

It’s a piecewise function not a straight power/logarithmic relation. This code is using mix instead of an if presumably because that’s nicer on the gpu since there’s no branching, the same should apply to doing this in visual shaders.

edit: formatted the shader code for slightly better readability

2 Likes

thanks for the in-depth solution. i might try using this instead of the hack i did.
unfortunately visual shader doesn’t seem to support functions in its expressions, so i’ll probably try and convert it to a text shader instead.

1 Like