Fix #139753: Discontinuity in mesh tangent without UV map

when there is no uv, we call the function `map_to_sphere()` to create
temporary uv for computing the tangent. It could happen that a triangle
has vertices with the u coordinates going across the line where u wraps
from 1 to 0. In this case, just computing the difference of the u
coordinates results in the wrong triangle area.

To fix this problem, we compute distance in toroidal (wrap around)
space.

This is safe for coordinates generated by `map_to_sphere()` function,
because it is not supposed to map the positions of a triangle to u
coordinates that span larger than 0.5.

Pull Request: https://projects.blender.org/blender/blender/pulls/139880
This commit is contained in:
Weizhen Huang 2025-06-09 13:52:00 +02:00 committed by Weizhen Huang
parent 1dfe8047d3
commit ee578cc738
7 changed files with 41 additions and 11 deletions

View File

@ -67,7 +67,7 @@ struct MikkMeshWrapper {
{
/* TODO: Check whether introducing a template boolean in order to
* turn this into a constexpr is worth it. */
if (uv != nullptr) {
if (has_uv()) {
const int corner_index = CornerIndex(face_num, vert_num);
const float2 tfuv = uv[corner_index];
return mikk::float3(tfuv.x, tfuv.y, 1.0f);
@ -101,6 +101,11 @@ struct MikkMeshWrapper {
}
}
bool has_uv() const
{
return uv != nullptr;
}
const Mesh *mesh;
const float3 *normal;

View File

@ -253,6 +253,11 @@ template<typename Mesh> class Mikktspace {
return mesh.GetTexCoord(f, v);
}
bool has_uv() const
{
return mesh.has_uv();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -522,9 +527,16 @@ template<typename Mesh> class Mikktspace {
const float3 t2 = getTexCoord(triangle.vertices[1]);
const float3 t3 = getTexCoord(triangle.vertices[2]);
const float t21x = t2.x - t1.x;
float t21x = t2.x - t1.x;
float t31x = t3.x - t1.x;
if (!has_uv()) {
/* Compute edge length in toroidal space, since the u generated by `map_to_sphere()` might
* go cross the seam. */
t21x -= floorf(t21x + 0.5f);
t31x -= floorf(t31x + 0.5f);
}
const float t21y = t2.y - t1.y;
const float t31x = t3.x - t1.x;
const float t31y = t3.y - t1.y;
const float3 d1 = v2 - v1, d2 = v3 - v1;

View File

@ -95,7 +95,7 @@ struct SGLSLEditMeshToTangent {
mikk::float3 GetTexCoord(const uint face_num, const uint vert_index)
{
const BMLoop *l = GetLoop(face_num, vert_index);
if (cd_loop_uv_offset != -1) {
if (has_uv()) {
const float *uv = (const float *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
return mikk::float3(uv[0], uv[1], 1.0f);
}
@ -130,6 +130,11 @@ struct SGLSLEditMeshToTangent {
copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
bool has_uv()
{
return cd_loop_uv_offset != -1;
}
Span<float3> face_normals;
Span<float3> corner_normals;
Span<std::array<BMLoop *, 3>> looptris;

View File

@ -70,6 +70,11 @@ struct BKEMeshToTangent {
copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
bool has_uv() const
{
return true;
}
OffsetIndices<int> faces; /* faces */
const int *corner_verts; /* faces vertices */
const float (*positions)[3]; /* vertices */
@ -227,7 +232,7 @@ struct SGLSLMeshToTangent {
int3 tri;
int face_index;
uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
if (mloopuv != nullptr) {
if (has_uv()) {
const float2 &uv = mloopuv[loop_index];
return mikk::float3(uv[0], uv[1], 1.0f);
}
@ -281,6 +286,11 @@ struct SGLSLMeshToTangent {
copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
bool has_uv() const
{
return mloopuv != nullptr;
}
Span<float3> face_normals;
Span<float3> corner_normals;
const int3 *corner_tris;

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cd07487f8bb71a4199fb15cf994599317670ca806757fdae24c00c85a26d3be2
size 28659
oid sha256:7fa3ab720f94fa70de22f70f9e87bd74b8cc06bff20a82352b53ee24d02e14d8
size 28195

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4a3a786cd629cbd7074a40c5ece486d6dccd031e8cafdf41ad5bd62f9c1afb1a
size 20981
oid sha256:e69131fc75964401791a7a13a29d50a44e04699f29f8ff23d827ddbd75899d3a
size 20489

View File

@ -43,8 +43,6 @@ BLOCKLIST = [
]
BLOCKLIST_METAL = [
# Blocked due to difference in tangent space calculation (to be fixed).
"tangent_no_uv.blend",
# Blocked due to difference in volume lightprobe bakes (to be fixed).
"clamp_.*.blend",
"shadow_all_max_bounces.blend",