mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-06-02 00:47:02 -05:00
Merge pull request #1373 from notargs/feature/use_new_mesh_api
New Mesh APIを利用することで、GPUへのMeshアップロードコストを削減
This commit is contained in:
commit
0e997d4162
|
|
@ -177,9 +177,9 @@ namespace UniGLTF
|
|||
var index = i;
|
||||
using (MeasureTime("ReadMesh"))
|
||||
{
|
||||
var x = await awaitCaller.Run(() => meshImporter.ReadMesh(Data, index, inverter));
|
||||
var y = await BuildMeshAsync(awaitCaller, MeasureTime, x, index);
|
||||
Meshes.Add(y);
|
||||
var meshContext = await awaitCaller.Run(() => meshImporter.ReadMesh(Data, index, inverter));
|
||||
var meshWithMaterials = await BuildMeshAsync(awaitCaller, MeasureTime, meshContext, index);
|
||||
Meshes.Add(meshWithMaterials);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,42 +2,50 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class MeshContext
|
||||
internal class MeshContext
|
||||
{
|
||||
private readonly List<Vector3> _positions = new List<Vector3>();
|
||||
private readonly List<Vector3> _normals = new List<Vector3>();
|
||||
[Obsolete] private readonly List<Vector4> _tangents = new List<Vector4>();
|
||||
private readonly List<Vector2> _uv = new List<Vector2>();
|
||||
private readonly List<Vector2> _uv2 = new List<Vector2>();
|
||||
private readonly List<Color> _colors = new List<Color>();
|
||||
private readonly List<BoneWeight> _boneWeights = new List<BoneWeight>();
|
||||
private readonly List<int[]> _subMeshes = new List<int[]>();
|
||||
private readonly List<MeshVertex> _vertices = new List<MeshVertex>();
|
||||
private readonly List<int> _indices = new List<int>();
|
||||
private readonly List<SubMeshDescriptor> _subMeshes = new List<SubMeshDescriptor>();
|
||||
private readonly List<int> _materialIndices = new List<int>();
|
||||
private readonly List<BlendShape> _blendShapes = new List<BlendShape>();
|
||||
|
||||
public IReadOnlyList<Vector3> Positions => _positions;
|
||||
public IReadOnlyList<Vector3> Normals => _normals;
|
||||
|
||||
[Obsolete] public IReadOnlyList<Vector4> Tangetns => _tangents;
|
||||
|
||||
public IReadOnlyList<Vector2> UV => _uv;
|
||||
|
||||
public IReadOnlyList<Vector2> UV2 => _uv2;
|
||||
public IReadOnlyList<Color> Colors => _colors;
|
||||
|
||||
public IReadOnlyList<BoneWeight> BoneWeights => _boneWeights;
|
||||
|
||||
public IReadOnlyList<int[]> SubMeshes => _subMeshes;
|
||||
|
||||
public IReadOnlyList<int> MaterialIndices => _materialIndices;
|
||||
|
||||
public IReadOnlyList<BlendShape> BlendShapes => _blendShapes;
|
||||
|
||||
public bool HasNormal { get; private set; } = true;
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 頂点情報をMeshに対して送る
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
public void UploadMeshVertices(Mesh mesh)
|
||||
{
|
||||
mesh.SetVertexBufferParams(_vertices.Count, MeshVertex.GetVertexAttributeDescriptor());
|
||||
mesh.SetVertexBufferData(_vertices, 0, 0, _vertices.Count);
|
||||
}
|
||||
/// <summary>
|
||||
/// インデックス情報をMeshに対して送る
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
public void UploadMeshIndices(Mesh mesh)
|
||||
{
|
||||
mesh.SetIndexBufferParams(_indices.Count, IndexFormat.UInt32);
|
||||
mesh.SetIndexBufferData(_indices, 0, 0, _indices.Count);
|
||||
mesh.subMeshCount = _subMeshes.Count;
|
||||
for (var i = 0; i < _subMeshes.Count; i++)
|
||||
{
|
||||
mesh.SetSubMesh(i, _subMeshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private BlendShape GetOrCreateBlendShape(int i)
|
||||
{
|
||||
if (i < _blendShapes.Count && _blendShapes[i] != null)
|
||||
|
|
@ -62,41 +70,23 @@ namespace UniGLTF
|
|||
name = $"UniGLTF import#{meshIndex}";
|
||||
}
|
||||
|
||||
this.Name = name;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill list with 0s with the specified length
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="fillLength"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
private static void FillZero<T>(ICollection<T> list, int fillLength)
|
||||
private static (float x, float y, float z, float w) NormalizeBoneWeight(
|
||||
(float x, float y, float z, float w) src)
|
||||
{
|
||||
if (list.Count > fillLength)
|
||||
{
|
||||
throw new Exception("Impossible");
|
||||
}
|
||||
|
||||
while (list.Count < fillLength)
|
||||
{
|
||||
list.Add(default);
|
||||
}
|
||||
}
|
||||
|
||||
private static BoneWeight NormalizeBoneWeight(BoneWeight src)
|
||||
{
|
||||
var sum = src.weight0 + src.weight1 + src.weight2 + src.weight3;
|
||||
var sum = src.x + src.y + src.z + src.w;
|
||||
if (sum == 0)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
var f = 1.0f / sum;
|
||||
src.weight0 *= f;
|
||||
src.weight1 *= f;
|
||||
src.weight2 *= f;
|
||||
src.weight3 *= f;
|
||||
src.x *= f;
|
||||
src.y *= f;
|
||||
src.z *= f;
|
||||
src.w *= f;
|
||||
return src;
|
||||
}
|
||||
|
||||
|
|
@ -111,127 +101,72 @@ namespace UniGLTF
|
|||
/// <returns></returns>
|
||||
public void ImportMeshIndependentVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter)
|
||||
{
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
foreach (var primitives in gltfMesh.primitives)
|
||||
{
|
||||
var indexOffset = _positions.Count;
|
||||
var indexBuffer = prim.indices;
|
||||
var vertexOffset = _vertices.Count;
|
||||
var indexBufferCount = primitives.indices;
|
||||
|
||||
// position は必ずある
|
||||
var positions = data.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION);
|
||||
_positions.AddRange(positions.Select(inverter.InvertVector3));
|
||||
var fillLength = _positions.Count;
|
||||
var positions = primitives.GetPositions(data);
|
||||
var normals = primitives.GetNormals(data, positions.Length);
|
||||
var texCoords0 = primitives.GetTexCoords0(data, positions.Length);
|
||||
var texCoords1 = primitives.GetTexCoords1(data, positions.Length);
|
||||
var colors = primitives.GetColors(data, positions.Length);
|
||||
var jointsGetter = primitives.GetJoints(data, positions.Length);
|
||||
var weightsGetter = primitives.GetWeights(data, positions.Length);
|
||||
|
||||
// normal
|
||||
if (prim.attributes.NORMAL != -1)
|
||||
CheckAttributeUsages(primitives);
|
||||
|
||||
for (var i = 0; i < positions.Length; ++i)
|
||||
{
|
||||
var normals = data.GetArrayFromAccessor<Vector3>(prim.attributes.NORMAL);
|
||||
if (normals.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
var position = inverter.InvertVector3(positions[i]);
|
||||
var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero;
|
||||
|
||||
_normals.AddRange(normals.Select(inverter.InvertVector3));
|
||||
FillZero(_normals, fillLength);
|
||||
}
|
||||
|
||||
// uv
|
||||
if (prim.attributes.TEXCOORD_0 != -1)
|
||||
{
|
||||
var uvs = data.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_0);
|
||||
if (uvs.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
var texCoord0 = Vector2.zero;
|
||||
if (texCoords0 != null)
|
||||
{
|
||||
if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
// backward compatibility
|
||||
_uv.AddRange(uvs.Select(x => x.ReverseY()));
|
||||
FillZero(_uv, fillLength);
|
||||
// backward compatibility
|
||||
texCoord0 = texCoords0[i].ReverseY();
|
||||
#pragma warning restore 0612
|
||||
}
|
||||
else
|
||||
{
|
||||
_uv.AddRange(uvs.Select(x => x.ReverseUV()));
|
||||
FillZero(_uv, fillLength);
|
||||
}
|
||||
}
|
||||
|
||||
// uv2
|
||||
if (prim.attributes.TEXCOORD_1 != -1)
|
||||
{
|
||||
var uvs = data.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_1);
|
||||
if (uvs.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
else
|
||||
{
|
||||
texCoord0 = texCoords0[i].ReverseUV();
|
||||
}
|
||||
}
|
||||
|
||||
_uv2.AddRange(uvs.Select(x => x.ReverseUV()));
|
||||
FillZero(_uv2, fillLength);
|
||||
}
|
||||
var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero;
|
||||
var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0);
|
||||
var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0);
|
||||
|
||||
// color
|
||||
if (prim.attributes.COLOR_0 != -1)
|
||||
{
|
||||
var colors = data.GetArrayFromAccessor<Color>(prim.attributes.COLOR_0);
|
||||
if (colors.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
_colors.AddRange(colors);
|
||||
FillZero(_colors, fillLength);
|
||||
}
|
||||
|
||||
// skin
|
||||
if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1)
|
||||
{
|
||||
var (joints0, jointsLength) = JointsAccessor.GetAccessor(data, prim.attributes.JOINTS_0);
|
||||
var (weights0, weightsLength) = WeightsAccessor.GetAccessor(data, prim.attributes.WEIGHTS_0);
|
||||
if (jointsLength != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
if (weightsLength != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
for (var j = 0; j < jointsLength; ++j)
|
||||
{
|
||||
var bw = new BoneWeight();
|
||||
|
||||
var joints = joints0(j);
|
||||
var weights = weights0(j);
|
||||
|
||||
bw.boneIndex0 = joints.x;
|
||||
bw.weight0 = weights.x;
|
||||
|
||||
bw.boneIndex1 = joints.y;
|
||||
bw.weight1 = weights.y;
|
||||
|
||||
bw.boneIndex2 = joints.z;
|
||||
bw.weight2 = weights.z;
|
||||
|
||||
bw.boneIndex3 = joints.w;
|
||||
bw.weight3 = weights.w;
|
||||
|
||||
bw = NormalizeBoneWeight(bw);
|
||||
|
||||
_boneWeights.Add(bw);
|
||||
}
|
||||
|
||||
FillZero(_boneWeights, fillLength);
|
||||
var color = colors[i];
|
||||
_vertices.Add(
|
||||
new MeshVertex(
|
||||
position,
|
||||
normal,
|
||||
texCoord0,
|
||||
texCoord1,
|
||||
color,
|
||||
joints.x,
|
||||
joints.y,
|
||||
joints.z,
|
||||
joints.w,
|
||||
weights.x,
|
||||
weights.y,
|
||||
weights.z,
|
||||
weights.w
|
||||
));
|
||||
}
|
||||
|
||||
// blendshape
|
||||
if (prim.targets != null && prim.targets.Count > 0)
|
||||
if (primitives.targets != null && primitives.targets.Count > 0)
|
||||
{
|
||||
for (var i = 0; i < prim.targets.Count; ++i)
|
||||
for (var i = 0; i < primitives.targets.Count; ++i)
|
||||
{
|
||||
var primTarget = prim.targets[i];
|
||||
var primTarget = primitives.targets[i];
|
||||
var blendShape = GetOrCreateBlendShape(i);
|
||||
if (primTarget.POSITION != -1)
|
||||
{
|
||||
|
|
@ -242,7 +177,6 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
blendShape.Positions.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
FillZero(blendShape.Positions, fillLength);
|
||||
}
|
||||
|
||||
if (primTarget.NORMAL != -1)
|
||||
|
|
@ -254,7 +188,6 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
blendShape.Normals.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
FillZero(blendShape.Normals, fillLength);
|
||||
}
|
||||
|
||||
if (primTarget.TANGENT != -1)
|
||||
|
|
@ -266,29 +199,38 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
blendShape.Tangents.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
FillZero(blendShape.Tangents, fillLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var indices =
|
||||
(indexBuffer >= 0)
|
||||
? data.GetIndices(indexBuffer)
|
||||
: TriangleUtil.FlipTriangle(Enumerable.Range(0, _positions.Count))
|
||||
.ToArray() // without index array
|
||||
;
|
||||
for (var i = 0; i < indices.Length; ++i)
|
||||
if (indexBufferCount >= 0)
|
||||
{
|
||||
indices[i] += indexOffset;
|
||||
var indexOffset = _indices.Count;
|
||||
var dataIndices = data.GetIndices(indexBufferCount);
|
||||
_indices.AddRange(dataIndices.Select(index => index + vertexOffset));
|
||||
_subMeshes.Add(new SubMeshDescriptor(indexOffset, dataIndices.Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
var indexOffset = _indices.Count;
|
||||
_indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count)).Select(index => index + vertexOffset));
|
||||
_subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count));
|
||||
}
|
||||
|
||||
_subMeshes.Add(indices);
|
||||
|
||||
// material
|
||||
_materialIndices.Add(prim.material);
|
||||
_materialIndices.Add(primitives.material);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 各種頂点属性が使われているかどうかをチェックし、使われていなかったらフラグを切る
|
||||
/// MEMO: O(1)で検知する手段がありそう
|
||||
/// </summary>
|
||||
private void CheckAttributeUsages(glTFPrimitives primitives)
|
||||
{
|
||||
if (!primitives.HasNormal()) HasNormal = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 各primitiveが同じ attribute を共有している場合専用のローダー。
|
||||
|
|
@ -301,116 +243,67 @@ namespace UniGLTF
|
|||
{
|
||||
{
|
||||
// 同じVertexBufferを共有しているので先頭のモノを使う
|
||||
var prim = gltfMesh.primitives.First();
|
||||
_positions.AddRange(data.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION)
|
||||
.SelectInplace(inverter.InvertVector3));
|
||||
var primitives = gltfMesh.primitives.First();
|
||||
|
||||
// normal
|
||||
if (prim.attributes.NORMAL != -1)
|
||||
var positions = primitives.GetPositions(data);
|
||||
var normals = primitives.GetNormals(data, positions.Length);
|
||||
var texCoords0 = primitives.GetTexCoords0(data, positions.Length);
|
||||
var texCoords1 = primitives.GetTexCoords1(data, positions.Length);
|
||||
var colors = primitives.GetColors(data, positions.Length);
|
||||
var jointsGetter = primitives.GetJoints(data, positions.Length);
|
||||
var weightsGetter = primitives.GetWeights(data, positions.Length);
|
||||
|
||||
CheckAttributeUsages(primitives);
|
||||
|
||||
for (var i = 0; i < positions.Length; ++i)
|
||||
{
|
||||
_normals.AddRange(data.GetArrayFromAccessor<Vector3>(prim.attributes.NORMAL)
|
||||
.SelectInplace(inverter.InvertVector3));
|
||||
}
|
||||
|
||||
#if false
|
||||
// tangent
|
||||
if (prim.attributes.TANGENT != -1)
|
||||
var position = inverter.InvertVector3(positions[i]);
|
||||
var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero;
|
||||
var texCoord0 = Vector2.zero;
|
||||
if (texCoords0 != null)
|
||||
{
|
||||
tangents.AddRange(gltf.GetArrayFromAccessor<Vector4>(prim.attributes.TANGENT).SelectInplace(inverter.InvertVector4));
|
||||
}
|
||||
#endif
|
||||
|
||||
// uv
|
||||
if (prim.attributes.TEXCOORD_0 != -1)
|
||||
{
|
||||
if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
// backward compatibility
|
||||
_uv.AddRange(data.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_0)
|
||||
.SelectInplace(x => x.ReverseY()));
|
||||
#pragma warning restore 0612
|
||||
}
|
||||
else
|
||||
{
|
||||
_uv.AddRange(data.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_0)
|
||||
.SelectInplace(x => x.ReverseUV()));
|
||||
}
|
||||
}
|
||||
|
||||
// uv2
|
||||
if (prim.attributes.TEXCOORD_1 != -1)
|
||||
{
|
||||
_uv2.AddRange(data.GetArrayFromAccessor<Vector2>(prim.attributes.TEXCOORD_1)
|
||||
.SelectInplace(x => x.ReverseUV()));
|
||||
}
|
||||
|
||||
// color
|
||||
if (prim.attributes.COLOR_0 != -1)
|
||||
{
|
||||
switch (data.GLTF.accessors[prim.attributes.COLOR_0].TypeCount)
|
||||
{
|
||||
case 3:
|
||||
if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
var vec3Color = data.GetArrayFromAccessor<Vector3>(prim.attributes.COLOR_0);
|
||||
_colors.AddRange(new Color[vec3Color.Length]);
|
||||
|
||||
for (var i = 0; i < vec3Color.Length; i++)
|
||||
{
|
||||
var color = vec3Color[i];
|
||||
_colors[i] = new Color(color.x, color.y, color.z);
|
||||
}
|
||||
|
||||
break;
|
||||
#pragma warning disable 0612
|
||||
texCoord0 = texCoords0[i].ReverseY();
|
||||
#pragma warning restore 0612
|
||||
}
|
||||
else
|
||||
{
|
||||
texCoord0 = texCoords0[i].ReverseUV();
|
||||
}
|
||||
case 4:
|
||||
_colors.AddRange(data.GetArrayFromAccessor<Color>(prim.attributes.COLOR_0));
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(
|
||||
$"unknown color type {data.GLTF.accessors[prim.attributes.COLOR_0].type}");
|
||||
}
|
||||
}
|
||||
|
||||
// skin
|
||||
if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1)
|
||||
{
|
||||
var (joints0, jointsLength) = JointsAccessor.GetAccessor(data, prim.attributes.JOINTS_0);
|
||||
var (weights0, weightsLength) = WeightsAccessor.GetAccessor(data, prim.attributes.WEIGHTS_0);
|
||||
var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero;
|
||||
var color = colors != null ? colors[i] : Color.black;
|
||||
var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0);
|
||||
var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0);
|
||||
|
||||
for (var j = 0; j < jointsLength; ++j)
|
||||
{
|
||||
var bw = new BoneWeight();
|
||||
|
||||
var joints = joints0(j);
|
||||
var weights = weights0(j);
|
||||
|
||||
bw.boneIndex0 = joints.x;
|
||||
bw.weight0 = weights.x;
|
||||
|
||||
bw.boneIndex1 = joints.y;
|
||||
bw.weight1 = weights.y;
|
||||
|
||||
bw.boneIndex2 = joints.z;
|
||||
bw.weight2 = weights.z;
|
||||
|
||||
bw.boneIndex3 = joints.w;
|
||||
bw.weight3 = weights.w;
|
||||
|
||||
bw = NormalizeBoneWeight(bw);
|
||||
|
||||
_boneWeights.Add(bw);
|
||||
}
|
||||
_vertices.Add(new MeshVertex(
|
||||
position,
|
||||
normal,
|
||||
texCoord0,
|
||||
texCoord1,
|
||||
color,
|
||||
joints.x,
|
||||
joints.y,
|
||||
joints.z,
|
||||
joints.w,
|
||||
weights.x,
|
||||
weights.y,
|
||||
weights.z,
|
||||
weights.w
|
||||
));
|
||||
}
|
||||
|
||||
// blendshape
|
||||
if (prim.targets != null && prim.targets.Count > 0)
|
||||
if (primitives.targets != null && primitives.targets.Count > 0)
|
||||
{
|
||||
_blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape(i.ToString())));
|
||||
for (int i = 0; i < prim.targets.Count; ++i)
|
||||
_blendShapes.AddRange(primitives.targets.Select((x, i) => new BlendShape(i.ToString())));
|
||||
for (int i = 0; i < primitives.targets.Count; ++i)
|
||||
{
|
||||
//var name = string.Format("target{0}", i++);
|
||||
var primTarget = prim.targets[i];
|
||||
var primTarget = primitives.targets[i];
|
||||
var blendShape = _blendShapes[i];
|
||||
|
||||
if (primTarget.POSITION != -1)
|
||||
|
|
@ -434,20 +327,24 @@ namespace UniGLTF
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
foreach (var primitive in gltfMesh.primitives)
|
||||
{
|
||||
if (prim.indices == -1)
|
||||
if (primitive.indices == -1)
|
||||
{
|
||||
_subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, _positions.Count)).ToArray());
|
||||
var indexOffset = _indices.Count;
|
||||
_indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count)));
|
||||
_subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count));
|
||||
}
|
||||
else
|
||||
{
|
||||
var indices = data.GetIndices(prim.indices);
|
||||
_subMeshes.Add(indices);
|
||||
var indexOffset = _indices.Count;
|
||||
var indices = data.GetIndices(primitive.indices);
|
||||
_indices.AddRange(indices);
|
||||
_subMeshes.Add(new SubMeshDescriptor(indexOffset, indices.Length));
|
||||
}
|
||||
|
||||
// material
|
||||
_materialIndices.Add(prim.material);
|
||||
_materialIndices.Add(primitive.material);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -490,29 +387,23 @@ namespace UniGLTF
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// https://github.com/vrm-c/UniVRM/issues/610
|
||||
//
|
||||
// VertexBuffer の後ろに未使用頂点がある場合に削除する
|
||||
//
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/UniVRM/issues/610
|
||||
///
|
||||
/// VertexBuffer の後ろに未使用頂点がある場合に削除する
|
||||
/// </summary>
|
||||
public void DropUnusedVertices()
|
||||
{
|
||||
var maxIndex = _subMeshes.SelectMany(x => x).Max();
|
||||
Truncate(_positions, maxIndex);
|
||||
Truncate(_normals, maxIndex);
|
||||
Truncate(_uv, maxIndex);
|
||||
Truncate(_uv2, maxIndex);
|
||||
Truncate(_colors, maxIndex);
|
||||
Truncate(_boneWeights, maxIndex);
|
||||
#if false
|
||||
Truncate(m_tangents, maxIndex);
|
||||
#endif
|
||||
foreach (var blendshape in _blendShapes)
|
||||
Profiler.BeginSample("MeshContext.DropUnusedVertices");
|
||||
var maxIndex = _indices.Max();
|
||||
Truncate(_vertices, maxIndex);
|
||||
foreach (var blendShape in _blendShapes)
|
||||
{
|
||||
Truncate(blendshape.Positions, maxIndex);
|
||||
Truncate(blendshape.Normals, maxIndex);
|
||||
Truncate(blendshape.Tangents, maxIndex);
|
||||
Truncate(blendShape.Positions, maxIndex);
|
||||
Truncate(blendShape.Normals, maxIndex);
|
||||
Truncate(blendShape.Tangents, maxIndex);
|
||||
}
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,8 +29,9 @@ namespace UniGLTF
|
|||
return sharedAttributes;
|
||||
}
|
||||
|
||||
public MeshContext ReadMesh(GltfData data, int meshIndex, IAxisInverter inverter)
|
||||
internal MeshContext ReadMesh(GltfData data, int meshIndex, IAxisInverter inverter)
|
||||
{
|
||||
Profiler.BeginSample("ReadMesh");
|
||||
var gltfMesh = data.GLTF.meshes[meshIndex];
|
||||
|
||||
var meshContext = new MeshContext(gltfMesh.name, meshIndex);
|
||||
|
|
@ -46,11 +47,12 @@ namespace UniGLTF
|
|||
meshContext.RenameBlendShape(gltfMesh);
|
||||
|
||||
meshContext.DropUnusedVertices();
|
||||
|
||||
|
||||
Profiler.EndSample();
|
||||
return meshContext;
|
||||
}
|
||||
|
||||
private static (Mesh, bool) _BuildMesh(MeshContext meshContext)
|
||||
private static (Mesh, bool) BuildMesh(MeshContext meshContext)
|
||||
{
|
||||
meshContext.AddDefaultMaterial();
|
||||
|
||||
|
|
@ -60,63 +62,15 @@ namespace UniGLTF
|
|||
name = meshContext.Name
|
||||
};
|
||||
|
||||
if (meshContext.Positions.Count > ushort.MaxValue)
|
||||
{
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
}
|
||||
meshContext.UploadMeshVertices(mesh);
|
||||
meshContext.UploadMeshIndices(mesh);
|
||||
|
||||
mesh.vertices = meshContext.Positions.ToArray();
|
||||
var recalculateNormals = false;
|
||||
if (meshContext.Normals != null && meshContext.Normals.Count > 0)
|
||||
{
|
||||
mesh.normals = meshContext.Normals.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
recalculateNormals = true;
|
||||
}
|
||||
|
||||
if (meshContext.UV.Count == mesh.vertexCount)
|
||||
{
|
||||
mesh.uv = meshContext.UV.ToArray();
|
||||
}
|
||||
|
||||
if (meshContext.UV2.Count == mesh.vertexCount)
|
||||
{
|
||||
mesh.uv2 = meshContext.UV2.ToArray();
|
||||
}
|
||||
|
||||
var recalculateTangents = true;
|
||||
#if UNIGLTF_IMPORT_TANGENTS
|
||||
if (meshContext.Tangents.Length > 0)
|
||||
{
|
||||
mesh.tangents = meshContext.Tangents.ToArray();
|
||||
recalculateTangents = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (meshContext.Colors.Count == mesh.vertexCount)
|
||||
{
|
||||
mesh.colors = meshContext.Colors.ToArray();
|
||||
}
|
||||
|
||||
if (meshContext.BoneWeights.Count > 0)
|
||||
{
|
||||
mesh.boneWeights = meshContext.BoneWeights.ToArray();
|
||||
}
|
||||
|
||||
mesh.subMeshCount = meshContext.SubMeshes.Count;
|
||||
for (var i = 0; i < meshContext.SubMeshes.Count; ++i)
|
||||
{
|
||||
mesh.SetTriangles(meshContext.SubMeshes[i], i);
|
||||
}
|
||||
|
||||
if (recalculateNormals)
|
||||
if (!meshContext.HasNormal)
|
||||
{
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
|
||||
return (mesh, recalculateTangents);
|
||||
return (mesh, true);
|
||||
}
|
||||
|
||||
private static async Task BuildBlendShapeAsync(IAwaitCaller awaitCaller, Mesh mesh, BlendShape blendShape,
|
||||
|
|
@ -162,11 +116,13 @@ namespace UniGLTF
|
|||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
public static async Task<MeshWithMaterials> BuildMeshAsync(IAwaitCaller awaitCaller, Func<int, Material> ctx,
|
||||
internal static async Task<MeshWithMaterials> BuildMeshAsync(
|
||||
IAwaitCaller awaitCaller,
|
||||
Func<int, Material> ctx,
|
||||
MeshContext meshContext)
|
||||
{
|
||||
Profiler.BeginSample("MeshImporter._BuildMesh");
|
||||
var (mesh, recalculateTangents) = _BuildMesh(meshContext);
|
||||
Profiler.BeginSample("MeshImporter.BuildMesh");
|
||||
var (mesh, recalculateTangents) = BuildMesh(meshContext);
|
||||
Profiler.EndSample();
|
||||
|
||||
if (recalculateTangents)
|
||||
|
|
|
|||
68
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs
Normal file
68
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// インターリーブされたメッシュの頂点情報を表す構造体
|
||||
/// そのままGPUにアップロードされる
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct MeshVertex
|
||||
{
|
||||
private readonly Vector3 _position;
|
||||
private readonly Vector3 _normal;
|
||||
private readonly Color _color;
|
||||
private readonly Vector2 _texCoord0;
|
||||
private readonly Vector2 _texCoord1;
|
||||
private readonly float _boneWeight0;
|
||||
private readonly float _boneWeight1;
|
||||
private readonly float _boneWeight2;
|
||||
private readonly float _boneWeight3;
|
||||
private readonly ushort _boneIndex0;
|
||||
private readonly ushort _boneIndex1;
|
||||
private readonly ushort _boneIndex2;
|
||||
private readonly ushort _boneIndex3;
|
||||
|
||||
public MeshVertex(
|
||||
Vector3 position,
|
||||
Vector3 normal,
|
||||
Vector2 texCoord0,
|
||||
Vector2 texCoord1,
|
||||
Color color,
|
||||
ushort boneIndex0,
|
||||
ushort boneIndex1,
|
||||
ushort boneIndex2,
|
||||
ushort boneIndex3,
|
||||
float boneWeight0,
|
||||
float boneWeight1,
|
||||
float boneWeight2,
|
||||
float boneWeight3)
|
||||
{
|
||||
_position = position;
|
||||
_normal = normal;
|
||||
_texCoord0 = texCoord0;
|
||||
_texCoord1 = texCoord1;
|
||||
_color = color;
|
||||
_boneIndex0 = boneIndex0;
|
||||
_boneIndex1 = boneIndex1;
|
||||
_boneIndex2 = boneIndex2;
|
||||
_boneIndex3 = boneIndex3;
|
||||
_boneWeight0 = boneWeight0;
|
||||
_boneWeight1 = boneWeight1;
|
||||
_boneWeight2 = boneWeight2;
|
||||
_boneWeight3 = boneWeight3;
|
||||
}
|
||||
|
||||
public static VertexAttributeDescriptor[] GetVertexAttributeDescriptor() => new[] {
|
||||
new VertexAttributeDescriptor(VertexAttribute.Position),
|
||||
new VertexAttributeDescriptor(VertexAttribute.Normal),
|
||||
new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4),
|
||||
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2),
|
||||
new VertexAttributeDescriptor(VertexAttribute.TexCoord1, dimension: 2),
|
||||
new VertexAttributeDescriptor(VertexAttribute.BlendWeight, dimension: 4),
|
||||
new VertexAttributeDescriptor(VertexAttribute.BlendIndices, VertexAttributeFormat.UInt16, 4),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d540d8e32d54e7089a72156edb7ad80
|
||||
timeCreated: 1636526648
|
||||
119
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs
Normal file
119
Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
internal static class PrimitiveExtensions
|
||||
{
|
||||
public static bool HasNormal(this glTFPrimitives primitives) => primitives.attributes.NORMAL != -1;
|
||||
public static bool HasTexCoord0(this glTFPrimitives primitives) => primitives.attributes.TEXCOORD_0 != -1;
|
||||
public static bool HasTexCoord1(this glTFPrimitives primitives) => primitives.attributes.TEXCOORD_1 != -1;
|
||||
public static bool HasSkin(this glTFPrimitives primitives) => primitives.attributes.JOINTS_0 != -1 && primitives.attributes.WEIGHTS_0 != -1;
|
||||
public static bool HasColor(this glTFPrimitives primitives) => primitives.attributes.COLOR_0 != -1;
|
||||
|
||||
public static Vector3[] GetPositions(this glTFPrimitives primitives, GltfData data)
|
||||
{
|
||||
return data.GetArrayFromAccessor<Vector3>(primitives.attributes.POSITION);
|
||||
}
|
||||
|
||||
public static Vector3[] GetNormals(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
if (!HasNormal(primitives)) return null;
|
||||
var result = data.GetArrayFromAccessor<Vector3>(primitives.attributes.NORMAL);
|
||||
if (result.Length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Vector2[] GetTexCoords0(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
if (!HasTexCoord0(primitives)) return null;
|
||||
var result = data.GetArrayFromAccessor<Vector2>(primitives.attributes.TEXCOORD_0);
|
||||
if (result.Length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Vector2[] GetTexCoords1(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
if (!HasTexCoord1(primitives)) return null;
|
||||
var result = data.GetArrayFromAccessor<Vector2>(primitives.attributes.TEXCOORD_1);
|
||||
if (result.Length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Color[] GetColors(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
if (!HasColor(primitives)) return null;
|
||||
|
||||
switch (data.GLTF.accessors[primitives.attributes.COLOR_0].TypeCount)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
var vec3Color = data.GetArrayFromAccessor<Vector3>(primitives.attributes.COLOR_0);
|
||||
if (vec3Color.Length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
var colors = new Color[vec3Color.Length];
|
||||
|
||||
for (var index = 0; index < vec3Color.Length; index++)
|
||||
{
|
||||
var color = vec3Color[index];
|
||||
colors[index] = new Color(color.x, color.y, color.z);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
case 4:
|
||||
var result = data.GetArrayFromAccessor<Color>(primitives.attributes.COLOR_0);
|
||||
if (result.Length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return result;
|
||||
default:
|
||||
throw new NotImplementedException(
|
||||
$"unknown color type {data.GLTF.accessors[primitives.attributes.COLOR_0].type}");
|
||||
}
|
||||
}
|
||||
|
||||
public static JointsAccessor.Getter GetJoints(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
// skin
|
||||
if (!HasSkin(primitives)) return null;
|
||||
var (getter, length) = JointsAccessor.GetAccessor(data, primitives.attributes.JOINTS_0);
|
||||
if (length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return getter;
|
||||
|
||||
}
|
||||
|
||||
public static WeightsAccessor.Getter GetWeights(this glTFPrimitives primitives, GltfData data, int positionsLength)
|
||||
{
|
||||
// skin
|
||||
if (!HasSkin(primitives)) return null;
|
||||
var (getter, length) = WeightsAccessor.GetAccessor(data, primitives.attributes.WEIGHTS_0);
|
||||
if (length != positionsLength)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
|
||||
return getter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 867e7d22991044cd921d5479269142f2
|
||||
timeCreated: 1636536120
|
||||
Loading…
Reference in New Issue
Block a user