fix node index mapping in skinning
This commit is contained in:
@@ -6,6 +6,7 @@ using System.Numerics;
|
|||||||
using dq8chr2glb.Core.InfoCfg;
|
using dq8chr2glb.Core.InfoCfg;
|
||||||
using dq8chr2glb.Core.MDSFormat;
|
using dq8chr2glb.Core.MDSFormat;
|
||||||
using dq8chr2glb.Core.MOTFormat;
|
using dq8chr2glb.Core.MOTFormat;
|
||||||
|
using dq8chr2glb.Logger;
|
||||||
using SharpGLTF.Materials;
|
using SharpGLTF.Materials;
|
||||||
using SharpGLTF.Memory;
|
using SharpGLTF.Memory;
|
||||||
using SharpGLTF.Schema2;
|
using SharpGLTF.Schema2;
|
||||||
@@ -22,7 +23,7 @@ public class MDSConverter
|
|||||||
private readonly Dictionary<int, Node> _nodeMap = new();
|
private readonly Dictionary<int, Node> _nodeMap = new();
|
||||||
private readonly List<Node> _boneNodes = new();
|
private readonly List<Node> _boneNodes = new();
|
||||||
private readonly Dictionary<string, MaterialBuilder> _materialCache = new();
|
private readonly Dictionary<string, MaterialBuilder> _materialCache = new();
|
||||||
private Dictionary<string, ImageBuilder> _textureBuilders = new Dictionary<string, ImageBuilder>();
|
private Dictionary<string, ImageBuilder> _textureBuilders = new();
|
||||||
|
|
||||||
private const float FRAMERATE = 16f;
|
private const float FRAMERATE = 16f;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ public class MDSConverter
|
|||||||
_gltfModel = ModelRoot.CreateModel();
|
_gltfModel = ModelRoot.CreateModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Convert(MDSScene scene, List<TM2Format.Texture> images, string name)
|
public void Convert(MDSScene scene, List<Texture> images, string name)
|
||||||
{
|
{
|
||||||
var gltfScene = _gltfModel.UseScene("DefaultScene");
|
var gltfScene = _gltfModel.UseScene("DefaultScene");
|
||||||
|
|
||||||
@@ -78,6 +79,17 @@ public class MDSConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nodesMapping = new Dictionary<int, int>();
|
||||||
|
for (int i = 0; i < _boneNodes.Count; i++)
|
||||||
|
{
|
||||||
|
var boneNode = _boneNodes[i];
|
||||||
|
var mdsNode = Array.Find(scene.nodes, n => n.name == boneNode.Name);
|
||||||
|
if (mdsNode != null)
|
||||||
|
{
|
||||||
|
nodesMapping[mdsNode.index] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CreateMaterials(scene.materials, images);
|
CreateMaterials(scene.materials, images);
|
||||||
|
|
||||||
var meshes = scene.nodes.Where(n => n is MDSMesh).Cast<MDSMesh>().ToArray();
|
var meshes = scene.nodes.Where(n => n is MDSMesh).Cast<MDSMesh>().ToArray();
|
||||||
@@ -85,7 +97,7 @@ public class MDSConverter
|
|||||||
{
|
{
|
||||||
if (mdsMesh?.vertices == null || mdsMesh.triangles == null) continue;
|
if (mdsMesh?.vertices == null || mdsMesh.triangles == null) continue;
|
||||||
|
|
||||||
var mesh = CreateGltfMesh(mdsMesh, scene.materials);
|
var mesh = CreateGltfMesh(mdsMesh, scene.materials, nodesMapping);
|
||||||
if (_nodeMap.TryGetValue(mdsMesh.index, out var meshNode))
|
if (_nodeMap.TryGetValue(mdsMesh.index, out var meshNode))
|
||||||
{
|
{
|
||||||
meshNode.WithMesh(mesh);
|
meshNode.WithMesh(mesh);
|
||||||
@@ -178,9 +190,9 @@ public class MDSConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mesh CreateGltfMesh(MDSMesh mdsMesh, MDSMaterial[] materials)
|
private Mesh CreateGltfMesh(MDSMesh mdsMesh, MDSMaterial[] materials, Dictionary<int, int> nodesMapping)
|
||||||
{
|
{
|
||||||
return UniversalMeshBuilder.CreateMesh(_gltfModel, mdsMesh, materials, _materialCache);
|
return UniversalMeshBuilder.CreateMesh(_gltfModel, mdsMesh, materials, _materialCache, nodesMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupSkeleton(MDSNode[] nodes, string name)
|
private void SetupSkeleton(MDSNode[] nodes, string name)
|
||||||
@@ -196,14 +208,9 @@ public class MDSConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rootBone == null && _boneNodes.Count > 0)
|
|
||||||
{
|
|
||||||
rootBone = _boneNodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_boneNodes.Count == 0)
|
if (_boneNodes.Count == 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Skip mesh with 0 bones");
|
Log.Line("Skip mesh with 0 bones");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,8 +229,7 @@ public class MDSConverter
|
|||||||
var bindposeMatrix = ToNumericsMatrix4x4(b.bindpose);
|
var bindposeMatrix = ToNumericsMatrix4x4(b.bindpose);
|
||||||
if (Matrix4x4.Invert(bindposeMatrix, out var bindposeInverse))
|
if (Matrix4x4.Invert(bindposeMatrix, out var bindposeInverse))
|
||||||
{
|
{
|
||||||
var multiplied = Matrix4x4.Multiply(bindposeInverse, Matrix4x4.Identity);
|
bindMatrix = Matrix4x4.Multiply(bindposeInverse, Matrix4x4.Identity);
|
||||||
bindMatrix = SanitizeBindMatrix(multiplied);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -240,7 +246,7 @@ public class MDSConverter
|
|||||||
{
|
{
|
||||||
if (node.Mesh != null)
|
if (node.Mesh != null)
|
||||||
{
|
{
|
||||||
if (node.Mesh.Primitives.All(i => i.VertexAccessors.ContainsKey("WEIGHTS_0")))
|
if (node.Mesh.Primitives.Any(i => i.VertexAccessors.ContainsKey("WEIGHTS_0")))
|
||||||
{
|
{
|
||||||
if (Quaternion.Dot(node.LocalTransform.GetDecomposed().Rotation, Quaternion.Identity) >= 0.999f)
|
if (Quaternion.Dot(node.LocalTransform.GetDecomposed().Rotation, Quaternion.Identity) >= 0.999f)
|
||||||
{
|
{
|
||||||
@@ -253,11 +259,6 @@ public class MDSConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Matrix4x4 SanitizeBindMatrix(Matrix4x4 matrix)
|
|
||||||
{
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Matrix4x4 ToNumericsMatrix4x4(MDSMatrix m)
|
private Matrix4x4 ToNumericsMatrix4x4(MDSMatrix m)
|
||||||
{
|
{
|
||||||
return new Matrix4x4(
|
return new Matrix4x4(
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using dq8chr2glb.Core.MDSFormat;
|
using dq8chr2glb.Core.MDSFormat;
|
||||||
|
using dq8chr2glb.Logger;
|
||||||
using SharpGLTF.Geometry;
|
using SharpGLTF.Geometry;
|
||||||
using SharpGLTF.Geometry.VertexTypes;
|
using SharpGLTF.Geometry.VertexTypes;
|
||||||
using SharpGLTF.Materials;
|
using SharpGLTF.Materials;
|
||||||
using SharpGLTF.Schema2;
|
using SharpGLTF.Schema2;
|
||||||
|
using Node = SharpGLTF.Schema2.Node;
|
||||||
|
|
||||||
namespace dq8chr2glb.Converter
|
namespace dq8chr2glb.Converter
|
||||||
{
|
{
|
||||||
public static class UniversalMeshBuilder
|
public static class UniversalMeshBuilder
|
||||||
{
|
{
|
||||||
public static Mesh CreateMesh(ModelRoot _root, MDSMesh mdsMesh, MDSMaterial[] materials,
|
public static Mesh CreateMesh(ModelRoot _root, MDSMesh mdsMesh, MDSMaterial[] materials,
|
||||||
Dictionary<string, MaterialBuilder> materialCache)
|
Dictionary<string, MaterialBuilder> materialCache, Dictionary<int, int> nodesMap)
|
||||||
{
|
{
|
||||||
var (hasUvs, hasSkinning) = AnalyzeMeshAttributes(mdsMesh);
|
var hasUvs = (mdsMesh.features & MeshFeatures.UVs) != 0;
|
||||||
|
var hasSkinning = (mdsMesh.features & MeshFeatures.Weights) != 0;
|
||||||
|
|
||||||
// Выбираем подходящий тип вершины на основе атрибутов
|
// Выбираем подходящий тип вершины на основе атрибутов
|
||||||
if (hasSkinning)
|
if (hasSkinning)
|
||||||
@@ -22,12 +26,12 @@ namespace dq8chr2glb.Converter
|
|||||||
if (hasUvs)
|
if (hasUvs)
|
||||||
{
|
{
|
||||||
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexTexture1, VertexJoints4>(
|
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexTexture1, VertexJoints4>(
|
||||||
_root, mdsMesh, materials, materialCache);
|
_root, mdsMesh, materials, materialCache, nodesMap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexEmpty, VertexJoints4>(
|
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexEmpty, VertexJoints4>(
|
||||||
_root, mdsMesh, materials, materialCache);
|
_root, mdsMesh, materials, materialCache, nodesMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -35,12 +39,12 @@ namespace dq8chr2glb.Converter
|
|||||||
if (hasUvs)
|
if (hasUvs)
|
||||||
{
|
{
|
||||||
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexTexture1, VertexEmpty>(
|
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexTexture1, VertexEmpty>(
|
||||||
_root, mdsMesh, materials, materialCache);
|
_root, mdsMesh, materials, materialCache, nodesMap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexEmpty, VertexEmpty>(
|
return CreateMeshWithAllAttributes<VertexPositionNormal, VertexEmpty, VertexEmpty>(
|
||||||
_root, mdsMesh, materials, materialCache);
|
_root, mdsMesh, materials, materialCache, nodesMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,8 +54,7 @@ namespace dq8chr2glb.Converter
|
|||||||
var hasUvs = mdsMesh.uv != null && mdsMesh.uv.Length > 0 &&
|
var hasUvs = mdsMesh.uv != null && mdsMesh.uv.Length > 0 &&
|
||||||
Array.Exists(mdsMesh.uv, uv => uv != null && uv.Length >= 2);
|
Array.Exists(mdsMesh.uv, uv => uv != null && uv.Length >= 2);
|
||||||
var hasSkinning = mdsMesh.weights != null && mdsMesh.bones != null &&
|
var hasSkinning = mdsMesh.weights != null && mdsMesh.bones != null &&
|
||||||
mdsMesh.bones.Length > 0 &&
|
mdsMesh.bones.Length > 0; // && Array.Exists(mdsMesh.bones, b => b != null)
|
||||||
Array.Exists(mdsMesh.bones, b => b != null);
|
|
||||||
|
|
||||||
return (hasUvs, hasSkinning);
|
return (hasUvs, hasSkinning);
|
||||||
}
|
}
|
||||||
@@ -60,7 +63,8 @@ namespace dq8chr2glb.Converter
|
|||||||
ModelRoot root,
|
ModelRoot root,
|
||||||
MDSMesh mdsMesh,
|
MDSMesh mdsMesh,
|
||||||
MDSMaterial[] materials,
|
MDSMaterial[] materials,
|
||||||
Dictionary<string, MaterialBuilder> materialCache)
|
Dictionary<string, MaterialBuilder> materialCache,
|
||||||
|
Dictionary<int, int> nodesMap)
|
||||||
where TvG : struct, IVertexGeometry
|
where TvG : struct, IVertexGeometry
|
||||||
where TvM : struct, IVertexMaterial
|
where TvM : struct, IVertexMaterial
|
||||||
where TvS : struct, IVertexSkinning
|
where TvS : struct, IVertexSkinning
|
||||||
@@ -71,10 +75,10 @@ namespace dq8chr2glb.Converter
|
|||||||
var normals = new List<Vector3>();
|
var normals = new List<Vector3>();
|
||||||
var texCoords = new List<Vector2>();
|
var texCoords = new List<Vector2>();
|
||||||
var skinningData = new List<(int, float)[]>();
|
var skinningData = new List<(int, float)[]>();
|
||||||
var hasUvs = mdsMesh.uv != null && mdsMesh.uv.Length > 0;
|
var hasUvs = (mdsMesh.features & MeshFeatures.UVs) != 0;
|
||||||
var hasSkinning = mdsMesh.weights != null && mdsMesh.bones != null;
|
var hasSkinning = (mdsMesh.features & MeshFeatures.Weights) != 0;
|
||||||
|
|
||||||
for (int i = 0; i < mdsMesh.vertices.Length; i++)
|
for (var i = 0; i < mdsMesh.vertices.Length; i++)
|
||||||
{
|
{
|
||||||
positions.Add(new Vector3(
|
positions.Add(new Vector3(
|
||||||
mdsMesh.vertices[i][0],
|
mdsMesh.vertices[i][0],
|
||||||
@@ -92,15 +96,25 @@ namespace dq8chr2glb.Converter
|
|||||||
texCoords.Add(Vector2.Zero);
|
texCoords.Add(Vector2.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSkinning && i < mdsMesh.bones.Length && mdsMesh.bones[i] != null)
|
if (hasSkinning && i < mdsMesh.bones.Length)
|
||||||
{
|
{
|
||||||
var boneIndices = mdsMesh.bones[i];
|
var boneIndices = mdsMesh.bones[i];
|
||||||
var boneWeights = mdsMesh.weights[i];
|
var boneWeights = mdsMesh.weights[i];
|
||||||
|
|
||||||
var bindings = new (int JointIndex, float Weight)[Math.Min(8, boneIndices.Length)];
|
var bindings = new (int JointIndex, float Weight)[Math.Min(4, boneIndices.Length)];
|
||||||
for (var b = 0; b < bindings.Length; b++)
|
for (var b = 0; b < bindings.Length; b++)
|
||||||
{
|
{
|
||||||
bindings[b] = (boneIndices[b], boneWeights[b]);
|
var mdsBoneIndex = boneIndices[b];
|
||||||
|
if (nodesMap.ContainsKey(mdsBoneIndex))
|
||||||
|
{
|
||||||
|
var gltfBoneIndex = nodesMap[mdsBoneIndex];
|
||||||
|
bindings[b] = (Math.Max(gltfBoneIndex, 0), boneWeights[b]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Обработка случая, когда MDS-индекс не найден в маппинге
|
||||||
|
bindings[b] = (0, boneWeights[b]); // или другое значение по умолчанию
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skinningData.Add(bindings);
|
skinningData.Add(bindings);
|
||||||
@@ -134,6 +148,15 @@ namespace dq8chr2glb.Converter
|
|||||||
indices.Add(mdsMesh.triangles[i + 2]);
|
indices.Add(mdsMesh.triangles[i + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var maxBoneIndex = 0;
|
||||||
|
foreach (var bones in mdsMesh.bones)
|
||||||
|
{
|
||||||
|
foreach (var boneID in bones)
|
||||||
|
{
|
||||||
|
maxBoneIndex = Math.Max(boneID, maxBoneIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < indices.Count; i += 3)
|
for (var i = 0; i < indices.Count; i += 3)
|
||||||
{
|
{
|
||||||
var idxA = indices[i];
|
var idxA = indices[i];
|
||||||
@@ -144,19 +167,19 @@ namespace dq8chr2glb.Converter
|
|||||||
positions[idxA],
|
positions[idxA],
|
||||||
normals[idxA],
|
normals[idxA],
|
||||||
texCoords.Count > idxA ? texCoords[idxA] : Vector2.Zero,
|
texCoords.Count > idxA ? texCoords[idxA] : Vector2.Zero,
|
||||||
skinningData.Count > idxA ? skinningData[idxA] : null);
|
skinningData.Count != 0 ? skinningData[idxA] : null);
|
||||||
|
|
||||||
var vertexB = CreateVertex<TvG, TvM, TvS>(
|
var vertexB = CreateVertex<TvG, TvM, TvS>(
|
||||||
positions[idxB],
|
positions[idxB],
|
||||||
normals[idxB],
|
normals[idxB],
|
||||||
texCoords.Count > idxB ? texCoords[idxB] : Vector2.Zero,
|
texCoords.Count > idxB ? texCoords[idxB] : Vector2.Zero,
|
||||||
skinningData.Count > idxB ? skinningData[idxB] : null);
|
skinningData.Count != 0 ? skinningData[idxB] : null);
|
||||||
|
|
||||||
var vertexC = CreateVertex<TvG, TvM, TvS>(
|
var vertexC = CreateVertex<TvG, TvM, TvS>(
|
||||||
positions[idxC],
|
positions[idxC],
|
||||||
normals[idxC],
|
normals[idxC],
|
||||||
texCoords.Count > idxC ? texCoords[idxC] : Vector2.Zero,
|
texCoords.Count > idxC ? texCoords[idxC] : Vector2.Zero,
|
||||||
skinningData.Count > idxC ? skinningData[idxC] : null);
|
skinningData.Count != 0 ? skinningData[idxC] : null);
|
||||||
|
|
||||||
primitive.AddTriangle(vertexA, vertexB, vertexC);
|
primitive.AddTriangle(vertexA, vertexB, vertexC);
|
||||||
}
|
}
|
||||||
@@ -185,8 +208,9 @@ namespace dq8chr2glb.Converter
|
|||||||
{
|
{
|
||||||
material.SetTexCoord(0, texCoord);
|
material.SetTexCoord(0, texCoord);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Log.Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +221,9 @@ namespace dq8chr2glb.Converter
|
|||||||
{
|
{
|
||||||
skinning.SetBindings(skinningData);
|
skinning.SetBindings(skinningData);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Log.Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ public struct MDTHeader
|
|||||||
[FieldOffset(20)] public int value2; // always 4104?
|
[FieldOffset(20)] public int value2; // always 4104?
|
||||||
[FieldOffset(24)] public int value3; // always 4112?
|
[FieldOffset(24)] public int value3; // always 4112?
|
||||||
|
|
||||||
[FieldOffset(32)] public float scaleFactorX;
|
[FieldOffset(32)] public float scaleX;
|
||||||
[FieldOffset(36)] public float scaleFactorY;
|
[FieldOffset(36)] public float scaleY;
|
||||||
|
|
||||||
[FieldOffset(40)] public float scaleFactorZ;
|
[FieldOffset(40)] public float scaleZ;
|
||||||
|
|
||||||
// [FieldOffset(64)] public Float3 someScale; // always 1.079?
|
// [FieldOffset(64)] public Float3 someScale; // always 1.079?
|
||||||
[FieldOffset(80)] public float uvScaleX;
|
[FieldOffset(80)] public float uvScaleX;
|
||||||
@@ -61,7 +61,7 @@ public struct MDTHeader
|
|||||||
[FieldOffset(192)] public AABB bounds;
|
[FieldOffset(192)] public AABB bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 40)]
|
[StructLayout(LayoutKind.Explicit, Size = 48)]
|
||||||
public struct AABB
|
public struct AABB
|
||||||
{
|
{
|
||||||
[FieldOffset(00)] public float minX;
|
[FieldOffset(00)] public float minX;
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using dq8chr2glb.Logger;
|
||||||
|
|
||||||
namespace dq8chr2glb.Core.MDSFormat;
|
namespace dq8chr2glb.Core.MDSFormat;
|
||||||
|
|
||||||
public class Reader
|
public class Reader
|
||||||
{
|
{
|
||||||
|
private const float gScale = 0.00003f; // Global Scale Constant
|
||||||
|
|
||||||
public static MDSScene Read(byte[] data, string filename)
|
public static MDSScene Read(byte[] data, string filename)
|
||||||
{
|
{
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
@@ -43,26 +46,17 @@ public class Reader
|
|||||||
mesh.features = features;
|
mesh.features = features;
|
||||||
mesh.bounds = mdtHeader.bounds;
|
mesh.bounds = mdtHeader.bounds;
|
||||||
|
|
||||||
// Console.WriteLine($"Features {features}");
|
|
||||||
|
|
||||||
var gScale = 0.00003f;
|
|
||||||
var scale = new float[3]
|
var scale = new float[3]
|
||||||
{
|
{ mdtHeader.scaleX * gScale, mdtHeader.scaleY * gScale, mdtHeader.scaleZ * gScale };
|
||||||
mdtHeader.scaleFactorX * gScale, mdtHeader.scaleFactorY * gScale, mdtHeader.scaleFactorZ * gScale
|
|
||||||
};
|
|
||||||
var uvScale = new float[2] { mdtHeader.uvScaleX, mdtHeader.uvScaleY };
|
var uvScale = new float[2] { mdtHeader.uvScaleX, mdtHeader.uvScaleY };
|
||||||
|
|
||||||
// read vertices array
|
// read vertices array
|
||||||
var vOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstVertex;
|
var vOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstVertex;
|
||||||
var vCount = mdtHeader.vertsCount;
|
var vCount = mdtHeader.vertsCount;
|
||||||
var vertices = Utils.ReadArray<short[], float[]>(data, vOffset, vCount, 3,
|
var vertices = Utils.ReadArray<short[], float[]>(data, vOffset, vCount, 3,
|
||||||
s =>
|
s => new[]
|
||||||
{
|
{
|
||||||
return new[]
|
s[0] * scale[0], s[1] * scale[1], s[2] * scale[2]
|
||||||
{
|
|
||||||
s[0] * scale[0], s[1] * scale[1],
|
|
||||||
s[2] * scale[2]
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// read colors array
|
// read colors array
|
||||||
@@ -71,51 +65,33 @@ public class Reader
|
|||||||
{
|
{
|
||||||
var cOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstColor;
|
var cOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstColor;
|
||||||
var cCount = mdtHeader.colorsCount;
|
var cCount = mdtHeader.colorsCount;
|
||||||
|
var maxByte = (float)byte.MaxValue;
|
||||||
colors = Utils.ReadArray<byte[], float[]>(data, cOffset, cCount, 3,
|
colors = Utils.ReadArray<byte[], float[]>(data, cOffset, cCount, 3,
|
||||||
s =>
|
s => new[]
|
||||||
{
|
{
|
||||||
return new[]
|
s[0] / maxByte, s[1] / maxByte, s[2] / maxByte
|
||||||
{ s[0] / 256f, s[1] / 256f, s[2] / 256f };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// read texcoords array
|
// read texcoords array
|
||||||
var tOffset = offset + mdtHeader.toVertexCount + mdtHeader.uvOffset;
|
var tOffset = offset + mdtHeader.toVertexCount + mdtHeader.uvOffset;
|
||||||
var tCount = mdtHeader.uvCount;
|
var tCount = mdtHeader.uvCount;
|
||||||
|
var maxSByte = (float)sbyte.MaxValue;
|
||||||
var uvs = Utils.ReadArray<byte[], float[]>(data, tOffset, tCount, 2,
|
var uvs = Utils.ReadArray<byte[], float[]>(data, tOffset, tCount, 2,
|
||||||
s =>
|
s => new[]
|
||||||
{
|
{
|
||||||
return new[]
|
s[0] / maxSByte * uvScale[0], s[1] / maxSByte * uvScale[1]
|
||||||
{
|
|
||||||
s[0] / 127f * uvScale[0], s[1] / 127f * uvScale[1]
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// read weights array
|
// read weights array
|
||||||
var wOffset = offset + mdtHeader.toVertexCount + mdtHeader.toWeightsOffset;
|
var wOffset = offset + mdtHeader.toVertexCount + mdtHeader.toWeightsOffset;
|
||||||
var weights = Utils.ReadArray<ushort[], float[]>(data, wOffset, vCount, 4, s =>
|
var weights = Utils.ReadArray<ushort[], float[]>(data, wOffset, vCount, 4,
|
||||||
{
|
s => Array.ConvertAll(s, x => (float)x / short.MaxValue));
|
||||||
var output = new float[4];
|
|
||||||
for (var i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
output[i] = s[i] / 32768f;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
});
|
|
||||||
|
|
||||||
// read bones per vertex array
|
// read bones per vertex array
|
||||||
var bOffset = offset + mdtHeader.toVertexCount + mdtHeader.toBoneIndicesOffset;
|
var bOffset = offset + mdtHeader.toVertexCount + mdtHeader.toBoneIndicesOffset;
|
||||||
var boneIndices = Utils.ReadArray<short[], int[]>(data, bOffset, vCount, 4, s =>
|
var boneIndices = Utils.ReadArray<short[], int[]>(data, bOffset, vCount, 4,
|
||||||
{
|
s => Array.ConvertAll(s, x => (int)x));
|
||||||
var output = new int[4];
|
|
||||||
for (var i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
output[i] = s[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
});
|
|
||||||
|
|
||||||
var submeshes = new List<SubMesh>();
|
var submeshes = new List<SubMesh>();
|
||||||
var triangleGroupOffset = offset + mdtHeader.vertexAttrSize;
|
var triangleGroupOffset = offset + mdtHeader.vertexAttrSize;
|
||||||
@@ -131,8 +107,16 @@ public class Reader
|
|||||||
for (var submeshIndex = 0; submeshIndex < mdtHeader.triangleGroupCount; submeshIndex++)
|
for (var submeshIndex = 0; submeshIndex < mdtHeader.triangleGroupCount; submeshIndex++)
|
||||||
{
|
{
|
||||||
var triangleGroupHeader = Utils.ReadStruct<TriangleGroupHeader>(data, ref triangleGroupOffset);
|
var triangleGroupHeader = Utils.ReadStruct<TriangleGroupHeader>(data, ref triangleGroupOffset);
|
||||||
if (triangleGroupHeader.headerSize == 32)
|
if (triangleGroupHeader.headerSize == 32 && triangleGroupHeader.toNext == 0)
|
||||||
{
|
{
|
||||||
|
// This is normal. Often, such blocks complete a sequence.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triangleGroupHeader.headerSize == 32 && triangleGroupHeader.toNext != 0)
|
||||||
|
{
|
||||||
|
// This might be weird.
|
||||||
|
Log.Line($"Skip 32-bit triangle group header on {triangleGroupOffset}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +205,6 @@ public class Reader
|
|||||||
if (type == NodeType.Bone)
|
if (type == NodeType.Bone)
|
||||||
{
|
{
|
||||||
var boneNode = new MDSBone();
|
var boneNode = new MDSBone();
|
||||||
mdsNode = new MDSNode();
|
|
||||||
mdsNode = boneNode;
|
mdsNode = boneNode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -317,8 +300,7 @@ public class Reader
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Bad index [{triangleVertexIndex}] in {content} array. Array start index: {address}, elements: {attribute.Length}");
|
Log.Line($"Bad index [{triangleVertexIndex}] in {content} array. Array start index: {address}, elements: {attribute.Length}");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace dq8chr2glb.Logger;
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Log
|
||||||
|
{
|
||||||
|
public static void Line(object data, LogLevel level = LogLevel.Debug)
|
||||||
|
{
|
||||||
|
Console.WriteLine(data.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(Exception e, LogLevel level = LogLevel.Error)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{e.Message}\n From:\n{e.Source}\nStacktrace:\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user