Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextureAtlas doesn't work in shader when passed as sampler2D #25895

Open
Shadowblitz16 opened this issue Feb 15, 2019 · 11 comments
Open

TextureAtlas doesn't work in shader when passed as sampler2D #25895

Shadowblitz16 opened this issue Feb 15, 2019 · 11 comments

Comments

@Shadowblitz16
Copy link

Shadowblitz16 commented Feb 15, 2019

Godot version: 3.0.6

Window 7 Home 64 bit

passed a texture atlas to a shader for palette swapping it seems like the shader ignores the texture atlas crop.

  • make a shader material
  • copy the shader code below and paste it as your shader code
  • copy the palette image to your project
  • create two texture atlases 1 with a rect of 0,0,4,1 and 1 with a rect of 0,1,4,1
  • pass these texture atlases as parameters to the shader.
  • see that the shader does not update the color.

if you use separate images it works.

shader_type canvas_item;

uniform sampler2D palette_old; //the color to test against
uniform sampler2D palette_new; //the target color
uniform float     threshold; 

//get the texture color
void fragment()
{
	vec4  texture_col  = texture    (TEXTURE,     UV);
	int   palette_size = textureSize(palette_old,  0).x;
	
	for (int i = 0; i < 4; i ++)
	{
		vec4 palette_col_old = texelFetch(palette_old, ivec2(i, 0), 0);
		vec4 palette_col_new = texelFetch(palette_new, ivec2(i, 0), 0);
		if (distance(texture_col.rgb, palette_col_old.rgb) < threshold) 
		{
		    texture_col.rgb = palette_col_new.rgb; break;
		}
	}
	COLOR = texture_col;
}

pal8 <-- palette

@ghost
Copy link

ghost commented Feb 15, 2019

Might be related to this: #25049

@arkology
Copy link
Contributor

Have the same problem. I had asked several times in Discord about it, no answer. So I had to cut my texture atlas on ~200 separated textures, and this is awful

@Zylann
Copy link
Contributor

Zylann commented Feb 15, 2019

What is a "texture atlas"? Do you mean you passed an AtlasTexture? Do you have an example project?

I'm quite skeptical as to how shaders are currently supposed to adjust sampling coordinates for AtlasTextures, because those textures are not actually textures, but just a region with a reference to an actual texture. They work in simple use cases because the draw_texture function adjusts the UVs when drawing, and if you use those UVs to sample the texture then it's all fine in the end. However, in the shader language, the sampler2D type stands for an actual texture, and doesn't have any clue about the region. So when you assign an AtlasTexture as parameter for a shader to do something ELSE, the region information is not available, because it would need another uniform, all you get is the texture used by the AtlasTexture.

@Shadowblitz16
Copy link
Author

shouldn't it crop it before passing it to the shader?
or at least not allow texture types to be passed?

I prefer the the first since it makes godot more flexible.

@Zylann
Copy link
Contributor

Zylann commented Feb 16, 2019

The problem with baking region into the sampling operation under the hood, is that it will break the common use case. As I explained, when you draw an AtlasTexture, the region information is actually used to change the UV parameter, which ends up with the correct result if your use case is to draw sprites. If the sampling itself was doing this region transform, it would break that because it would transform texture coordinates twice in the flow, and Godot would need to be refactored to leave UV unmodified.

Preventing from setting atlas textures in shader parameters would also be inconvenient, despite the annoyance, because it prevents again the "common" use case.

Those two use cases are both valid to me, but they can't work both without breaking compatibility.
There is a workaround, which involves some boilerplate to pass region information as a second parameter to the shader, so that you can do the cooordinate transform yourself when sampling the texture. Or, if you know how your texture is supposed to be, you can do some math to avoid having to pass it (i.e if you know the number of palettes laid out vertically, you can divide X by that number).

@Shadowblitz16
Copy link
Author

Shadowblitz16 commented Feb 16, 2019

I really don't want to have to manually modify uv coords in the shader based on the region info passed in.
maybe godot could do some shader code behind the scenes right before running our shaders to clip the region.

@QbieShay
Copy link
Contributor

QbieShay commented Nov 2, 2019

Can confirm on version 3.2 on commit cbfb944
In the top right you can see the texture being correctly visualized by the editor, while in the scene you can see the texture applied to a 3D plane and the texture region being ignored.
Screenshot_2019-11-02_16-13-11

@t-mw
Copy link
Contributor

t-mw commented Apr 28, 2020

I ran into this while trying to work around the performance issues with Sprite3D, by trying to use an AtlasTexture on a MeshInstance material. Here's the shader and script I'm using to do that https://gist.github.com/t-mw/0b78167372ed97e7c78e3f3844f3ae75, assuming you're using an orthogonal camera and quad geometry.

It won't work for geometry that uses perspective, maybe someone can rework it to do that. The important part is:

	vec2 uv_offset = region_origin * inv_atlas_size;
	vec2 uv_scale = region_size * inv_atlas_size;
	UV = UV * uv_scale + uv_offset;

and then you'll need to somehow adjust for the atlas margins.

@Frontrider
Copy link

Frontrider commented May 16, 2020

In a visual shader, plug in the uv input into a texture's uv that has the correct region, it will output the texture that you want.
image

This is my workaround.

@Frontrider
Copy link

the above solution is broken with godot 3.2.2.stable.

@Shadowblitz16
Copy link
Author

this is related godotengine/godot-proposals#1708

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants