From d7a2ddf9dc5f5103b8cebc94a1503789e91e34dd Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Thu, 15 May 2025 23:38:06 +0900 Subject: [PATCH] =?UTF-8?q?fix(tangent):=20binarize=20tangent.w=20to=20?= =?UTF-8?q?=C2=B11=20to=20prevent=20NaNs=20and=20artifacts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unity’s Mesh.RecalculateTangents() sometimes generates triangles whose three vertices disagree on tangent.w (+1 vs –1). The mixed values are linearly interpolated in the fragment shader; at the midpoint w≈0, bitangent normalization hits a divide-by-zero, producing NaNs and visible glitches (notably on Android GPUs). --- .../VRM10/MToon10/Shaders/vrmc_materials_mtoon_utility.hlsl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Assets/VRM10/MToon10/Shaders/vrmc_materials_mtoon_utility.hlsl b/Assets/VRM10/MToon10/Shaders/vrmc_materials_mtoon_utility.hlsl index f6ce873dc..e6b7479ed 100644 --- a/Assets/VRM10/MToon10/Shaders/vrmc_materials_mtoon_utility.hlsl +++ b/Assets/VRM10/MToon10/Shaders/vrmc_materials_mtoon_utility.hlsl @@ -58,7 +58,11 @@ inline half3x3 MToon_GetTangentToWorld(const half3 normalWS, const half4 tangent const half3 normalizedNormalWS = normalize(normalWS); const half3 normalizedTangentWS = normalize(tangentWS.xyz); - const half3 normalizedBitangentWS = normalize(tangentWS.w * cross(normalizedNormalWS, normalizedTangentWS)); + // NOTE: tangent Sign は本来、+1 か -1 の値が望まれる。そしてこれは通常、三角形内ですべておなじ値である。 + // しかし Unity 純正の Mesh.RecalculateTangents() を呼び出すと、頂点ごとに異なる tangent Sign を持つ三角形が生まれることがある。 + // その場合 interpolate されて 0 となり、ゼロ除算と NaN が発生し、Android 環境等でビジュアルアーティファクトが出る場合があるため、二値化する。 + const half tangentSign = tangentWS.w > 0 ? 1.0 : -1.0; + const half3 normalizedBitangentWS = normalize(tangentSign * cross(normalizedNormalWS, normalizedTangentWS)); return half3x3(normalizedTangentWS, normalizedBitangentWS, normalizedNormalWS); }