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

SurfaceTool generate_normals seems broken #88839

Open
wagnerfs opened this issue Feb 25, 2024 · 8 comments
Open

SurfaceTool generate_normals seems broken #88839

wagnerfs opened this issue Feb 25, 2024 · 8 comments

Comments

@wagnerfs
Copy link

wagnerfs commented Feb 25, 2024

Tested versions

4.2.1.stable.official

System information

Windows 10

Issue description

Having godot generate the normals from loaded meshes seems to produce terrible outputs.
In the example below I just loaded an ArrayMesh, tossed it to SurfaceTool as surface arrays and called commit after generating normals, no changes were made.

Left side the mesh loaded directly to a MeshInstance3D, on the right the one that went through the SurfaceTool, the issue is quite noticeable on he arms

image

[EDIT]

On further inspection, it doesn't seem to be something related to normals themselves, tested manually creating the normals and the result was the same, tested the exact same code that creates normals manually on Godot 3 and it seems to work just fine.

image

Steps to reproduce

Read above

Minimal reproduction project (MRP)

generate_noormals.zip

@clayjohn
Copy link
Member

I don't have a solution, but I've investigated this a little bit. The mesh is kind of interesting, it contains 21002 indexed vertices, after deindexing and indexing again, it drops to 15882 which means the original mesh is either carrying a lot of unnecessary vertex data or Godot is losing vertex data when calling deindex() and index().

I'm wondering if your asset authoring tool is more clever than Godot when generating normals. Godot just averages the face normal of all faces that touch a given vertex

@wagnerfs
Copy link
Author

@clayjohn exactly what I did, just calculate all vertex normals based on face normals and then average them, thing is, it does work just fine on Godot 3, but gives weird results on 4.
I used a Mixamo mesh to upload it here but I also have a couple meshes done by myself that give the same result, normals come out awfully wrong no matter if using Godot 4's built in generate_normals or manually genearting them.

@clayjohn
Copy link
Member

clayjohn commented Mar 2, 2024

@clayjohn exactly what I did, just calculate all vertex normals based on face normals and then average them, thing is, it does work just fine on Godot 3, but gives weird results on 4. I used a Mixamo mesh to upload it here but I also have a couple meshes done by myself that give the same result, normals come out awfully wrong no matter if using Godot 4's built in generate_normals or manually genearting them.

Looking at the code I am having trouble figuring out what could be different. The code changes all seem pretty safe and simple. I'm wondering if something in the import process is changing the mesh in a way that impacts how normals are getting generated. I.e. maybe the issue isn't with generate_normals() itself, but is earlier in the pipeline

edit: the biggest change is how smooth groups are treated. Before "smooth_group" was a true or false property that basically meant allow smoothing this vertex with other vertices. In Godot 4.0 smooth group is an id, and vertices only blend with other vertices in the same smooth group. So you can get a lot more detailed with how the smoothing works.

@clayjohn
Copy link
Member

clayjohn commented Mar 2, 2024

I don't have a solution, but I've investigated this a little bit. The mesh is kind of interesting, it contains 21002 indexed vertices, after deindexing and indexing again, it drops to 15882 which means the original mesh is either carrying a lot of unnecessary vertex data or Godot is losing vertex data when calling deindex() and index().

Okay, checking in Godot 3.5.3, the mesh contains 15882 from the very beginning. So in Godot 4.2 it is indeed carrying too many indices

Here is my test code (inserted into your MRP)

var arrys = mesh.surface_get_arrays(0)
print("before (vertex, index)")
print(len(arrys[Mesh.ARRAY_VERTEX]))
print(len(arrys[Mesh.ARRAY_INDEX]))

var surface_tool = SurfaceTool.new()
surface_tool.append_from(mesh, 0, Transform3D.IDENTITY)

surface_tool.deindex()

var arr = surface_tool.commit_to_arrays()
print("middle (vertex)")
print(len(arr[Mesh.ARRAY_VERTEX]))

surface_tool.index()
arr = surface_tool.commit_to_arrays()

print("after (vertex, index)")
print(len(arr[Mesh.ARRAY_VERTEX]))
print(len(arr[Mesh.ARRAY_INDEX]))
	

In 3.5.3 it prints:

before (vertex, index)
15882
86640
middle (vertex)
86640
after (vertex, index)
15882
86640

In 4.2.1 it prints:

before (vertex, index)
20510
86640
middle (vertex)
86640
after (vertex, index)
15882
86640

@clayjohn
Copy link
Member

clayjohn commented Mar 2, 2024

And blender confirms that 15882 is the correct number of vertices:
image

@clayjohn
Copy link
Member

clayjohn commented Mar 2, 2024

It seems that the difference in number of vertices comes from the LOD generation code. I'm not sure why the code would be adding vertices, but it seems that the difference in vertex count is not the root of this problem as it persists even after disabling LOD generation

@wagnerfs
Copy link
Author

wagnerfs commented Mar 2, 2024

@clayjohn thing is, vertex count shouldn't be a problem if at the end of the day, the mesh is rendered using index-to-vertex logic, which means that as long as the first 15882 vertices and 86640 indices remain unchanged, adding extra vertices shouldn't give any wrong output right?

Also I haven't spend a lot of time digging through the source to check what's going on, but I have a guess the problem lies on the arrays to ArrayMesh assemble since I've been trying to skip using surface tools and still getting a different result when using add_surface_from_arrays.

I'll drop by with any concrete information once I get time to dive into the source.

@wagnerfs
Copy link
Author

wagnerfs commented Mar 7, 2024

I spent quite a while on this to narrow down the problem but haven't got much about the issue whatsoever, BUT I did find that the vertex duplication comes from the GLTF itself apparently, since vertices needs to be doubled for correct UV/Vertex color maping.

I still have no clue why regenerating normals break this hard

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

2 participants