godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.04k stars 21.17k forks source link

Transparent textures are not sorting correctly #53974

Closed acatxnamedvirtue closed 3 years ago

acatxnamedvirtue commented 3 years ago

Godot version

3.3.4

System information

Windows 10, GLES3, NVIDIA GeForce RTX 2060, 30.0.14.7168

Issue description

Hello!

I am working on a prototype that uses 2D pixel art tiles applied to simple square meshes in 3D gridmaps. Everything was working very well until I tried upgrading Godot from 3.3.2 to 3.3.3 or 3.3.4

I noticed that 3.3.3 included two PRs, which I have confirmed are causing my issue. On the 3.x branch, I manually reverted those two changes, compiled Godot, and tested my project, and no longer experienced the issue.

50721

43506

Since I am using pixel art, transparency is pretty important (especially in sprites, but also in the tiles themselves).

I know that those two PRs above are positioned as fixes themselves, so I am unsure if I was just relying on Godot incorrectly sorting my sprites/tiles, but the way Godot sorted my sprites/meshes in 3.3.2 seems to me to be correct.

Sorting in 3.3.2: image

Sorting in 3.3.3+: image

I have also noticed the same sorting issues when I compile Godot 4 (master branch) from source. If I have to stay on 3.3.2, I guess I could, but I was really hoping to start taking advantage of the incredible TIleMap editor improvements.

Please let me know if you have any questions!

Thanks!

Steps to reproduce

  1. Open project in Godot 3.3.2

  2. Move around in the 3D editor or play the scene, and notice that the "Player" (Godot icon) is correctly drawn in front of cliffs.

  3. Open project in Godot 3.3.3

  4. Move around in the 3D editor or play the scene, and notice that the "Player" (Godot icon) is drawn behind cliffs when they should be drawn in front of them.

Minimal reproduction project

godot-transparency-sort-bug.zip

Calinou commented 3 years ago

See also https://github.com/godotengine/godot/issues/50794.

Make sure to use alpha testing (alpha scissor) instead of alpha blending on the SpatialMaterial when you only need 1-bit transparency. This eliminates most sorting issues.

clayjohn commented 3 years ago

I took a look at the example project and I think I have figured out what is going on. Unfortunately, it doesn't look like a bug.

Godot uses AABBs to sort transparent objects and determine what order they should be drawn in. AABBs are created from the source mesh. The corner tiles in your tilemap are using a vertex shader to manually offset the vertex positions so they are not captured by the AABB.

Notice in the below photo h Screenshot (32) ow the AABB (the orange square) appears in front of the sprite while the actual mesh appears behind it?

Now notice the scene viewed from the front. You can see that the renderer incorrectly thinks the tile is in front of the sprite. Screenshot (33)

Previously, you didn't notice this because the old (buggy) behaviour resulted in objects drawing in an arbitrary order based on their position relative to the DirectionalLight in the scene. Once your project became more complex, you would likely have run into #50721.

The solution to this issue is to create a mesh to use for your corner tiles instead of relying on offsetting the tile in the vertex shader. This will provide Godot with the correct AABB so the tiles will sort properly.

I have not used the GridMap node extensively, but I think you can even create a gridmap tile using a rotated QuadMesh.

acatxnamedvirtue commented 3 years ago

@clayjohn Oh, that makes a lot of sense, thank you so much for walking through that! I'll see if I can play around in blender and make some new meshes and apply the textures to them.

I'll also see if I can switch over to using alpha scissor as @Calinou suggested for cases where pixels are either fully transparent or fully opaque.

Just so I fully understand it, would partially transparent pixels in meshes still potentially have sorting problems?

Thank you both for your time and assistance!

Calinou commented 3 years ago

Just so I fully understand it, would partially transparent pixels in meshes still potentially have sorting problems?

Yes. The only way to combat this is to use the Render Priority property in the Material, or rely on dithering to simulate partial transparency while still using an alpha-scissor material.

acatxnamedvirtue commented 3 years ago

Hi again! I spent some time in Blender and created the appropriate mesh shapes.

I'm really pleased with the results!! Not using the shader approach also allows me to simplify my scene tree and code a bit, plus 3D shadows/lighting works perfectly.

Would you like me to close this issue?

Thanks again!

Calinou commented 3 years ago

Would you like me to close this issue?

Indeed, I consider this resolved as best as we can in a real-time 3D rendering engine. (Order-independent transparency is a thing, but it's expensive and not something you want to use in a game with a pixel art aesthetic.)