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

3ds Max: 8 UV Channels #1129

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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