Skip to content

Commit

Permalink
3ds Max: 8 UV Channels (#1129)
Browse files Browse the repository at this point in the history
Increased number of UV Channels in the 3DS Max exporter, to match the Maya Exporter
---------

Co-authored-by: Jonas Boye <[email protected]>
  • Loading branch information
JBoye and Jonas Boye authored Dec 19, 2024
1 parent a1a1d82 commit 87d89d2
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 17 deletions.
173 changes: 156 additions & 17 deletions 3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,12 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
var mappingChannels = unskinnedMesh.ActiveMapChannelNum;
bool hasUV = false;
bool hasUV2 = false;
bool hasUV3 = false;
bool hasUV4 = false;
bool hasUV5 = false;
bool hasUV6 = false;
bool hasUV7 = false;
bool hasUV8 = false;
for (int i = 0; i < mappingChannels.Count; ++i)
{
#if MAX2017 || MAX2018 || MAX2019 || MAX2020 || MAX2021 || MAX2022 || MAX2023 || MAX2024 || MAX2025 || MAX2026
Expand All @@ -386,7 +392,33 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
{
hasUV2 = true;
}
else if (channelNum == 3)
{
hasUV3 = true;
}
else if (channelNum == 4)
{
hasUV4 = true;
}
else if (channelNum == 5)
{
hasUV5 = true;
}
else if (channelNum == 6)
{
hasUV6 = true;
}
else if (channelNum == 7)
{
hasUV7 = true;
}
else if (channelNum == 8)
{
hasUV8 = true;
}
}


var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;

Expand All @@ -399,7 +431,7 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
// Compute normals
var subMeshes = new List<BabylonSubMesh>();
List<int> faceIndexes = null;
ExtractGeometry(babylonMesh, vertices, indices, subMeshes, boneIds, skin, unskinnedMesh, invertedWorldMatrix, offsetTM, hasUV, hasUV2, hasColor, hasAlpha, optimizeVertices, multiMatsCount, meshNode, ref faceIndexes);
ExtractGeometry(babylonMesh, vertices, indices, subMeshes, boneIds, skin, unskinnedMesh, invertedWorldMatrix, offsetTM, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, optimizeVertices, multiMatsCount, meshNode, ref faceIndexes);

if (vertices.Count >= 65536)
{
Expand Down Expand Up @@ -434,8 +466,32 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
{
babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray();
}
if (hasUV3)
{
babylonMesh.uvs3 = vertices.SelectMany(v => new[] { v.UV3.X, 1 - v.UV3.Y }).ToArray();
}
if (hasUV4)
{
babylonMesh.uvs4 = vertices.SelectMany(v => new[] { v.UV4.X, 1 - v.UV4.Y }).ToArray();
}
if (hasUV5)
{
babylonMesh.uvs5 = vertices.SelectMany(v => new[] { v.UV5.X, 1 - v.UV5.Y }).ToArray();
}
if (hasUV6)
{
babylonMesh.uvs6 = vertices.SelectMany(v => new[] { v.UV6.X, 1 - v.UV6.Y }).ToArray();
}
if (hasUV7)
{
babylonMesh.uvs7 = vertices.SelectMany(v => new[] { v.UV7.X, 1 - v.UV7.Y }).ToArray();
}
if (hasUV8)
{
babylonMesh.uvs8 = vertices.SelectMany(v => new[] { v.UV8.X, 1 - v.UV8.Y }).ToArray();
}

if (skin != null)
if (skin != null)
{
babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
Expand Down Expand Up @@ -888,11 +944,11 @@ private List<GlobalVertex> ExtractVertices(BabylonAbstractMesh babylonAbstractMe
var offsetTM = GetOffsetTM(maxMorphTarget, 0);

var vertices = new List<GlobalVertex>();
ExtractGeometry(babylonAbstractMesh, vertices, new List<int>(), new List<BabylonSubMesh>(), null, null, gameMesh, invertedWorldMatrix, offsetTM, false, false, false, false, optimizeVertices, multiMatsCount, maxMorphTarget, ref faceIndexes);
ExtractGeometry(babylonAbstractMesh, vertices, new List<int>(), new List<BabylonSubMesh>(), null, null, gameMesh, invertedWorldMatrix, offsetTM, false, false, false, false, false, false, false, false, false, false, optimizeVertices, multiMatsCount, maxMorphTarget, ref faceIndexes);
return vertices;
}

private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List<GlobalVertex> vertices, List<int> indices, List<BabylonSubMesh> subMeshes, List<int> boneIds, IIGameSkin skin, IIGameMesh unskinnedMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, bool optimizeVertices, int multiMatsCount, IIGameNode meshNode, ref List<int> faceIndexes)
private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List<GlobalVertex> vertices, List<int> indices, List<BabylonSubMesh> subMeshes, List<int> boneIds, IIGameSkin skin, IIGameMesh unskinnedMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, bool hasUV, bool hasUV2, bool hasUV3, bool hasUV4, bool hasUV5, bool hasUV6, bool hasUV7, bool hasUV8, bool hasColor, bool hasAlpha, bool optimizeVertices, int multiMatsCount, IIGameNode meshNode, ref List<int> faceIndexes)
{
Dictionary<GlobalVertex, List<GlobalVertex>> verticesAlreadyExported = null;

Expand Down Expand Up @@ -937,7 +993,7 @@ private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List<Globa
{
face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
}
ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
}
}
else
Expand All @@ -964,7 +1020,7 @@ private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List<Globa
{
face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
}
ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
}
}
else
Expand Down Expand Up @@ -1018,24 +1074,23 @@ private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List<Globa
}
}
}

private void ExtractFace(IIGameSkin skin, IIGameMesh unskinnedMesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, List<GlobalVertex> vertices, List<int> indices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, Dictionary<GlobalVertex, List<GlobalVertex>> verticesAlreadyExported, ref int indexCount, ref int minVertexIndex, ref int maxVertexIndex, IFaceEx face, List<int> boneIds)
private void ExtractFace(IIGameSkin skin, IIGameMesh unskinnedMesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, List<GlobalVertex> vertices, List<int> indices, bool hasUV, bool hasUV2, bool hasUV3, bool hasUV4, bool hasUV5, bool hasUV6, bool hasUV7, bool hasUV8, bool hasColor, bool hasAlpha, Dictionary<GlobalVertex, List<GlobalVertex>> verticesAlreadyExported, ref int indexCount, ref int minVertexIndex, ref int maxVertexIndex, IFaceEx face, List<int> boneIds)
{
int a, b, c;
// parity is TRUE, if determinant negative ( counter-intuitive convention of 3ds max, see docs... :/ )
if (invertedWorldMatrix.Parity)
{
// flipped case: reverse winding order
a = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 0, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
b = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 1, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
c = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 2, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
// flipped case: reverse winding order
a = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 0, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
b = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 1, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
c = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 2, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
}
else
{
// normal case
a = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 0, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
b = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 2, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
c = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 1, vertices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
// normal case
a = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 0, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
b = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 2, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
c = CreateGlobalVertex(unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, face, 1, vertices, hasUV, hasUV2, hasUV3, hasUV4, hasUV5, hasUV6, hasUV7, hasUV8, hasColor, hasAlpha, verticesAlreadyExported, skin, boneIds);
}

indices.Add(a);
Expand Down Expand Up @@ -1077,7 +1132,7 @@ private void ExtractFace(IIGameSkin skin, IIGameMesh unskinnedMesh, BabylonAbstr
CheckCancelled();
}

int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, IFaceEx face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, Dictionary<GlobalVertex, List<GlobalVertex>> verticesAlreadyExported, IIGameSkin skin, List<int> boneIds)
int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, IFaceEx face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasUV3, bool hasUV4, bool hasUV5, bool hasUV6, bool hasUV7, bool hasUV8, bool hasColor, bool hasAlpha, Dictionary<GlobalVertex, List<GlobalVertex>> verticesAlreadyExported, IIGameSkin skin, List<int> boneIds)
{
var vertexIndex = (int)face.Vert[facePart];

Expand Down Expand Up @@ -1152,6 +1207,90 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV3)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(3, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(3, indices[facePart]);
vertex.UV3 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV4)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(4, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(4, indices[facePart]);
vertex.UV4 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV5)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(5, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(5, indices[facePart]);
vertex.UV5 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV6)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(6, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(6, indices[facePart]);
vertex.UV6 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV7)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(7, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(7, indices[facePart]);
vertex.UV7 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasUV8)
{
var indices = new int[3];
unsafe
{
fixed (int* indicesPtr = indices)
{
mesh.GetMapFaceIndex(8, face.MeshFaceIndex, new IntPtr(indicesPtr));
}
}
var texCoord = mesh.GetMapVertex(8, indices[facePart]);
vertex.UV8 = Loader.Global.Point2.Create(texCoord.X, 1 - texCoord.Y);
}

if (hasColor)
{
var vertexColorIndex = (int)face.Color[facePart];
Expand Down
42 changes: 42 additions & 0 deletions 3ds Max/Max2Babylon/Exporter/GlobalVertex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ public struct GlobalVertex
public float[] Tangent { get; set; }
public IPoint2 UV { get; set; }
public IPoint2 UV2 { get; set; }
public IPoint2 UV3 { get; set; }
public IPoint2 UV4 { get; set; }
public IPoint2 UV5 { get; set; }
public IPoint2 UV6 { get; set; }
public IPoint2 UV7 { get; set; }
public IPoint2 UV8 { get; set; }
public int BonesIndices { get; set; }
public IPoint4 Weights { get; set; }
public int BonesIndicesExtra { get; set; }
Expand All @@ -28,6 +34,12 @@ public GlobalVertex(GlobalVertex other)
this.Tangent = other.Tangent != null ? other.Tangent.Clone2() : null;
this.UV = other.UV != null ? other.UV.Clone() : null;
this.UV2 = other.UV2 != null ? other.UV2.Clone() : null;
this.UV3 = other.UV3 != null ? other.UV3.Clone() : null;
this.UV4 = other.UV4 != null ? other.UV4.Clone() : null;
this.UV5 = other.UV5 != null ? other.UV5.Clone() : null;
this.UV6 = other.UV6 != null ? other.UV6.Clone() : null;
this.UV7 = other.UV7 != null ? other.UV7.Clone() : null;
this.UV8 = other.UV8 != null ? other.UV8.Clone() : null;
this.BonesIndices = other.BonesIndices;
this.Weights = other.Weights != null ? other.Weights.Clone() : null;
this.BonesIndicesExtra = other.BonesIndicesExtra;
Expand Down Expand Up @@ -88,6 +100,36 @@ public override bool Equals(object obj)
return false;
}

if (UV3 != null && !other.UV3.IsAlmostEqualTo(UV3, Tools.Epsilon))
{
return false;
}

if (UV4 != null && !other.UV4.IsAlmostEqualTo(UV4, Tools.Epsilon))
{
return false;
}

if (UV5 != null && !other.UV5.IsAlmostEqualTo(UV5, Tools.Epsilon))
{
return false;
}

if (UV6 != null && !other.UV6.IsAlmostEqualTo(UV6, Tools.Epsilon))
{
return false;
}

if (UV7 != null && !other.UV7.IsAlmostEqualTo(UV7, Tools.Epsilon))
{
return false;
}

if (UV8 != null && !other.UV8.IsAlmostEqualTo(UV8, Tools.Epsilon))
{
return false;
}

if (Weights != null && !other.Weights.IsAlmostEqualTo(Weights, Tools.Epsilon))
{
return false;
Expand Down

0 comments on commit 87d89d2

Please sign in to comment.