Shader texture function indices rounding

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By gmaps

I send a texture to my shader and try to access it’s pixels.

pixel_val = texture(map_info, vec2(projected_pos.x, projected_pos.z))

The indices are float numbers. How do I know which pixel I’m accessing? For example if I know that pixel (0,0) is black and (1, 0) is white. If I projected value is (0.5, 0) will it be black or white?

It appears in black

php-training | 2019-08-28 13:48

:bust_in_silhouette: Reply From: p7f

Shaders don’t work with pixels. Textures in shaders have x and y indices going from 0 to 1. In the shader, the function texture samples the color of the texture given some coordinates in that range. If you have a 10x10 image, your PIXELS in range from 0 to 1 should have a 0.1x0.1 size, but the shader will also sample “smaller” indices like (0.05; 0.05). The sample value will be calculated according to the interpolation method you chose (nearest, linear).

So, Returning to the example… if your image is 10x10, and you know that the pixel (0,0) is white, and the pixel (1,0) is black… then in the shader, the fragment in coordinates (0,0) should be white, and the fragment (0.1,0) corresponding to the seccond pixel, will be black, but the fragment between them (0.05,0) will also be sampled and will get a gray value (if linear interpolation is chosen).

Also, in your example, if the image is 10x10, the fragment at (0.5,0) will in fact be the pixel (5,0) of your image, so i can’t tell what color it will have given the first and second pixel.

IDK if i’m making myself clear… what are you trying to achieve? Perhaps i can give you more info.

Yes, I figured out that indices are between 0 and 1, I may have wrote the question a bit confusing. So I think I had the nearest neighbour interpolation because I had no gray values in between. So my question was about nearest neighbour, whteher (if I take your case) the values 0.025, 0.05, 0.075 in between two pixels would round up or down. I wanted to write bilinear interpolation. But if it’s possible to change the interpolation of the texture before it’s passed to shader, it might be even better (if it’s performant), as then I wouldn’t have to write the interpolation in shader.

So my use case is: I create an image texture from image, where I paint unit line of sight for fog of war, ones are visible locations, zeroes are fog, and I wanted to interpolate the borders in shader, because they are too edgy. The calculation of the FOW texture happens cca 4 times per second on a 512*512 texture, so performance is quite important.

gmaps | 2019-08-27 13:15

In godot, you can only change filter on/off and mipmaps on/off, that i think that are the equivalent to:

  • filter on/off → GL_LINEAR/GL_NEAREST

So if you want to change to linear interp, you should select the texture, go to the import tab and check filter checkbox.

Anyways, i think what you need for that purpose is in fact blur and change opacity of the texture near to transparency. So you could define a widht (or use the pixel size of the image) and make a mean between al fragments arround the actual fragment. then set opacity with the given result. you can also mean the colors so border gets blured in case opacity is 0 or 1… if you have a sample project to share, may be i can try to write the shader for you.

p7f | 2019-08-27 17:23

Thank you for your help, I realized I had all the flags set to 0, which makes the sampler use nearest neighbour. When I turned on filtering I got bilinear sampling, and the pixels in the middle really were grayscale. I also used the blur and everything works perfect.

gmaps | 2019-09-02 07:20

Glad to help!

p7f | 2019-09-04 13:03