Skip to content

Commit

Permalink
fixed wrong flipped triangles when it's required to generate them ("F…
Browse files Browse the repository at this point in the history
…ox"-Test model) + fixed wrong imported vertex data on submeshes
  • Loading branch information
pfcDorn committed Oct 24, 2023
1 parent 3b0ea35 commit 972221a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 88 deletions.
3 changes: 3 additions & 0 deletions Runtime/Scripts/GLTFSceneImporter.cs
Expand Up @@ -82,6 +82,9 @@ public class UnityMeshData

public MeshTopology[] Topology;
public int[][] Indices;

public HashSet<int> alreadyAddedAccessors = new HashSet<int>();
public uint[] subMeshVertexOffset;
}

public struct ImportProgress
Expand Down
191 changes: 104 additions & 87 deletions Runtime/Scripts/SceneImporter/ImporterMeshes.cs
Expand Up @@ -68,34 +68,32 @@ protected virtual async Task ConstructMesh(GLTFMesh mesh, int meshIndex, Cancell
var firstPrim = mesh.Primitives.Count > 0 ? mesh.Primitives[0] : null;
cancellationToken.ThrowIfCancellationRequested();

var totalVertCount = mesh.Primitives.Aggregate((uint)0, (sum, p) => sum + p.Attributes[SemanticProperties.POSITION].Value.Count);
var vertOffset = 0;
var meshCache = _assetCache.MeshCache[meshIndex];
UnityMeshData unityData = new UnityMeshData()
{
Vertices = new Vector3[totalVertCount],
Normals = firstPrim.Attributes.ContainsKey(SemanticProperties.NORMAL) ? new Vector3[totalVertCount] : null,
Tangents = firstPrim.Attributes.ContainsKey(SemanticProperties.TANGENT) ? new Vector4[totalVertCount] : null,
Uv1 = firstPrim.Attributes.ContainsKey(SemanticProperties.TEXCOORD_0) ? new Vector2[totalVertCount] : null,
Uv2 = firstPrim.Attributes.ContainsKey(SemanticProperties.TEXCOORD_1) ? new Vector2[totalVertCount] : null,
Uv3 = firstPrim.Attributes.ContainsKey(SemanticProperties.TEXCOORD_2) ? new Vector2[totalVertCount] : null,
Uv4 = firstPrim.Attributes.ContainsKey(SemanticProperties.TEXCOORD_3) ? new Vector2[totalVertCount] : null,
Colors = firstPrim.Attributes.ContainsKey(SemanticProperties.COLOR_0) ? new Color[totalVertCount] : null,
BoneWeights = firstPrim.Attributes.ContainsKey(SemanticProperties.WEIGHTS_0) ? new BoneWeight[totalVertCount] : null,

MorphTargetVertices = firstPrim.Targets != null && firstPrim.Targets[0].ContainsKey(SemanticProperties.POSITION) ?
Allocate2dArray<Vector3>((uint)firstPrim.Targets.Count, totalVertCount) : null,
MorphTargetNormals = firstPrim.Targets != null && firstPrim.Targets[0].ContainsKey(SemanticProperties.NORMAL) ?
Allocate2dArray<Vector3>((uint)firstPrim.Targets.Count, totalVertCount) : null,
MorphTargetTangents = firstPrim.Targets != null && firstPrim.Targets[0].ContainsKey(SemanticProperties.TANGENT) ?
Allocate2dArray<Vector3>((uint)firstPrim.Targets.Count, totalVertCount) : null,

Topology = new MeshTopology[mesh.Primitives.Count],
Indices = new int[mesh.Primitives.Count][]
};
var unityMeshData = CreateUnityMeshData(mesh, firstPrim, totalVertCount);
Dictionary<int, AccessorId> accessorIds = new Dictionary<int, AccessorId>();
uint vOffset = 0;
int primIndex = 0;
uint[] vertOffsetBySubMesh = new uint[mesh.Primitives.Count];
uint totalVertCount = 0;
uint lastVertOffset = 0;
foreach (var p in mesh.Primitives)
{

var acc = p.Attributes[SemanticProperties.POSITION];
if (accessorIds.TryAdd(acc.Id, acc))
{
totalVertCount += acc.Value.Count;
vOffset = lastVertOffset;
lastVertOffset += acc.Value.Count;
}
vertOffsetBySubMesh[primIndex] = vOffset;

primIndex++;
}

var meshCache = _assetCache.MeshCache[meshIndex];

var unityData = CreateUnityMeshData(mesh, firstPrim, totalVertCount);
unityData.subMeshVertexOffset = vertOffsetBySubMesh;

for (int i = 0; i < mesh.Primitives.Count; ++i)
{
var primitive = mesh.Primitives[i];
Expand All @@ -104,27 +102,24 @@ protected virtual async Task ConstructMesh(GLTFMesh mesh, int meshIndex, Cancell

if (IsMultithreaded)
{
await Task.Run(() => ConvertAttributeAccessorsToUnityTypes(primCache, unityData, vertOffset, i));
await Task.Run(() => ConvertAttributeAccessorsToUnityTypes(primCache, unityData, unityData.subMeshVertexOffset[i], i));
}
else
{
ConvertAttributeAccessorsToUnityTypes(primCache, unityData, vertOffset, i);
ConvertAttributeAccessorsToUnityTypes(primCache, unityData, unityData.subMeshVertexOffset[i], i);
}

await CreateMaterials(primitive);

cancellationToken.ThrowIfCancellationRequested();

var vertCount = primitive.Attributes[SemanticProperties.POSITION].Value.Count;
vertOffset += (int)vertCount;


if (unityData.Topology[i] == MeshTopology.Triangles && primitive.Indices != null && primitive.Indices.Value != null)
{
Statistics.TriangleCount += primitive.Indices.Value.Count / 3;
}
}

Statistics.VertexCount += vertOffset;
Statistics.VertexCount += unityData.Vertices.Length;
await ConstructUnityMesh(unityData, meshIndex, mesh.Name);
}

Expand Down Expand Up @@ -408,7 +403,8 @@ private static UnityMeshData CreateUnityMeshData(GLTFMesh gltfMesh, MeshPrimitiv
: null,

Topology = new MeshTopology[gltfMesh.Primitives.Count],
Indices = new int[gltfMesh.Primitives.Count][]
Indices = new int[gltfMesh.Primitives.Count][],
subMeshVertexOffset = new uint[gltfMesh.Primitives.Count]
};
if (!onlyMorphTargets)
{
Expand Down Expand Up @@ -480,11 +476,10 @@ protected async Task ConstructUnityMesh(UnityMeshData unityMeshData, int meshInd
await YieldOnTimeoutAndThrowOnLowMemory();

mesh.subMeshCount = unityMeshData.Indices.Length;
uint baseVertex = 0;
for (int i = 0; i < unityMeshData.Indices.Length; i++)
{
mesh.SetIndices(unityMeshData.Indices[i], unityMeshData.Topology[i], i, false, (int)baseVertex);
baseVertex += _assetCache.MeshCache[meshIndex].Primitives[i].Attributes[SemanticProperties.POSITION].AccessorId.Value.Count;
mesh.SetIndices(unityMeshData.Indices[i], unityMeshData.Topology[i], i, false,
(int)unityMeshData.subMeshVertexOffset[i]);
}
mesh.RecalculateBounds();
await YieldOnTimeoutAndThrowOnLowMemory();
Expand Down Expand Up @@ -759,85 +754,107 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv
protected void ConvertAttributeAccessorsToUnityTypes(
MeshCacheData.PrimitiveCacheData primData,
UnityMeshData unityData,
int vertOffset,
uint vertOffset,
int indexOffset)
{

// todo optimize: There are multiple copies being performed to turn the buffer data into mesh data. Look into reducing them
var meshAttributes = primData.Attributes;
int vertexCount = 0;
if (meshAttributes.ContainsKey(SemanticProperties.POSITION))
uint vertexCount = 0;
if (meshAttributes.TryGetValue(SemanticProperties.POSITION, out var attribute))
{
vertexCount = attribute.AccessorId.Value.Count;
}

int[] indices;

if (meshAttributes.TryGetValue(SemanticProperties.INDICES, out var indicesAccessor))
{
vertexCount = (int)meshAttributes[SemanticProperties.POSITION].AccessorId.Value.Count;
indices = indicesAccessor.AccessorContent.AsUInts.ToIntArrayRaw();
if (unityData.Topology[indexOffset] == MeshTopology.Triangles)
SchemaExtensions.FlipTriangleFaces(indices);
}
else
{
indices = MeshPrimitive.GenerateTriangles((int)vertexCount);
}

var indices = meshAttributes.ContainsKey(SemanticProperties.INDICES)
? meshAttributes[SemanticProperties.INDICES].AccessorContent.AsUInts.ToIntArrayRaw()
: MeshPrimitive.GenerateTriangles(vertexCount);
if (unityData.Topology[indexOffset] == MeshTopology.Triangles)
SchemaExtensions.FlipTriangleFaces(indices);
unityData.Indices[indexOffset] = indices;

if (meshAttributes.ContainsKey(SemanticProperties.Weight[0]) && meshAttributes.ContainsKey(SemanticProperties.Joint[0]))
// Only add weight/joint data when it's not already added to the unity mesh data !
if (meshAttributes.ContainsKey(SemanticProperties.Weight[0]) && meshAttributes.ContainsKey(SemanticProperties.Joint[0])
&& !unityData.alreadyAddedAccessors.Contains(meshAttributes[SemanticProperties.Weight[0]].AccessorId.Id))
{
unityData.alreadyAddedAccessors.Add(meshAttributes[SemanticProperties.Weight[0]].AccessorId.Id);

CreateBoneWeightArray(
meshAttributes[SemanticProperties.Joint[0]].AccessorContent.AsVec4s.ToUnityVector4Raw(),
meshAttributes[SemanticProperties.Weight[0]].AccessorContent.AsVec4s.ToUnityVector4Raw(),
ref unityData.BoneWeights,
vertOffset);
}

if (meshAttributes.ContainsKey(SemanticProperties.POSITION))
{
meshAttributes[SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3Raw(unityData.Vertices, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.NORMAL))
{
meshAttributes[SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3Raw(unityData.Normals, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.TANGENT))
{
meshAttributes[SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4Raw(unityData.Tangents, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.TexCoord[0]))
{
meshAttributes[SemanticProperties.TexCoord[0]].AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv1, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.TexCoord[1]))
{
meshAttributes[SemanticProperties.TexCoord[1]].AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv2, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.TexCoord[2]))
// Only add vertex data when it's not already added to the unity mesh data !
if (!unityData.alreadyAddedAccessors.Contains(meshAttributes[SemanticProperties.POSITION].AccessorId.Id))
{
meshAttributes[SemanticProperties.TexCoord[2]].AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv3, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.TexCoord[3]))
{
meshAttributes[SemanticProperties.TexCoord[3]].AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv4, vertOffset);
}
if (meshAttributes.ContainsKey(SemanticProperties.Color[0]))
{
if (QualitySettings.activeColorSpace == ColorSpace.Gamma)
meshAttributes[SemanticProperties.Color[0]].AccessorContent.AsColors.ToUnityColorRaw(unityData.Colors, vertOffset);
else
meshAttributes[SemanticProperties.Color[0]].AccessorContent.AsColors.ToUnityColorLinear(unityData.Colors, vertOffset);
}

if (meshAttributes.TryGetValue(SemanticProperties.POSITION, out var attrPos))
{
unityData.alreadyAddedAccessors.Add(attrPos.AccessorId.Id);
attrPos.AccessorContent.AsVertices.ToUnityVector3Raw(unityData.Vertices, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.NORMAL, out var attrNorm))
{
attrNorm.AccessorContent.AsNormals.ToUnityVector3Raw(unityData.Normals, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.TANGENT, out var attrTang))
{
attrTang.AccessorContent.AsTangents.ToUnityVector4Raw(unityData.Tangents, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.TexCoord[0], out var attrTex0))
{
attrTex0.AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv1, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.TexCoord[1], out var attrTex1))
{
attrTex1.AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv2, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.TexCoord[2], out var attrTex2))
{
attrTex2.AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv3, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.TexCoord[3], out var attrTex3))
{
attrTex3.AccessorContent.AsTexcoords.ToUnityVector2Raw(unityData.Uv4, (int)vertOffset);
}
if (meshAttributes.TryGetValue(SemanticProperties.Color[0], out var attrColor))
{
if (QualitySettings.activeColorSpace == ColorSpace.Gamma)
attrColor.AccessorContent.AsColors.ToUnityColorRaw(unityData.Colors, (int)vertOffset);
else
attrColor.AccessorContent.AsColors.ToUnityColorLinear(unityData.Colors, (int)vertOffset);
}

}
var targets = primData.Targets;
if (targets != null)
{
for (int i = 0; i < targets.Count; ++i)
{
if (targets[i].ContainsKey(SemanticProperties.POSITION))
if (targets[i].TryGetValue(SemanticProperties.POSITION, out var tarAttrPos) && !unityData.alreadyAddedAccessors.Contains(tarAttrPos.AccessorId.Id))
{
targets[i][SemanticProperties.POSITION].AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetVertices[i], vertOffset);
unityData.alreadyAddedAccessors.Add(tarAttrPos.AccessorId.Id);
tarAttrPos.AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetVertices[i], (int)vertOffset);
}
if (targets[i].ContainsKey(SemanticProperties.NORMAL))
if (targets[i].TryGetValue(SemanticProperties.NORMAL, out var tarAttrNorm) && !unityData.alreadyAddedAccessors.Contains(tarAttrNorm.AccessorId.Id))
{
targets[i][SemanticProperties.NORMAL].AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetNormals[i], vertOffset);
unityData.alreadyAddedAccessors.Add(tarAttrNorm.AccessorId.Id);
tarAttrNorm.AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetNormals[i], (int)vertOffset);
}
if (targets[i].ContainsKey(SemanticProperties.TANGENT))
if (targets[i].TryGetValue(SemanticProperties.TANGENT, out var tarAttrTang) && !unityData.alreadyAddedAccessors.Contains(tarAttrTang.AccessorId.Id))
{
targets[i][SemanticProperties.TANGENT].AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetTangents[i], vertOffset);
unityData.alreadyAddedAccessors.Add(tarAttrTang.AccessorId.Id);
tarAttrTang.AccessorContent.AsVec3s.ToUnityVector3Raw(unityData.MorphTargetTangents[i], (int)vertOffset);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Runtime/Scripts/SceneImporter/ImporterSkinning.cs
Expand Up @@ -66,7 +66,7 @@ protected virtual async Task SetupBones(Skin skin, SkinnedMeshRenderer renderer,
renderer.bones = bones;
}

private void CreateBoneWeightArray(Vector4[] joints, Vector4[] weights, ref BoneWeight[] destArr, int offset = 0)
private void CreateBoneWeightArray(Vector4[] joints, Vector4[] weights, ref BoneWeight[] destArr, uint offset = 0)
{
// normalize weights (built-in normalize function only normalizes three components)
for (int i = 0; i < weights.Length; i++)
Expand Down

0 comments on commit 972221a

Please sign in to comment.