Improve tangent space generation - #119161
Merged
Merged
Conversation
meshopt_generateTangents is used to generate per-corner tangent vectors. For unindexed inputs, we then simply copy the result to the output. For indexed inputs, we copy them into the existing vertices and split vertices with divergent tangents on the fly. Splitting may interfere with blend shapes as it may disturb shared indexing. While it would be possible to propagate the split vector into the blend shape code and apply it to the blend targets as well, for now we simply avoid doing the splitting in the first place if the mesh has blend shapes. Script binding for generate_tangents uses pre-splitting behavior for compatibility.
Contributor
Author
|
Since all dependent PRs were merged I've squashed this and removed the draft status; the code is otherwise unchanged. |
Calinou
approved these changes
Jul 1, 2026
Member
There was a problem hiding this comment.
Tested locally, it works as expected. Code looks good to me.
Preview
master |
This PR | Difference (dssim) |
|---|---|---|
![]() |
![]() |
![]() |
Benchmark
PC specifications
- CPU: AMD Ryzen 9 9950X3D
- GPU: NVIDIA GeForce RTX 5090
- RAM: 64 GB (2×32 GB DDR5-6000 CL30)
- SSD: Solidigm P44 Pro 2 TB
- OS: Linux (Fedora 44)
Time taken to import octavus.obj as a 3D scene 101 times (average of 10 runs). Material import, LOD generation and shadow mesh generation are disabled to isolate tangent generation as much as possible.
Using an optimized editor binary (production=yes lto=full) in headless mode.
(master)
Benchmark 1: bin/godot.linuxbsd.editor.x86_64.master --headless --path /tmp/4 --import
Time (mean ± σ): 38.916 s ± 1.367 s [User: 38.572 s, System: 0.383 s]
Range (min … max): 38.005 s … 42.657 s 10 runs
(This PR)
Benchmark 2: bin/godot.linuxbsd.editor.x86_64 --headless --path /tmp/4 --import
Time (mean ± σ): 34.029 s ± 0.077 s [User: 33.705 s, System: 0.378 s]
Range (min … max): 33.915 s … 34.206 s 10 runs
Contributor
|
Thanks! |
BendyLand
pushed a commit
to BendyLand/voltaire
that referenced
this pull request
Aug 2, 2026
Improve tangent space generation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



This change switches from mikktspace.c tangent frame generation to the new comparable functionality provided by meshoptimizer via
meshopt_generateTangents; see documentation.It simultaneously achieves three things: fixes common tangent artifacts inherent to MikkTSpace, fixes incorrect tangents on seams with UV mirroring due to incorrect mikktspace.h usage (#114508) and speeds up the generation process ~6-7x (e.g. testing on a 2M triangle mesh, the tangent generation goes from ~2.5 seconds to ~330 msec).
Splitting vertices with divergent tangents is correct, but may disturb shared indexing when used with blend shapes. Because of this, meshes with blend shapes skip splitting and will continue to have the same problems as shown in #114508. This could be improved in the future, as it stands this change maintains behavior here.
Technically, "fixing common tangent artifacts" also implies that the tangents we generate are not-exactly-MikkTSpace. Because Godot previously didn't handle UV mirroring at all and the cases that the improved weighting fixes are objectively broken in MikkTSpace, I don't think this will be a problem; but if it ever does become a problem, we can always enable the "compatible" option which generates the same tangents as MikkTSpace by using the same weighting.
CSG code is using mikktspace directly instead of SurfaceTool. So we'd need an extra change after this to switch that over to meshopt too to be able to remove mikktspace; for now, this only replaces import path.
Script-side calls to
generate_tangentspreserve the behavior of not splitting vertices with different tangent windings out of caution.Fixes #114508