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

[FBX][UV] Problem exporting multiple UVs (>2) #67

Open
zwrtron opened this issue Feb 22, 2025 · 2 comments
Open

[FBX][UV] Problem exporting multiple UVs (>2) #67

zwrtron opened this issue Feb 22, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@zwrtron
Copy link

zwrtron commented Feb 22, 2025

I've ran into a problem with exporting more than two UV channels.
If any object has three or more UV channels, the exported object has no UVs at all.
Forcefully setting hasUV[n] to false for n >= 2 on all ImportedMesh resolves the problem. (only correctly exports first 2 channels)

Simple reproductive example:

  • works for any asset
  • just copy UV0 (if exists) to UV1 (work) and UV2 (not work)
  • no UVs are exported (UV0 is lost)
var converter = new ModelConverter(root, ImageFormat.Png);

foreach (var mesh in converter.MeshList) {
    if (!mesh.hasUV[0]) {
        continue; // no UVs
    }

    mesh.hasUV[1] = true;
    mesh.hasUV[2] = true;

    foreach (var vertex in mesh.VertexList) {
        if (vertex.UV[1] == null) {
            vertex.UV[1] = new float[2];
            Array.Copy(vertex.UV[0], vertex.UV[1], 2);
        }

        if (vertex.UV[2] == null) {
            vertex.UV[2] = new float[2];
            Array.Copy(vertex.UV[0], vertex.UV[2], 2);
        }
        
    }
}

ModelExporter.ExportFbx(
    file, 
    converter,
    true,  //eulerFilter
    0.25f, //filterPrecision
    true,  //allNodes
    true,  //skins
    true,  //animation
    true,  //blendShape
    true, //castToBone
    1, //boneSize
    false, //exportAllUvsAsDiffuseMaps 
    1, //scaleFactor
    3, //versionIndex
    false //isAscii
);

If the UV[2] parts are commented out, it works - UV1 is successfully copy of UV0 (if UV1 not exist)

Does anyone know how to fix it?

@aelurum
Copy link
Owner

aelurum commented Feb 23, 2025

Your issue is probably also related to this one Perfare#1047

From what I tested earlier, the problem seems to be in UVs of the same type.
In the current AS code uv0 = diffuse map, uv1 = normal map, uv2+ = diffuse map.
Would be more correct if we change uv2 to some other type, such as displacement map.

You would need to add something like this to AssetStudioFBXNative\api.cpp

AS_API(void) AsFbxMeshCreateDisplacementUV(FbxMesh* pMesh, int32_t uv)
{
	if (pMesh == nullptr)
	{
		return;
	}

	auto pUV = pMesh->CreateElementUV(FbxString("UV") + FbxString(uv), FbxLayerElement::eTextureDisplacement);
	pUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
	pUV->SetReferenceMode(FbxGeometryElement::eDirect);
}

to AssetStudioFBXNative\api.h

AS_API(void) AsFbxMeshCreateDisplacementUV(fbxsdk::FbxMesh* pMesh, int32_t uv);

to AssetStudioFBXWrapper\FbxExporterContext.PInvoke.cs

 [DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
 private static extern void AsFbxMeshCreateDisplacementUV(IntPtr mesh, int uv);

And then replace this part

for (int i = 0; i < importedMesh.hasUV.Length; i++)
{
if (!importedMesh.hasUV[i]) { continue; }
if (i == 1 && !exportAllUvsAsDiffuseMaps)
{
AsFbxMeshCreateNormalMapUV(mesh, 1);
}
else
{
AsFbxMeshCreateDiffuseUV(mesh, i);
}
}

with something like this

for (var i = 0; i < importedMesh.hasUV.Length; i++)
{
    if (!importedMesh.hasUV[i]) { continue; }

    switch (i)
    {
        case 1 when !exportAllUvsAsDiffuseMaps:
            AsFbxMeshCreateNormalMapUV(mesh, i);
            break;
        case 2 when !exportAllUvsAsDiffuseMaps:
            AsFbxMeshCreateDisplacementUV(mesh, i);
            break;
        default:
            AsFbxMeshCreateDiffuseUV(mesh, i);
            break;
    }
}

Still not sure how correct this workaround is, but it may solve some issues with multiple UVs 👀

@zwrtron
Copy link
Author

zwrtron commented Feb 24, 2025

Honestly I have no idea how "Diffuse" and "Normal Map" UVs are different, but I can confirm that using different type, as you suggested, works as expected and UV2 is correctly exported.
Thank you!

@aelurum aelurum added the bug Something isn't working label Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants