0 votes

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?

in Engine by (713 points)

It appears in black

1 Answer

+2 votes
Best answer

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.

by (3,505 points)
selected by

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.

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

  • filter on/off -> GLLINEAR/GLNEAREST

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.

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.

Glad to help!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.