• Godot Help
  • Why are get_pixel and screen_texture returning different colors?

I'm trying to write a spatial shader that highlights any pixel with the same color as the last pixel the user clicked. In my C# script located on the map mesh, I locate the desired pixel, grab its color, and send it to the uniform on the shader:

[Export]
MeshInstance3D mapMesh; //reference set manually in map tscn
void SetPixelColor(Vector2 pixelCoord, Texture2D texture)
{
    Image mapImage = texture.GetImage(); //get and decompress image
    if (mapImage.IsCompressed())
    {
        mapImage.Decompress();
    }

    Color pixelColor = mapImage.GetPixel((int)pixelCoord.X, (int)pixelCoord.Y); //read color

    ShaderMaterial highlightMat = (ShaderMaterial)mapMesh.MaterialOverride.NextPass; //locate highlight shader and set uniform
    Vector3 colorVec = new Vector3(pixelColor.R, pixelColor.G, pixelColor.B);
    highlightMat.SetShaderParameter("colorToHighlight", colorVec);
}

Then in the shader, I check the uniform for each fragment and hide each pixel of the highlight texture that doesn't correspond to the desired color:

uniform vec3 colorToHighlight;
uniform sampler2D screen_texture : source_color;

void fragment() {
	vec3  texColor = textureLod(screen_texture, SCREEN_UV, 0.0).rgb;
	
	if (ColorMatch(texColor, colorToHighlight, 0.0001)){
		ALPHA = 1.0;
	} else{
		ALPHA = 0.0;
	}
}

This doesn't work, and I think the reason is because get_pixel is returning the wrong color. Here's an example output: the 4-color image on the left is the correct colors, it's what I get from both the raw image and from texColor. But if I click on the green quadrant and have my shader set every pixel to colourToHighlight, I get the much lighter shade of green on the right:

I'm obviously just getting started with godot, but I could really use help figuring out where to start debugging. My first thought was that the two images might have different color compression, but I verified that the raw image was imported as Lossless, and I'm not sure how to check what the shader's compression is.

  • xyz replied to this.

    Soshinshu How does that green color look if you assign this texture to a standard material albedo? What happens if you enable "force srgb" checkbox in material's albedo section?

      xyz If I click "force srgb" both the source color and the get_pixel result change. Without it clicked, get pixel returns an RGB of (44.3,99.6,69.4) (measured in Gimp) and the shader returns (12.5,52.9,17.3). With force sRGB enabled, their RGB is (40.4,99.2,67.1) and (22.7,94.9,45.1) respectively.

      By 'assign this texture to a standard material albedo', do you mean creating a standard material, then dragging the texture into the albedo slot? That's how I have it set up now- here's my current the material configuration. The base material is just the texture, and the NextPass has the shader stuff I quoted earlier:

      I would be happy to zip a tiny godot project with just this asset and the shader code if that would be helpful- I wouldn't be surprised if this whole thing is caused by a mistake somewhere in the basic asset setup.

      • xyz replied to this.

        Soshinshu I meant to assign this texture to a dummy albedo material and observe the difference between texture colors when you toggle force srgb checkbox. Is this difference comparable with the difference from your first post. If yes then the problem is in srgb vs linear color space. Shaders operate in liner space while your image is likely srgb. You'll have to convert one or another so they're in matching color spaces.

          xyz

          Thank you for the explanation! Forcing sRGB definitely changes the color, but the mismatch isn't the same as the get_pixel/fragment mismatch. Here's a screenshot: the grid on the left is in forced sRGB, the right is a dummy texture with nothing applied to it, and the smaller squares on the bottom are the color get_pixel returns.

          • xyz replied to this.

            Soshinshu Try converting so srgb in the shader anyway. You can get the conversion code by enabling forced srgb in the standard material and, convert that material to the shader material and look into that shader's code. There are couple of lines that do the conversion marked by a comment.

              xyz That looks a lot closer! It's still behaving oddly but I have more than enough to tinker with from here- thank you very much for your patient feedback and troubleshooting. 🙂