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

2D Sprite Normal Maps Are Inverted #18299

Closed
JarLowrey opened this issue Apr 19, 2018 · 18 comments
Closed

2D Sprite Normal Maps Are Inverted #18299

JarLowrey opened this issue Apr 19, 2018 · 18 comments

Comments

@JarLowrey
Copy link

JarLowrey commented Apr 19, 2018

Godot version:
3.0.2

OS/device including version:
Win10

Issue description:
2D normal mapping is inverted on Sprite's: dark is is light and light is dark. This user had the same issue and solved it by inverting the green or the red & green channels, depending on how they generated the map.

capture

Steps to reproduce:
Create sprite, add normal map, add Light2D. Colors are inverted.

Minimal reproduction project:
New Game Project1.zip

@eon-s
Copy link
Contributor

eon-s commented Apr 20, 2018

Could be that Sprites are upside down (-Y = up) for 2D while normal maps do not have the 2D correction.

@JarLowrey
Copy link
Author

I have tried inverting G and RG channels and rotating the sprite 180 degrees and unfortunately it didnt solve the problem

@JarLowrey
Copy link
Author

JarLowrey commented May 5, 2018

Translating my Godot2 normal map shader into Godot 3 did not change anything, it looks the same.

shader_type canvas_item;
uniform sampler2D normal : hint_normal;

void fragment(){
	//normal maps expect Y-up, but 2D is Y-down, so must mirror this.
	NORMAL = texture(normal, UV).rgb * vec3(2.0,-2.0,1.0) - vec3(1.0,-1.0,0.0);
}

@JarLowrey
Copy link
Author

It looks like the light is coming from the correct direction but is getting blocked after touching the map. I have dramatically reduced my normal map height and it doesnt appear to help much

capture

@fracteed
Copy link

@JarLowrey I tried adding your line of code to my shader and it was working much better than a straight *= -1 of the y/green channel. But, for the life of me I cannot work out why you are multiplying the red and green channels by 2 and the blue by only one? Why do you then subtract that vector. I have started using this line of code, but I never like using "magic numbers", so enquiring minds would love an answer :)

@JarLowrey
Copy link
Author

JarLowrey commented Jun 21, 2018

Great question! ... I don't know. I found this code about a year ago and cannot find my original source again. It seems like the issue we're facing in 3.0.

I believe it is based on this example and this comment from @reduz.

Is that working for your normal map? I couldn't get that shader to work for me in 3.0

@fracteed
Copy link

fracteed commented Jun 24, 2018

@JarLowrey thanks for the info! Strangely, in that post from reduz you linked to, he adds the vector at the end, rather than subtracting. Also, had a look at the 2d sprite shaders project file and could see no normal map example. I am guessing it was in the the Godot 2.0 version example scene and not the current one, as there is built in 2d normal lighting. The builtin normal light is great, assuming you have the correct normal map format which I am not sure that any programs render by default.

I still don't understand the math behind that line, but all is good as it works well now in my game, so obviously reduz did it this way for some reason :)
Not sure if you are on twitter or not, but my jellyfish game is using this code. I am also flipping the green and blue channels before do the green channel flip as discussed above. I am rendering out from Cinema4d so it needs these 2 operations, but after that it works great. Obviously the rotating light problem persists, but I don't really need it.

https://twitter.com/fracteed/status/1010443593884954624

@JarLowrey
Copy link
Author

Looks great! I followed you. I'll try the normal mapping again when I have time.

@leslviv
Copy link

leslviv commented Oct 6, 2018

In my case both Y & X were inverted. So here's micro fix.

shader_type canvas_item;

void fragment() {
COLOR = texture(TEXTURE, UV);
NORMAL = texture(NORMAL_TEXTURE, UV).rgb * vec3(-2.0, -2.0, 1.0) - vec3(-1.0, -1.0, 0.0);
}

@clayjohn
Copy link
Member

clayjohn commented Dec 7, 2018

For future reference, in CanvasItem shaders use NORMALMAP when using normal maps that are meant for 3D. This will override NORMAL and perform the conversion for you automatically. This isnt documented right now, but Reduz mentions it at the end of the thread linked to above.

@Calinou
Copy link
Member

Calinou commented May 31, 2020

Should we flip the expected 2D normal map direction for 4.0, since we can break compatibility there?

@phkeese
Copy link

phkeese commented May 31, 2020

What about a flag to invert one of the channels for sprite normal maps?

@Calinou
Copy link
Member

Calinou commented May 31, 2020

@greygraphics This was requested here already: godotengine/godot-proposals#785

It'd work for both 2D and 3D normal maps. Still, I think the default normal map direction should be consistent across 2D and 3D.

@HeroicNate
Copy link

I ran into this issue and I've been trying to figure out how to flip it in code. I see the code in the above posts but have no idea where to put it. I dropped my normal map into the normal map area under the texture but there is not a place to enter code on it.

@phkeese
Copy link

phkeese commented Sep 15, 2020

I ran into this issue and I've been trying to figure out how to flip it in code. I see the code in the above posts but have no idea where to put it. I dropped my normal map into the normal map area under the texture but there is not a place to enter code on it.

It is shader code, see the documentation on writing your own shaders.

@HeroicNate
Copy link

It is shader code, see the documentation on writing your own shaders.

Thanks for the link to the documentation. I'll have to do a deep dive on the shaders in godot to fully understand how it applies to the specific case of the normals being flipped. The documentation appears to be about 3D, but I guess it all applies the same.

@eon-s
Copy link
Contributor

eon-s commented Sep 15, 2020

@HeroicNate you can convert a spatial material into shader material and see how it is used.

@Calinou
Copy link
Member

Calinou commented Jun 5, 2021

Fixed by #39202 (master) and #48693 (3.x). To use this normal map Y inversion feature, select the normal map texture in the FileSystem dock, check Normal Map Invert Y in the Import dock then click Reimport.

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