Splatmap GLSL shader too bright

Hello,

I have a splatmap GLSL shader applied to a terrain that has 4 textures: splatmap, grass, sand and rock/moss. The shader works but is somehow too bright.

#version 150

uniform sampler2D p3d_Texture0;
uniform sampler2D p3d_Texture1;
uniform sampler2D p3d_Texture2;
uniform sampler2D p3d_Texture3;

float tex1_resolution = 16;
float tex2_resolution = 16;
float tex3_resolution = 16;

// Input from vertex shader
in vec2 texcoord;

// Output to the screen
out vec4 p3d_FragColor;

void main() {
    
    float mix1 = texture(p3d_Texture0, texcoord).r;
    float mix2 = texture(p3d_Texture0, texcoord).g;
    float mix3 = texture(p3d_Texture0, texcoord).b;

    vec4 color1 = texture(p3d_Texture1, texcoord * tex1_resolution).rgba * mix1;
    vec4 color2 = texture(p3d_Texture2, texcoord * tex2_resolution).rgba * mix2;
    vec4 color3 = texture(p3d_Texture3, texcoord * tex3_resolution).rgba * mix3;

    p3d_FragColor = color1 + color2 + color3;
}

I don’t know GLSL and I just adapted a Godot splatmap shader to GLSL. I had the same problem in Godot that was solved by a Godot-specific keyword that, presumably, converted sRGB to linear color space. I researched how to make that conversion in GLSL but didn’t find anything or didn’t understand.

I wasn’t sure if asking here or on shaders related forums.
If anyone knows how to solve the issue I will appreciate the help.
Thank you!

Edited:
To avoid this problem, images should be saved in linear RGB color space.

What do you mean by RGB model? You mean when exporting the image? I checked the images and they say “Color Space: RGB Color” and “Color Profile: Gimp’s built-in sRGB”. So I don’t know.

Try this option to convert to linear space.
https://docs.gimp.org/en/gimp-image-precision.html

The texture is probably marked as having the sRGB color space, this is not correct for a splat map, you can change it like so:

texture.set_format(Texture.F_rgb)

Use F_rgba if the texture has an alpha channel.

I think this is unlikely to be the problem, but you probably also want to cap the alpha value of the output to 1:

p3d_FragColor.a = 1.0;

It took me a while… Thank you guys for your suggestions! I converted the splatmap image to RGB linear light in Gimp like @serega-kkz pointed out. It works, it’s perfect, thank you!

I also tried the GLSL method of @rdb but I got a blueish terrain and some errors about the shader in the terminal. I would like to understand this method too. This is what I typed but clearly I got it wrong.

// I tried this
texture.set_format(p3d_Texture0.F_rgba)
// then this
p3d_Texture0.set_format(p3d_Texture0.F_rgba)
// and then this
p3d_Texture0.set_format(Texture.F_rgba)

I don’t know how to properly write GLSL code and I couldn’t find any api or something with that method. Do you have other suggestions please?

That is not GLSL, that’s meant to be Python code.

The method you have applied does work, but it crushes the quality of the splat map just a little bit. Better to just set the format properly in the code. Though, for a splat map the fidelity doesn’t matter that much, so you could just leave it as-is.

I disagree with the position of rdb, maps that store data for calculations should be stored in linear space. The maps that are displayed on the screen can be stored in a non-linear space, these are usually base color and emission. However, this is not necessary in the context of shading, since you are not deprived of the opportunity to perform gamma correction in the shader.

I also disagree with the statement about the loss of accuracy, because in fact the range of color values does not change, only the pixel value changes taking into account the curve, and the range remains unchanged from 0 to 1.

They are stored in linear space, but you need to tell Panda that. Because if you export from Blender, using panda3d-gltf or blend2bam, then they are marked as “sRGB” by default, which means that linearization happens when the texture is being sampled, which you don’t want.

I think this is true only if the textures were embedded. If there were only embedded links to them, then this will have no effect when loading.

It’s getting a little complicated. So, correct me if I’m wrong, the possible solutions are three:

1 - Save the splatmap image in linear space (what I’ve done and it worked).
2 - Set the format from Python with Texture.F_rgb (I couldn’t get findTexture() to work).
3 - Correct the gamma from the shader itself (I tried some code from the link but I always get errors).

Then one must know, based on the exporter in use, how are their textures exported.
Right?

No, the reference to the texture still contains the format.

Yes, option 2 is what I suggested, but if you’re happy with option 1, that is fine as well. There’s no reason to use option 3, it’s just a much less efficient way to do what is already happening.

I had to do a lot of tests, and you’re right. Now I have to figure out what I did wrong earlier, I’m writing my exporter, I couldn’t save the format, it was completely redefined when loading the model.