BufferAccessor use NativeArray

This commit is contained in:
ousttrue
2022-02-10 22:23:39 +09:00
parent abc9bfbe09
commit b98c2f852f
21 changed files with 646 additions and 670 deletions

View File

@@ -1,7 +1,8 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace UniGLTF
{
@@ -25,6 +26,11 @@ namespace UniGLTF
m_bytes = bytes;
}
public glTFBufferView Extend<T>(NativeArray<T> array, glBufferTarget target = default) where T : struct
{
return Extend(new ArraySegment<T>(array.ToArray()), target);
}
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target = default) where T : struct
{
using (var pin = Pin.Create(array))

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using UniJSON;
using Unity.Collections;
namespace UniGLTF
{
@@ -141,7 +142,7 @@ namespace UniGLTF
_buffer.ExtendCapacity(bytesLength);
}
public int AppendToBuffer(ArraySegment<byte> segment)
public int AppendToBuffer(NativeArray<byte> segment)
{
var gltfBufferView = _buffer.Extend(segment);
var viewIndex = Gltf.bufferViews.Count;

View File

@@ -266,29 +266,32 @@ namespace UniVRM10
try
{
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(root);
// 右手系に変換
m_logLabel += $"convert to right handed coordinate...\n";
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
// export vrm-1.0
var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs();
exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta);
var exportedBytes = exporter.Storage.ToGlbBytes();
m_logLabel += $"write to {path}...\n";
File.WriteAllBytes(path, exportedBytes);
Debug.Log("exportedBytes: " + exportedBytes.Length);
var assetPath = UniGLTF.UnityPath.FromFullpath(path);
if (assetPath.IsUnderAssetsFolder)
using (var arrayManager = new NativeArrayManager())
{
// asset folder 内。import を発動
assetPath.ImportAsset();
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(arrayManager, root);
// 右手系に変換
m_logLabel += $"convert to right handed coordinate...\n";
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
// export vrm-1.0
var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs();
exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta);
var exportedBytes = exporter.Storage.ToGlbBytes();
m_logLabel += $"write to {path}...\n";
File.WriteAllBytes(path, exportedBytes);
Debug.Log("exportedBytes: " + exportedBytes.Length);
var assetPath = UniGLTF.UnityPath.FromFullpath(path);
if (assetPath.IsUnderAssetsFolder)
{
// asset folder 内。import を発動
assetPath.ImportAsset();
}
}
}
catch (Exception ex)

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using UniGLTF;
using Unity.Collections;
namespace UniVRM10
{
@@ -38,7 +39,7 @@ namespace UniVRM10
{
count = self.Count;
}
var slice = self.Bytes.Slice(offset * stride, count * stride);
var slice = self.Bytes.GetSubArray(offset * stride, count * stride);
return data.AppendToBuffer(slice);
}
@@ -61,7 +62,7 @@ namespace UniVRM10
public static int AddAccessorTo(this VrmLib.BufferAccessor self,
ExportingGltfData data, int viewIndex,
Action<ArraySegment<byte>, glTFAccessor> minMax = null,
Action<NativeArray<byte>, glTFAccessor> minMax = null,
int offset = 0, int count = 0)
{
var gltf = data.Gltf;
@@ -79,7 +80,7 @@ namespace UniVRM10
ExportingGltfData data, int bufferIndex,
// GltfBufferTargetType targetType,
bool useSparse,
Action<ArraySegment<byte>, glTFAccessor> minMax = null,
Action<NativeArray<byte>, glTFAccessor> minMax = null,
int offset = 0, int count = 0)
{
if (self.ComponentType == VrmLib.AccessorValueType.FLOAT
@@ -104,48 +105,50 @@ namespace UniVRM10
&& sparseValuesWithIndex.Count * 16 < values.Length * 12)
{
// use sparse
var sparseIndexBin = new ArraySegment<byte>(new byte[sparseValuesWithIndex.Count * 4]);
var sparseIndexSpan = SpanLike.Wrap<Int32>(sparseIndexBin);
var sparseValueBin = new ArraySegment<byte>(new byte[sparseValuesWithIndex.Count * 12]);
var sparseValueSpan = SpanLike.Wrap<Vector3>(sparseValueBin);
for (int i = 0; i < sparseValuesWithIndex.Count; ++i)
using (var sparseIndexBin = new NativeArray<byte>(sparseValuesWithIndex.Count * 4, Allocator.Persistent))
using (var sparseValueBin = new NativeArray<byte>(sparseValuesWithIndex.Count * 12, Allocator.Persistent))
{
var (index, value) = sparseValuesWithIndex[i];
sparseIndexSpan[i] = index;
sparseValueSpan[i] = value;
}
var sparseIndexSpan = sparseIndexBin.Reinterpret<Int32>(1);
var sparseValueSpan = sparseValueBin.Reinterpret<Vector3>(1);
var sparseIndexView = data.AppendToBuffer(sparseIndexBin);
var sparseValueView = data.AppendToBuffer(sparseValueBin);
var accessorIndex = data.Gltf.accessors.Count;
var accessor = new glTFAccessor
{
componentType = (glComponentType)self.ComponentType,
type = self.AccessorType.ToString(),
count = self.Count,
byteOffset = -1,
sparse = new glTFSparse
for (int i = 0; i < sparseValuesWithIndex.Count; ++i)
{
count = sparseValuesWithIndex.Count,
indices = new glTFSparseIndices
{
componentType = (glComponentType)VrmLib.AccessorValueType.UNSIGNED_INT,
bufferView = sparseIndexView,
},
values = new glTFSparseValues
{
bufferView = sparseValueView,
},
var (index, value) = sparseValuesWithIndex[i];
sparseIndexSpan[i] = index;
sparseValueSpan[i] = value;
}
};
if (minMax != null)
{
minMax(sparseValueBin, accessor);
var sparseIndexView = data.AppendToBuffer(sparseIndexBin);
var sparseValueView = data.AppendToBuffer(sparseValueBin);
var accessorIndex = data.Gltf.accessors.Count;
var accessor = new glTFAccessor
{
componentType = (glComponentType)self.ComponentType,
type = self.AccessorType.ToString(),
count = self.Count,
byteOffset = -1,
sparse = new glTFSparse
{
count = sparseValuesWithIndex.Count,
indices = new glTFSparseIndices
{
componentType = (glComponentType)VrmLib.AccessorValueType.UNSIGNED_INT,
bufferView = sparseIndexView,
},
values = new glTFSparseValues
{
bufferView = sparseValueView,
},
}
};
if (minMax != null)
{
minMax(sparseValueBin, accessor);
}
data.Gltf.accessors.Add(accessor);
return accessorIndex;
}
data.Gltf.accessors.Add(accessor);
return accessorIndex;
}
}

View File

@@ -23,12 +23,12 @@ namespace UniVRM10
Profiler.BeginSample("MeshImporter.LoadSharedMesh");
var mesh = new Mesh();
var positions = src.VertexBuffer.Positions.AsNativeArray<Vector3>(Allocator.TempJob);
var normals = src.VertexBuffer.Normals?.AsNativeArray<Vector3>(Allocator.TempJob) ?? default;
var texCoords = src.VertexBuffer.TexCoords?.AsNativeArray<Vector2>(Allocator.TempJob) ?? default;
var colors = src.VertexBuffer.Colors?.AsNativeArray<Color>(Allocator.TempJob) ?? default;
var weights = src.VertexBuffer.Weights?.AsNativeArray<Vector4>(Allocator.TempJob) ?? default;
var joints = src.VertexBuffer.Joints?.AsNativeArray<SkinJoints>(Allocator.TempJob) ?? default;
var positions = src.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = src.VertexBuffer.Normals?.Bytes.Reinterpret<Vector3>(1) ?? default;
var texCoords = src.VertexBuffer.TexCoords?.Bytes.Reinterpret<Vector2>(1) ?? default;
var colors = src.VertexBuffer.Colors?.Bytes.Reinterpret<Color>(1) ?? default;
var weights = src.VertexBuffer.Weights?.Bytes.Reinterpret<Vector4>(1) ?? default;
var joints = src.VertexBuffer.Joints?.Bytes.Reinterpret<SkinJoints>(1) ?? default;
using (var vertices = new NativeArray<MeshVertex>(positions.Length, Allocator.TempJob))
{
@@ -55,14 +55,6 @@ namespace UniVRM10
// Jobを完了
jobHandle.Complete();
// 入力のNativeArrayを開放
positions.Dispose();
if (normals.IsCreated) normals.Dispose();
if (texCoords.IsCreated) texCoords.Dispose();
if (colors.IsCreated) colors.Dispose();
if (weights.IsCreated) weights.Dispose();
if (joints.IsCreated) joints.Dispose();
// 頂点を更新
MeshVertex.SetVertexBufferParamsToMesh(mesh, vertices.Length);
mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);
@@ -74,16 +66,14 @@ namespace UniVRM10
switch (src.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
var shortIndices = src.IndexBuffer.AsNativeArray<ushort>(Allocator.Temp);
var shortIndices = src.IndexBuffer.Bytes.Reinterpret<ushort>(1);
mesh.SetIndexBufferParams(shortIndices.Length, IndexFormat.UInt16);
mesh.SetIndexBufferData(shortIndices, 0, 0, shortIndices.Length);
shortIndices.Dispose();
break;
case AccessorValueType.UNSIGNED_INT:
var intIndices = src.IndexBuffer.AsNativeArray<uint>(Allocator.Temp);
var intIndices = src.IndexBuffer.Bytes.Reinterpret<uint>(1);
mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32);
mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length);
intIndices.Dispose();
break;
default:
throw new NotImplementedException();

View File

@@ -126,8 +126,7 @@ namespace UniVRM10
case AccessorValueType.SHORT:
{
// unsigned short -> unsigned short
var source = mesh.IndexBuffer.AsNativeArray<ushort>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Ushort(
(ushort)vertexOffset,
new NativeSlice<ushort>(source),
@@ -138,8 +137,7 @@ namespace UniVRM10
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned short
var source = mesh.IndexBuffer.AsNativeArray<uint>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.Uint2Ushort(
(ushort)vertexOffset,
source,
@@ -173,8 +171,7 @@ namespace UniVRM10
case AccessorValueType.SHORT:
{
// unsigned short -> unsigned int
var source = mesh.IndexBuffer.AsNativeArray<ushort>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Uint(
(uint)vertexOffset,
source,
@@ -185,8 +182,7 @@ namespace UniVRM10
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned int
var source = mesh.IndexBuffer.AsNativeArray<uint>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.UInt2UInt(
(uint)vertexOffset,
source,
@@ -237,20 +233,15 @@ namespace UniVRM10
foreach (var mesh in meshGroup.Meshes)
{
var positions = mesh.VertexBuffer.Positions.AsNativeArray<Vector3>(Allocator.TempJob);
var normals = mesh.VertexBuffer.Normals.AsNativeArray<Vector3>(Allocator.TempJob);
var texCoords = mesh.VertexBuffer.TexCoords.AsNativeArray<Vector2>(Allocator.TempJob);
var positions = mesh.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = mesh.VertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1);
var texCoords = mesh.VertexBuffer.TexCoords.Bytes.Reinterpret<Vector2>(1);
var weights = meshGroup.Skin != null
? mesh.VertexBuffer.Weights.AsNativeArray<Vector4>(Allocator.TempJob)
? mesh.VertexBuffer.Weights.Bytes.Reinterpret<Vector4>(1)
: default;
var joints = meshGroup.Skin != null
? mesh.VertexBuffer.Joints.AsNativeArray<SkinJoints>(Allocator.TempJob)
? mesh.VertexBuffer.Joints.Bytes.Reinterpret<SkinJoints>(1)
: default;
if (positions.IsCreated) disposables.Add(positions);
if (normals.IsCreated) disposables.Add(normals);
if (texCoords.IsCreated) disposables.Add(texCoords);
if (weights.IsCreated) disposables.Add(weights);
if (joints.IsCreated) disposables.Add(joints);
interleaveVertexJob = new InterleaveMeshVerticesJob(
new NativeSlice<MeshVertex>(vertices, indexOffset, mesh.VertexBuffer.Count),

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using UniGLTF;
using Unity.Collections;
using VrmLib;
namespace UniVRM10
@@ -26,33 +27,33 @@ namespace UniVRM10
accessor.max = max.ToFloat3();
}
static int ExportIndices(ExportingGltfData data, BufferAccessor x, int offset, int count, ExportArgs option)
{
if (x.Count <= ushort.MaxValue)
{
if (x.ComponentType == AccessorValueType.UNSIGNED_INT)
{
// ensure ushort
var src = x.GetSpan<UInt32>().Slice(offset, count);
var bytes = new byte[src.Length * 2];
var dst = SpanLike.Wrap<UInt16>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (ushort)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.SCALAR, count);
return accessor.AddAccessorTo(data, 0, option.sparse, null, 0, count);
}
else
{
return x.AddAccessorTo(data, 0, option.sparse, null, offset, count);
}
}
else
{
return x.AddAccessorTo(data, 0, option.sparse, null, offset, count);
}
}
// static int ExportIndices(ExportingGltfData data, BufferAccessor x, int offset, int count, ExportArgs option)
// {
// if (x.Count <= ushort.MaxValue)
// {
// if (x.ComponentType == AccessorValueType.UNSIGNED_INT)
// {
// // ensure ushort
// var src = x.GetSpan<UInt32>().Slice(offset, count);
// var bytes = new byte[src.Length * 2];
// var dst = SpanLike.Wrap<UInt16>(new ArraySegment<byte>(bytes));
// for (int i = 0; i < src.Length; ++i)
// {
// dst[i] = (ushort)src[i];
// }
// var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.SCALAR, count);
// return accessor.AddAccessorTo(data, 0, option.sparse, null, 0, count);
// }
// else
// {
// return x.AddAccessorTo(data, 0, option.sparse, null, offset, count);
// }
// }
// else
// {
// return x.AddAccessorTo(data, 0, option.sparse, null, offset, count);
// }
// }
/// <summary>
/// https://github.com/vrm-c/UniVRM/issues/800
@@ -69,7 +70,7 @@ namespace UniVRM10
ExportingGltfData writer, ExportArgs option)
{
var usedIndices = new List<int>();
var meshIndices = SpanLike.CopyFrom(mesh.IndexBuffer.GetAsIntArray());
var meshIndices = mesh.IndexBuffer.GetAsIntArray();
var positions = mesh.VertexBuffer.Positions.GetSpan<UnityEngine.Vector3>().ToArray();
var normals = mesh.VertexBuffer.Normals.GetSpan<UnityEngine.Vector3>().ToArray();
var uv = mesh.VertexBuffer.TexCoords.GetSpan<UnityEngine.Vector2>().ToArray();
@@ -87,7 +88,7 @@ namespace UniVRM10
foreach (var submesh in mesh.Submeshes)
{
var indices = meshIndices.Slice(submesh.Offset, submesh.DrawCount).ToArray();
var indices = meshIndices.GetSubArray(submesh.Offset, submesh.DrawCount).ToArray();
var hash = new HashSet<int>(indices);
// mesh
@@ -131,7 +132,7 @@ namespace UniVRM10
// index の順に attributes を蓄える
var morph = mesh.MorphTargets[j];
var blendShapePositions = morph.VertexBuffer.Positions.GetSpan<UnityEngine.Vector3>();
SpanLike<UnityEngine.Vector3>? blendShapeNormals = default;
NativeArray<UnityEngine.Vector3>? blendShapeNormals = default;
if (morph.VertexBuffer.Normals != null)
{
blendShapeNormals = morph.VertexBuffer.Normals.GetSpan<UnityEngine.Vector3>();

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UniGLTF;
using Unity.Collections;
using UnityEngine;
using VrmLib;
@@ -23,11 +25,11 @@ namespace UniVRM10
/// </summary>
/// <param name="root"></param>
/// <returns></returns>
public VrmLib.Model Export(GameObject root)
public VrmLib.Model Export(NativeArrayManager arrayManager, GameObject root)
{
Model = new VrmLib.Model(VrmLib.Coordinates.Unity);
_Export(root);
_Export(arrayManager, root);
// humanoid
{
@@ -51,7 +53,7 @@ namespace UniVRM10
return Model;
}
VrmLib.Model _Export(GameObject root)
VrmLib.Model _Export(NativeArrayManager arrayManager, GameObject root)
{
if (Model == null)
{
@@ -94,8 +96,8 @@ namespace UniVRM10
{
if (skinnedMeshRenderer.sharedMesh != null)
{
var mesh = CreateMesh(skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials);
var skin = CreateSkin(skinnedMeshRenderer, Nodes, root);
var mesh = CreateMesh(arrayManager, skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials);
var skin = CreateSkin(arrayManager, skinnedMeshRenderer, Nodes, root);
if (skin != null)
{
// blendshape only で skinning が無いやつがある
@@ -112,7 +114,7 @@ namespace UniVRM10
var filter = meshRenderer.gameObject.GetComponent<MeshFilter>();
if (filter != null && filter.sharedMesh != null)
{
var mesh = CreateMesh(filter.sharedMesh, meshRenderer, Materials);
var mesh = CreateMesh(arrayManager, filter.sharedMesh, meshRenderer, Materials);
Model.MeshGroups.Add(mesh);
Nodes[renderer.gameObject].MeshGroup = mesh;
if (!Meshes.ContainsKey(filter.sharedMesh))
@@ -167,30 +169,30 @@ namespace UniVRM10
return null;
}
private static VrmLib.MeshGroup CreateMesh(UnityEngine.Mesh mesh, Renderer renderer, List<UnityEngine.Material> materials)
private static VrmLib.MeshGroup CreateMesh(NativeArrayManager arrayManager, UnityEngine.Mesh mesh, Renderer renderer, List<UnityEngine.Material> materials)
{
var meshGroup = new VrmLib.MeshGroup(mesh.name);
var vrmMesh = new VrmLib.Mesh();
vrmMesh.VertexBuffer = new VrmLib.VertexBuffer();
vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(mesh.vertices));
vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, mesh.vertices));
if (mesh.boneWeights.Length == mesh.vertexCount)
{
vrmMesh.VertexBuffer.Add(
VrmLib.VertexBuffer.WeightKey,
ToBufferAccessor(mesh.boneWeights.Select(x =>
ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x =>
new Vector4(x.weight0, x.weight1, x.weight2, x.weight3)).ToArray()
));
vrmMesh.VertexBuffer.Add(
VrmLib.VertexBuffer.JointKey,
ToBufferAccessor(mesh.boneWeights.Select(x =>
ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x =>
new SkinJoints((ushort)x.boneIndex0, (ushort)x.boneIndex1, (ushort)x.boneIndex2, (ushort)x.boneIndex3)).ToArray()
));
}
if (mesh.uv.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(mesh.uv));
if (mesh.normals.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(mesh.normals));
if (mesh.colors.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(mesh.colors));
vrmMesh.IndexBuffer = ToBufferAccessor(mesh.triangles);
if (mesh.uv.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(arrayManager, mesh.uv));
if (mesh.normals.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(arrayManager, mesh.normals));
if (mesh.colors.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(arrayManager, mesh.colors));
vrmMesh.IndexBuffer = ToBufferAccessor(arrayManager, mesh.triangles);
int offset = 0;
for (int i = 0; i < mesh.subMeshCount; i++)
@@ -240,7 +242,7 @@ namespace UniVRM10
{
var morphTarget = new VrmLib.MorphTarget(mesh.GetBlendShapeName(i));
morphTarget.VertexBuffer = new VrmLib.VertexBuffer();
morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(blendShapeVertices));
morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, blendShapeVertices));
vrmMesh.MorphTargets.Add(morphTarget);
}
}
@@ -249,7 +251,7 @@ namespace UniVRM10
return meshGroup;
}
private static VrmLib.Skin CreateSkin(
private static VrmLib.Skin CreateSkin(NativeArrayManager arrayManager,
SkinnedMeshRenderer skinnedMeshRenderer,
Dictionary<GameObject, VrmLib.Node> nodes,
GameObject root)
@@ -260,7 +262,7 @@ namespace UniVRM10
}
var skin = new VrmLib.Skin();
skin.InverseMatrices = ToBufferAccessor(skinnedMeshRenderer.sharedMesh.bindposes);
skin.InverseMatrices = ToBufferAccessor(arrayManager, skinnedMeshRenderer.sharedMesh.bindposes);
if (skinnedMeshRenderer.rootBone != null)
{
skin.Root = nodes[skinnedMeshRenderer.rootBone.gameObject];
@@ -270,46 +272,45 @@ namespace UniVRM10
return skin;
}
private static VrmLib.BufferAccessor ToBufferAccessor(SkinJoints[] values)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, SkinJoints[] values)
{
return ToBufferAccessor(values, VrmLib.AccessorValueType.UNSIGNED_SHORT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, values, VrmLib.AccessorValueType.UNSIGNED_SHORT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Color[] colors)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, Color[] colors)
{
return ToBufferAccessor(colors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, colors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector4[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, Vector4[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector3[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, Vector3[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC3);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC3);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector2[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, Vector2[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC2);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC2);
}
private static VrmLib.BufferAccessor ToBufferAccessor(int[] scalars)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, int[] scalars)
{
return ToBufferAccessor(scalars, VrmLib.AccessorValueType.UNSIGNED_INT, VrmLib.AccessorVectorType.SCALAR);
return ToBufferAccessor(arrayManager, scalars, VrmLib.AccessorValueType.UNSIGNED_INT, VrmLib.AccessorVectorType.SCALAR);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Matrix4x4[] matrixes)
private static VrmLib.BufferAccessor ToBufferAccessor(NativeArrayManager arrayManager, Matrix4x4[] matrixes)
{
return ToBufferAccessor(matrixes, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.MAT4);
return ToBufferAccessor(arrayManager, matrixes, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.MAT4);
}
private static VrmLib.BufferAccessor ToBufferAccessor<T>(T[] value, VrmLib.AccessorValueType valueType, VrmLib.AccessorVectorType vectorType) where T : struct
private static VrmLib.BufferAccessor ToBufferAccessor<T>(NativeArrayManager arrayManager, T[] value, VrmLib.AccessorValueType valueType, VrmLib.AccessorVectorType vectorType) where T : struct
{
var span = SpanLike.CopyFrom(value);
return new VrmLib.BufferAccessor(
span.Bytes,
return new VrmLib.BufferAccessor(arrayManager,
arrayManager.CreateNativeArray(value).Reinterpret<byte>(Marshal.SizeOf<T>()),
valueType,
vectorType,
value.Length

View File

@@ -70,7 +70,7 @@ namespace UniVRM10
}
}
public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(List<Node> nodes, List<MeshGroup> groups, ExportingGltfData data, ExportArgs option)
public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(NativeArrayManager arrayManager, List<Node> nodes, List<MeshGroup> groups, ExportingGltfData data, ExportArgs option)
{
foreach (var node in nodes)
{
@@ -96,7 +96,7 @@ namespace UniVRM10
};
if (skin.InverseMatrices == null)
{
skin.CalcInverseMatrices();
skin.CalcInverseMatrices(arrayManager);
}
if (skin.InverseMatrices != null)
{
@@ -180,14 +180,17 @@ namespace UniVRM10
Storage.Gltf.meshes.Add(mesh);
}
foreach (var (node, skin) in ExportNodes(model.Nodes, model.MeshGroups, Storage, option))
using (var arrayManager = new NativeArrayManager())
{
Storage.Gltf.nodes.Add(node);
if (skin != null)
foreach (var (node, skin) in ExportNodes(arrayManager, model.Nodes, model.MeshGroups, Storage, option))
{
var skinIndex = Storage.Gltf.skins.Count;
Storage.Gltf.skins.Add(skin);
node.skin = skinIndex;
Storage.Gltf.nodes.Add(node);
if (skin != null)
{
var skinIndex = Storage.Gltf.skins.Count;
Storage.Gltf.skins.Add(skin);
node.skin = skinIndex;
}
}
}
Storage.Gltf.scenes.Add(new gltfScene()
@@ -343,7 +346,8 @@ namespace UniVRM10
colliders.Length == 0 &&
controller.SpringBone.ColliderGroups.Count == 0 &&
controller.SpringBone.Springs.Count == 0
) {
)
{
return null;
}
@@ -803,20 +807,23 @@ namespace UniVRM10
/// <returns></returns>
public static byte[] Export(GameObject go, ITextureSerializer textureSerializer = null)
{
// ヒエラルキーからジオメトリーを収集
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(go);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs
using (var arrayManager = new NativeArrayManager())
{
};
exporter10.Export(go, model, converter, option);
return exporter10.Storage.ToGlbBytes();
// ヒエラルキーからジオメトリーを収集
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(arrayManager, go);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs
{
};
exporter10.Export(go, model, converter, option);
return exporter10.Storage.ToGlbBytes();
}
}
}
}

View File

@@ -202,7 +202,7 @@ namespace UniVRM10
var accessor = Gltf.accessors[accessorIndex];
var bytes = GetAccessorBytes(accessorIndex);
var vectorType = EnumUtil.Parse<AccessorVectorType>(accessor.type);
ba = new BufferAccessor(new ArraySegment<byte>(bytes.ToArray()),
ba = new BufferAccessor(m_data.NativeArrayManager, bytes,
(AccessorValueType)accessor.componentType, vectorType, accessor.count);
return true;
}
@@ -275,7 +275,7 @@ namespace UniVRM10
var buffer = Gltf.buffers[firstViewBufferIndex];
var bin = GetBufferBytes(buffer);
var bytes = bin.GetSubArray(start, totalCount * firstAccessor.GetStride());
return new BufferAccessor(new ArraySegment<byte>(bytes.ToArray()),
return new BufferAccessor(m_data.NativeArrayManager, bytes,
(AccessorValueType)firstAccessor.componentType,
EnumUtil.Parse<AccessorVectorType>(firstAccessor.type),
totalCount);
@@ -339,7 +339,7 @@ namespace UniVRM10
throw new NotImplementedException($"accessor.componentType: {accessor.componentType}");
}
}
return new BufferAccessor(new ArraySegment<byte>(indices.ToArray()), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount);
return new BufferAccessor(m_data.NativeArrayManager, indices, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount);
}
}
}

View File

@@ -80,7 +80,7 @@ namespace UniVRM10
if (m_doNormalize)
{
var result = m_model.SkinningBake();
var result = m_model.SkinningBake(Data.NativeArrayManager);
Debug.Log($"SkinningBake: {result}");
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UniGLTF;
using Unity.Collections;
using UnityEngine;
namespace UniVRM10
@@ -23,7 +25,7 @@ namespace UniVRM10
_buffer = new ArrayByteBuffer(new byte[data.Bin.Length]);
}
int AddBuffer(ArraySegment<byte> bytes)
int AddBuffer(NativeArray<byte> bytes)
{
var bufferView = _buffer.Extend(bytes);
var index = _bufferViews.Count;
@@ -31,9 +33,9 @@ namespace UniVRM10
return index;
}
int AddAccessor<T>(SpanLike<T> span) where T : struct
int AddAccessor<T>(NativeArray<T> span) where T : struct
{
var bufferViewIndex = AddBuffer(span.Bytes);
var bufferViewIndex = AddBuffer(span.Reinterpret<byte>(Marshal.SizeOf<T>()));
var accessor = new glTFAccessor
{
bufferView = bufferViewIndex,
@@ -70,24 +72,20 @@ namespace UniVRM10
foreach (var image in gltf.images)
{
var bytes = _data.GetBytesFromBufferView(image.bufferView);
image.bufferView = AddBuffer(new ArraySegment<byte>(bytes.ToArray()));
image.bufferView = AddBuffer(bytes);
}
// update Mesh
foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0])))
{
SpanLike<uint> indices;
NativeArray<uint> indices;
switch (mesh.IndexBuffer.Stride)
{
case 1:
{
// byte
var byte_indices = mesh.IndexBuffer.GetSpan<byte>();
indices = SpanLike.Create<uint>(byte_indices.Length);
for (int i = 0; i < byte_indices.Length; ++i)
{
indices[i] = byte_indices[i];
}
indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x);
break;
}
@@ -95,11 +93,7 @@ namespace UniVRM10
{
// ushort
var ushort_indices = mesh.IndexBuffer.GetSpan<ushort>();
indices = SpanLike.Create<uint>(ushort_indices.Length);
for (int i = 0; i < ushort_indices.Length; ++i)
{
indices[i] = ushort_indices[i];
}
indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x);
break;
}
@@ -132,7 +126,7 @@ namespace UniVRM10
foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r)))
{
var subIndices = indices.Slice(submesh.Offset, submesh.DrawCount);
var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount);
gltfPrim.indices = AddAccessor(subIndices);
gltfPrim.attributes.POSITION = position.Value;
gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
@@ -178,7 +172,8 @@ namespace UniVRM10
gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan<Matrix4x4>());
gltf.skins.Add(gltfSkin);
}
else{
else
{
// multi nodes sharing a same skin may be error ?
// edge case.
}

View File

@@ -31,7 +31,7 @@ namespace UniVRM10.Test
private (GameObject, IReadOnlyList<VRMShaders.MaterialFactory.MaterialLoadInfo>) ToUnity(byte[] bytes)
{
// Vrm => Model
using(var data = new GlbBinaryParser(bytes, "tmp.vrm").Parse())
using (var data = new GlbBinaryParser(bytes, "tmp.vrm").Parse())
using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data result, out MigrationData migration))
{
if (result == null)
@@ -54,11 +54,14 @@ namespace UniVRM10.Test
private Model ToVrmModel(GameObject root)
{
var exporter = new UniVRM10.ModelExporter();
var model = exporter.Export(root);
using (var arrayManager = new NativeArrayManager())
{
var exporter = new UniVRM10.ModelExporter();
var model = exporter.Export(arrayManager, root);
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
return model;
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
return model;
}
}
void EqualColor(Color color1, Color color2)

View File

@@ -128,7 +128,7 @@ namespace VrmLib
{
get
{
var span = SpanLike.Wrap<Single>(Rotation.In.Bytes);
var span = Rotation.In.Bytes.Reinterpret<Single>(1);
if (Index < span.Length)
{
return span[Index];
@@ -219,107 +219,107 @@ namespace VrmLib
}
}
/// <summary>
/// モーションの基本姿勢を basePose ベースに再計算する
///
/// basePose は Humanoid.CopyNodes が必用 !
/// </summary>
public Animation RebaseAnimation(Humanoid basePose)
{
var map = NodeMap.ToDictionary(kv => kv.Key, kv => new List<Quaternion>());
var hipsPositions = new List<Vector3>();
// /// <summary>
// /// モーションの基本姿勢を basePose ベースに再計算する
// ///
// /// basePose は Humanoid.CopyNodes が必用 !
// /// </summary>
// public Animation RebaseAnimation(Humanoid basePose)
// {
// var map = NodeMap.ToDictionary(kv => kv.Key, kv => new List<Quaternion>());
// var hipsPositions = new List<Vector3>();
foreach (var (seconds, keyframes) in KeyFramesGroupBySeconds())
{
// モーション適用
SetTime(seconds);
Root.CalcWorldMatrix();
// foreach (var (seconds, keyframes) in KeyFramesGroupBySeconds())
// {
// // モーション適用
// SetTime(seconds);
// Root.CalcWorldMatrix();
foreach (var keyframe in keyframes)
{
if (!keyframe.Node.HumanoidBone.HasValue
|| keyframe.Node.HumanoidBone.Value == HumanoidBones.unknown)
{
continue;
}
// foreach (var keyframe in keyframes)
// {
// if (!keyframe.Node.HumanoidBone.HasValue
// || keyframe.Node.HumanoidBone.Value == HumanoidBones.unknown)
// {
// continue;
// }
// ローカル回転を算出する
var t = basePose[keyframe.Node].Rotation;
var w = keyframe.Node.Rotation;
var w_from_t = w * Quaternion.Inverse(t);
// // ローカル回転を算出する
// var t = basePose[keyframe.Node].Rotation;
// var w = keyframe.Node.Rotation;
// var w_from_t = w * Quaternion.Inverse(t);
// parent
var key = keyframe.Node.HumanoidBone.Value;
var curve = map[keyframe.Node];
if (key != HumanoidBones.hips)
{
if (basePose[key].Parent == null)
{
throw new Exception();
}
var parent_t = basePose[key].Parent.Rotation;
var parent_w = keyframe.Node.Parent.Rotation;
var parent_w_from_t = parent_w * Quaternion.Inverse(parent_t);
// // parent
// var key = keyframe.Node.HumanoidBone.Value;
// var curve = map[keyframe.Node];
// if (key != HumanoidBones.hips)
// {
// if (basePose[key].Parent == null)
// {
// throw new Exception();
// }
// var parent_t = basePose[key].Parent.Rotation;
// var parent_w = keyframe.Node.Parent.Rotation;
// var parent_w_from_t = parent_w * Quaternion.Inverse(parent_t);
var r = Quaternion.Inverse(parent_w_from_t) * w_from_t;
curve.Add(r);
}
else
{
// hips
curve.Add(w_from_t);
hipsPositions.Add(keyframe.Node.Translation);
}
}
}
// var r = Quaternion.Inverse(parent_w_from_t) * w_from_t;
// curve.Add(r);
// }
// else
// {
// // hips
// curve.Add(w_from_t);
// hipsPositions.Add(keyframe.Node.Translation);
// }
// }
// }
var dst = new Animation(Name + ".tpose");
foreach (var kv in map)
{
if (!kv.Value.Any())
{
continue;
}
// var dst = new Animation(Name + ".tpose");
// foreach (var kv in map)
// {
// if (!kv.Value.Any())
// {
// continue;
// }
var bone = kv.Key.HumanoidBone.Value;
// var bone = kv.Key.HumanoidBone.Value;
var inCurve = NodeMap[kv.Key].Curves[AnimationPathType.Rotation].In;
if (inCurve.Count != kv.Value.Count)
{
throw new Exception();
}
// var inCurve = NodeMap[kv.Key].Curves[AnimationPathType.Rotation].In;
// if (inCurve.Count != kv.Value.Count)
// {
// throw new Exception();
// }
var nodeAnimation = new NodeAnimation();
nodeAnimation.Curves.Add(AnimationPathType.Rotation, new CurveSampler
{
In = inCurve,
Out = BufferAccessor.Create(kv.Value.ToArray()),
});
if (bone == HumanoidBones.hips)
{
nodeAnimation.Curves.Add(AnimationPathType.Translation, new CurveSampler
{
In = inCurve,
Out = BufferAccessor.Create(hipsPositions.ToArray()),
});
}
dst.AddCurve(kv.Key, nodeAnimation);
}
return dst;
}
// var nodeAnimation = new NodeAnimation();
// nodeAnimation.Curves.Add(AnimationPathType.Rotation, new CurveSampler
// {
// In = inCurve,
// Out = BufferAccessor.Create(kv.Value.ToArray()),
// });
// if (bone == HumanoidBones.hips)
// {
// nodeAnimation.Curves.Add(AnimationPathType.Translation, new CurveSampler
// {
// In = inCurve,
// Out = BufferAccessor.Create(hipsPositions.ToArray()),
// });
// }
// dst.AddCurve(kv.Key, nodeAnimation);
// }
// return dst;
// }
/// <summary>
/// 指定された数のフレームを先頭から取り除く
/// </summary>
public void SkipFrame(int skipFrames)
{
foreach (var kv in NodeMap)
{
foreach (var curve in kv.Value.Curves)
{
curve.Value.SkipFrame(skipFrames);
}
}
}
// /// <summary>
// /// 指定された数のフレームを先頭から取り除く
// /// </summary>
// public void SkipFrame(int skipFrames)
// {
// foreach (var kv in NodeMap)
// {
// foreach (var curve in kv.Value.Curves)
// {
// curve.Value.SkipFrame(skipFrames);
// }
// }
// }
}
}

View File

@@ -79,7 +79,9 @@ namespace VrmLib
public class BufferAccessor
{
public ArraySegment<byte> Bytes;
public NativeArrayManager ArrayManager { get; }
public NativeArray<byte> Bytes;
public AccessorValueType ComponentType;
@@ -91,19 +93,20 @@ namespace VrmLib
public int ByteLength => Stride * Count;
public BufferAccessor(ArraySegment<byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count)
public BufferAccessor(NativeArrayManager arrayManager, NativeArray<byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count)
{
ArrayManager = arrayManager;
Bytes = bytes;
ComponentType = componentType;
AccessorType = accessorType;
Count = count;
}
public static BufferAccessor Create<T>(T[] list) where T : struct
public static BufferAccessor Create<T>(NativeArrayManager arrayManager, T[] list) where T : struct
{
var t = typeof(T);
var bytes = new byte[list.Length * Marshal.SizeOf(t)];
var span = SpanLike.Wrap<T>(new ArraySegment<byte>(bytes));
var bytes = arrayManager.CreateNativeArray<byte>(list.Length * Marshal.SizeOf(t));
var span = bytes.Reinterpret<T>(1);
for (int i = 0; i < list.Length; ++i)
{
span[i] = list[i];
@@ -144,8 +147,7 @@ namespace VrmLib
{
throw new NotImplementedException();
}
return new BufferAccessor(
new ArraySegment<byte>(bytes), componentType, accessorType, list.Length);
return new BufferAccessor(arrayManager, bytes, componentType, accessorType, list.Length);
}
public override string ToString()
@@ -153,58 +155,56 @@ namespace VrmLib
return $"{Stride}stride x{Count}";
}
public SpanLike<T> GetSpan<T>(bool checkStride = true) where T : struct
public NativeArray<T> GetSpan<T>(bool checkStride = true) where T : struct
{
if (checkStride && Marshal.SizeOf(typeof(T)) != Stride)
{
throw new Exception("different sizeof(T) with stride");
}
return SpanLike.Wrap<T>(Bytes);
return Bytes.Reinterpret<T>(1);
}
/// <summary>
/// バッファをNativeArrayに変換して返す
/// 開放の責務は使い手側にある点に注意
/// </summary>
public unsafe NativeArray<T> AsNativeArray<T>(Allocator allocator) where T : struct
{
if (Stride == Marshal.SizeOf(typeof(T)))
{
fixed (byte* byteArray = Bytes.Array)
{
var nativeArray = new NativeArray<T>(Bytes.Count / Marshal.SizeOf<T>(), allocator);
UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), byteArray + Bytes.Offset, Bytes.Count);
return nativeArray;
}
}
else
{
if (typeof(T) == typeof(SkinJoints) && Stride == 4)
{
// 例えば SkinJoints を使う JOINTS_0 は UNSIGNED_BYTE と UNSIGNED_SHORT の2種類がありえる。
fixed (UShort4* p = GetAsUShort4())
{
var nativeArray = new NativeArray<T>(Count, allocator);
UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), p, Bytes.Count);
return nativeArray;
}
}
else
{
throw new Exception($"Stride:{Stride}!= sizeof({typeof(T).Name}:{Marshal.SizeOf(typeof(T))}");
}
}
}
// /// <summary>
// /// バッファをNativeArrayに変換して返す
// /// 開放の責務は使い手側にある点に注意
// /// </summary>
// public unsafe NativeArray<T> AsNativeArray<T>(Allocator allocator) where T : struct
// {
// if (Stride == Marshal.SizeOf(typeof(T)))
// {
// fixed (byte* byteArray = Bytes.Array)
// {
// var nativeArray = new NativeArray<T>(Bytes.Count / Marshal.SizeOf<T>(), allocator);
// UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), byteArray + Bytes.Offset, Bytes.Count);
// return nativeArray;
// }
// }
// else
// {
// if (typeof(T) == typeof(SkinJoints) && Stride == 4)
// {
// // 例えば SkinJoints を使う JOINTS_0 は UNSIGNED_BYTE と UNSIGNED_SHORT の2種類がありえる。
// fixed (UShort4* p = GetAsUShort4())
// {
// var nativeArray = new NativeArray<T>(Count, allocator);
// UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), p, Bytes.Count);
// return nativeArray;
// }
// }
// else
// {
// throw new Exception($"Stride:{Stride}!= sizeof({typeof(T).Name}:{Marshal.SizeOf(typeof(T))}");
// }
// }
// }
/// <summary>
/// バッファをNativeSliceへと書き込む
/// </summary>
public unsafe void CopyToNativeSlice<T>(NativeSlice<T> destArray) where T : unmanaged
{
fixed (byte* byteArray = Bytes.Array)
{
UnsafeUtility.MemCpy((T*)destArray.GetUnsafePtr(), byteArray + Bytes.Offset, Bytes.Count);
}
var byteArray = NativeArrayUnsafeUtility.GetUnsafePtr(Bytes);
UnsafeUtility.MemCpy((T*)destArray.GetUnsafePtr(), byteArray, Bytes.Length);
}
public void Assign<T>(T[] values) where T : struct
@@ -213,24 +213,24 @@ namespace VrmLib
{
throw new Exception("invalid element size");
}
var array = new byte[Stride * values.Length];
Bytes = new ArraySegment<byte>(array);
values.ToBytes(Bytes);
Bytes = ArrayManager.CreateNativeArray<byte>(Stride * values.Length);
Count = values.Length;
Bytes.Reinterpret<T>(1).CopyFrom(values);
}
public void Assign<T>(SpanLike<T> values) where T : struct
public void Assign<T>(NativeArray<T> values) where T : struct
{
if (Marshal.SizeOf(typeof(T)) != Stride)
{
throw new Exception("invalid element size");
}
Bytes = values.Bytes;
Bytes = ArrayManager.CreateNativeArray<byte>(Marshal.SizeOf<T>() * values.Length);
NativeArray<T>.Copy(values, Bytes.Reinterpret<T>(1));
Count = values.Length;
}
// for index buffer
public void AssignAsShort(SpanLike<int> values)
public void AssignAsShort(NativeArray<int> values)
{
if (AccessorType != AccessorVectorType.SCALAR)
{
@@ -238,17 +238,12 @@ namespace VrmLib
}
ComponentType = AccessorValueType.UNSIGNED_SHORT;
Bytes = new ArraySegment<byte>(new byte[Stride * values.Length]);
var span = GetSpan<ushort>();
Bytes = ArrayManager.Convert(values, (int x) => (ushort)x).Reinterpret<Byte>(Marshal.SizeOf<ushort>());
Count = values.Length;
for (int i = 0; i < values.Length; ++i)
{
span[i] = (ushort)values[i];
}
}
// Index用
public int[] GetAsIntArray()
public NativeArray<int> GetAsIntArray()
{
if (AccessorType != AccessorVectorType.SCALAR)
{
@@ -257,109 +252,101 @@ namespace VrmLib
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes);
var array = new int[span.Length];
for (int i = 0; i < span.Length; ++i)
{
array[i] = span[i];
}
return array;
}
return ArrayManager.Convert(Bytes.Reinterpret<ushort>(1), (ushort x) => (int)x);
case AccessorValueType.UNSIGNED_INT:
return SpanLike.Wrap<Int32>(Bytes).ToArray();
return Bytes.Reinterpret<Int32>(1);
default:
throw new NotImplementedException();
}
}
public List<int> GetAsIntList()
{
if (AccessorType != AccessorVectorType.SCALAR)
{
throw new InvalidOperationException("not scalar");
}
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes);
var array = new List<int>(Count);
if (span.Length != Count)
{
for (int i = 0; i < Count; ++i)
{
array.Add(span[i]);
}
}
else
{
// Spanが動かないWorkAround
var bytes = Bytes.ToArray();
var offset = 0;
for (int i = 0; i < Count; ++i)
{
array.Add(BitConverter.ToUInt16(bytes, offset));
offset += 2;
}
}
return array;
}
// public List<int> GetAsIntList()
// {
// if (AccessorType != AccessorVectorType.SCALAR)
// {
// throw new InvalidOperationException("not scalar");
// }
// switch (ComponentType)
// {
// case AccessorValueType.UNSIGNED_SHORT:
// {
// var span = SpanLike.Wrap<UInt16>(Bytes);
// var array = new List<int>(Count);
// if (span.Length != Count)
// {
// for (int i = 0; i < Count; ++i)
// {
// array.Add(span[i]);
// }
// }
// else
// {
// // Spanが動かないWorkAround
// var bytes = Bytes.ToArray();
// var offset = 0;
// for (int i = 0; i < Count; ++i)
// {
// array.Add(BitConverter.ToUInt16(bytes, offset));
// offset += 2;
// }
// }
// return array;
// }
case AccessorValueType.UNSIGNED_INT:
return SpanLike.Wrap<Int32>(Bytes).ToArray().ToList();
// case AccessorValueType.UNSIGNED_INT:
// return SpanLike.Wrap<Int32>(Bytes).ToArray().ToList();
default:
throw new NotImplementedException();
}
}
// default:
// throw new NotImplementedException();
// }
// }
// Joints用
public UShort4[] GetAsUShort4()
{
if (AccessorType != AccessorVectorType.VEC4)
{
throw new InvalidOperationException("not vec4");
}
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
return SpanLike.Wrap<UShort4>(Bytes).ToArray();
// // Joints用
// public UShort4[] GetAsUShort4()
// {
// if (AccessorType != AccessorVectorType.VEC4)
// {
// throw new InvalidOperationException("not vec4");
// }
// switch (ComponentType)
// {
// case AccessorValueType.UNSIGNED_SHORT:
// return SpanLike.Wrap<UShort4>(Bytes).ToArray();
case AccessorValueType.UNSIGNED_BYTE:
{
var array = new UShort4[Count];
var span = SpanLike.Wrap<Byte4>(Bytes);
for (int i = 0; i < span.Length; ++i)
{
array[i] = new UShort4(span[i].x, span[i].y, span[i].z, span[i].w);
}
return array;
}
// case AccessorValueType.UNSIGNED_BYTE:
// {
// var array = new UShort4[Count];
// var span = SpanLike.Wrap<Byte4>(Bytes);
// for (int i = 0; i < span.Length; ++i)
// {
// array[i] = new UShort4(span[i].x, span[i].y, span[i].z, span[i].w);
// }
// return array;
// }
default:
throw new NotImplementedException();
}
}
// default:
// throw new NotImplementedException();
// }
// }
// Weigt用
public Vector4[] GetAsVector4()
{
if (AccessorType != AccessorVectorType.VEC4)
{
throw new InvalidOperationException("not vec4");
}
switch (ComponentType)
{
case AccessorValueType.FLOAT:
return SpanLike.Wrap<Vector4>(Bytes).ToArray();
// // Weigt用
// public Vector4[] GetAsVector4()
// {
// if (AccessorType != AccessorVectorType.VEC4)
// {
// throw new InvalidOperationException("not vec4");
// }
// switch (ComponentType)
// {
// case AccessorValueType.FLOAT:
// return SpanLike.Wrap<Vector4>(Bytes).ToArray();
default:
throw new NotImplementedException();
}
}
// default:
// throw new NotImplementedException();
// }
// }
public void Resize(int count)
{
@@ -374,14 +361,14 @@ namespace VrmLib
void ToByteLength(int byteLength)
{
var newBytes = new byte[byteLength];
Buffer.BlockCopy(Bytes.Array, Bytes.Offset, newBytes, 0, Bytes.Count);
Bytes = new ArraySegment<byte>(newBytes);
var newBytes = ArrayManager.CreateNativeArray<byte>(byteLength);
NativeArray<byte>.Copy(Bytes, newBytes);
Bytes = newBytes;
}
public void Extend(int count)
{
var oldLength = Bytes.Count;
var oldLength = Bytes.Length;
ToByteLength(oldLength + Stride * count);
Count += count;
}
@@ -406,30 +393,17 @@ namespace VrmLib
//ushort to uint
case AccessorValueType.UNSIGNED_SHORT:
{
var src = SpanLike.Wrap<UInt16>(a.Bytes).Slice(0, a.Count);
var bytes = new byte[src.Length * 4];
var dst = SpanLike.Wrap<UInt32>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (uint)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, a.Count);
var bytes = ArrayManager.Convert(a.Bytes.Reinterpret<UInt16>(1), (UInt16 x) => (UInt32)x).Reinterpret<byte>(Marshal.SizeOf<UInt32>());
var accessor = new BufferAccessor(ArrayManager, bytes, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, a.Count);
a = accessor;
break;
}
//uint to ushort (おそらく通ることはない)
case AccessorValueType.UNSIGNED_INT:
{
var src = SpanLike.Wrap<UInt32>(a.Bytes).Slice(0, a.Count);
var bytes = new byte[src.Length * 2];
var dst = SpanLike.Wrap<UInt16>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (ushort)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), ComponentType, AccessorVectorType.SCALAR, a.Count);
var bytes = ArrayManager.Convert(a.Bytes.Reinterpret<UInt32>(1), (UInt32 x) => (UInt16)x).Reinterpret<byte>(Marshal.SizeOf<UInt16>());
var accessor = new BufferAccessor(ArrayManager, bytes, ComponentType, AccessorVectorType.SCALAR, a.Count);
a = accessor;
break;
}
@@ -441,10 +415,10 @@ namespace VrmLib
}
// 連結した新しいバッファを確保
var oldLength = Bytes.Count;
ToByteLength(oldLength + a.Bytes.Count);
var oldLength = Bytes.Length;
ToByteLength(oldLength + a.Bytes.Length);
// 後ろにコピー
Buffer.BlockCopy(a.Bytes.Array, a.Bytes.Offset, Bytes.Array, Bytes.Offset + oldLength, a.Bytes.Count);
NativeArray<byte>.Copy(a.Bytes, Bytes.GetSubArray(oldLength, Bytes.Length - oldLength));
Count += a.Count;
if (offset > 0)
@@ -454,7 +428,7 @@ namespace VrmLib
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes.Slice(oldLength));
var span = Bytes.GetSubArray(oldLength, Bytes.Length - oldLength).Reinterpret<UInt16>(1);
var ushortOffset = (ushort)offset;
for (int i = 0; i < span.Length; ++i)
{
@@ -465,7 +439,7 @@ namespace VrmLib
case AccessorValueType.UNSIGNED_INT:
{
var span = SpanLike.Wrap<UInt32>(Bytes.Slice(oldLength));
var span = Bytes.GetSubArray(oldLength, Bytes.Length - oldLength).Reinterpret<UInt32>(1);
var uintOffset = (uint)offset;
for (int i = 0; i < span.Length; ++i)
{
@@ -487,18 +461,16 @@ namespace VrmLib
{
return this;
}
return new BufferAccessor(Bytes.Slice(Stride * skipFrames), ComponentType, AccessorType, Count - skipFrames);
var start = Stride * skipFrames;
return new BufferAccessor(ArrayManager, Bytes.GetSubArray(start, Bytes.Length - start), ComponentType, AccessorType, Count - skipFrames);
}
public BufferAccessor CloneWithOffset(int offsetCount)
{
var offsetSize = Stride * offsetCount;
var buffer = new byte[offsetSize + Bytes.Count];
Buffer.BlockCopy(Bytes.Array, Bytes.Offset, buffer, offsetSize, Bytes.Count);
return new BufferAccessor(new ArraySegment<byte>(buffer), ComponentType, AccessorType, Count + offsetCount);
var buffer = ArrayManager.CreateNativeArray<byte>(offsetSize + Bytes.Length);
NativeArray<byte>.Copy(Bytes, buffer.GetSubArray(offsetSize, buffer.Length - offsetSize));
return new BufferAccessor(ArrayManager, buffer, ComponentType, AccessorType, Count + offsetCount);
}
public void AddTo(Dictionary<string, BufferAccessor> dict, string key)

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -65,7 +66,7 @@ namespace VrmLib
/// indicesの最大値が65535未満(-1を避ける)ならばushort 型で、
/// そうでなければ int型で IndexBufferを代入する
/// </summary>
public void AssignIndexBuffer(SpanLike<int> indices)
public void AssignIndexBuffer(NativeArray<int> indices)
{
bool isInt = false;
foreach (var i in indices)
@@ -247,8 +248,8 @@ namespace VrmLib
{
m.Translation = Vector3.Zero;
var position = SpanLike.Wrap<Vector3>(VertexBuffer.Positions.Bytes);
var normal = SpanLike.Wrap<Vector3>(VertexBuffer.Normals.Bytes);
var position = VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normal = VertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < position.Length; ++i)
{

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -223,60 +224,60 @@ namespace VrmLib
this.Nodes.Remove(remove);
}
/// <summary>
/// Nodeを置き換える。参照を置換する。
/// </summary>
public void NodeReplace(Node src, Node dst)
{
if (src == null)
{
throw new ArgumentNullException();
}
if (dst == null)
{
throw new ArgumentNullException();
}
// /// <summary>
// /// Nodeを置き換える。参照を置換する。
// /// </summary>
// public void NodeReplace(Node src, Node dst)
// {
// if (src == null)
// {
// throw new ArgumentNullException();
// }
// if (dst == null)
// {
// throw new ArgumentNullException();
// }
// add dst same parent
src.Parent.Add(dst, ChildMatrixMode.KeepWorld);
// // add dst same parent
// src.Parent.Add(dst, ChildMatrixMode.KeepWorld);
// remove all child
foreach (var child in src.Children.ToArray())
{
dst.Add(child, ChildMatrixMode.KeepWorld);
}
// // remove all child
// foreach (var child in src.Children.ToArray())
// {
// dst.Add(child, ChildMatrixMode.KeepWorld);
// }
// remove from parent
src.Parent.Remove(src);
this.Nodes.Remove(src);
// // remove from parent
// src.Parent.Remove(src);
// this.Nodes.Remove(src);
// remove from skinning
foreach (var skin in this.Skins)
{
skin.Replace(src, dst);
}
// // remove from skinning
// foreach (var skin in this.Skins)
// {
// skin.Replace(src, dst);
// }
// fix animation reference
foreach (var animation in this.Animations)
{
if (animation.NodeMap.TryGetValue(src, out NodeAnimation nodeAnimation))
{
animation.NodeMap.Remove(src);
animation.NodeMap.Add(dst, nodeAnimation);
}
}
// // fix animation reference
// foreach (var animation in this.Animations)
// {
// if (animation.NodeMap.TryGetValue(src, out NodeAnimation nodeAnimation))
// {
// animation.NodeMap.Remove(src);
// animation.NodeMap.Add(dst, nodeAnimation);
// }
// }
if (this.Nodes.Contains(dst))
{
throw new Exception("already exists");
}
this.Nodes.Add(dst);
// if (this.Nodes.Contains(dst))
// {
// throw new Exception("already exists");
// }
// this.Nodes.Add(dst);
// TODO: SpringBone
}
// // TODO: SpringBone
// }
#endregion
public string SkinningBake()
public string SkinningBake(NativeArrayManager arrayManager)
{
foreach (var node in this.Nodes)
{
@@ -294,7 +295,7 @@ namespace VrmLib
{
{
// Skinningの出力先を自身にすることでBakeする
meshGroup.Skin.Skinning(mesh.VertexBuffer);
meshGroup.Skin.Skinning(arrayManager, mesh.VertexBuffer);
}
// morphのPositionは相対値が入っているはずなので、手を加えない正規化されていない場合、二重に補正が掛かる
@@ -339,7 +340,7 @@ namespace VrmLib
{
if (meshGroup.Skin != null)
{
meshGroup.Skin.CalcInverseMatrices();
meshGroup.Skin.CalcInverseMatrices(arrayManager);
}
}
}
@@ -355,7 +356,7 @@ namespace VrmLib
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
@@ -363,7 +364,7 @@ namespace VrmLib
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
@@ -383,7 +384,7 @@ namespace VrmLib
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
@@ -391,7 +392,7 @@ namespace VrmLib
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
@@ -476,7 +477,7 @@ namespace VrmLib
var uv = m.VertexBuffer.TexCoords;
if (uv != null)
{
var span = SpanLike.Wrap<Vector2>(uv.Bytes);
var span = uv.Bytes.Reinterpret<Vector2>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].UVVerticalFlip();
@@ -495,7 +496,7 @@ namespace VrmLib
{
// 複数の gltf.accessor が別の要素間で共有されている場合に、2回処理されることを防ぐ
// edgecase: InverseBindMatrices で遭遇
var unique = new HashSet<ArraySegment<byte>>();
var unique = new HashSet<NativeArray<byte>>();
foreach (var g in MeshGroups)
{
@@ -521,13 +522,13 @@ namespace VrmLib
switch (m.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_BYTE:
FlipTriangle(SpanLike.Wrap<Byte>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes);
break;
case AccessorValueType.UNSIGNED_SHORT:
FlipTriangle(SpanLike.Wrap<UInt16>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes.Reinterpret<UInt16>(1));
break;
case AccessorValueType.UNSIGNED_INT:
FlipTriangle(SpanLike.Wrap<UInt32>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes.Reinterpret<UInt32>(1));
break;
default:
throw new NotImplementedException();
@@ -580,7 +581,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<byte> indices)
static void FlipTriangle(NativeArray<byte> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
@@ -591,7 +592,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<ushort> indices)
static void FlipTriangle(NativeArray<ushort> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
@@ -602,7 +603,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<uint> indices)
static void FlipTriangle(NativeArray<uint> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{

View File

@@ -25,7 +25,7 @@ namespace VrmLib
{
if (In.ComponentType == AccessorValueType.FLOAT)
{
var times = SpanLike.Wrap<Single>(In.Bytes);
var times = In.Bytes.Reinterpret<Single>(1);
return times[times.Length - 1];
}
else

View File

@@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -29,7 +30,7 @@ namespace VrmLib
/// <summary>
/// BoneSkinningもしくはMorphTargetの適用
/// <summary>
public void Skinning(VertexBuffer vertexBuffer = null)
public void Skinning(NativeArrayManager arrayManager, VertexBuffer vertexBuffer = null)
{
m_indexOfRoot = (ushort)Joints.IndexOf(Root);
var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue;
@@ -46,13 +47,13 @@ namespace VrmLib
if (InverseMatrices == null)
{
CalcInverseMatrices();
CalcInverseMatrices(arrayManager);
}
else
{
if (addRoot)
{
var inverseArray = SpanLike.Wrap<Matrix4x4>(InverseMatrices.Bytes).ToArray();
var inverseArray = InverseMatrices.Bytes.Reinterpret<Matrix4x4>(1);
var concat = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray();
InverseMatrices.Assign(concat);
}
@@ -80,33 +81,33 @@ namespace VrmLib
if (vertexBuffer != null)
{
Apply(vertexBuffer);
Apply(arrayManager, vertexBuffer);
}
}
void Apply(VertexBuffer vertexBuffer)
void Apply(NativeArrayManager arrayManager, VertexBuffer vertexBuffer)
{
var dstPosition = SpanLike.Wrap<Vector3>(vertexBuffer.Positions.Bytes);
var dstPosition = vertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
// Span<Vector3> emptyNormal = stackalloc Vector3[0];
Apply(vertexBuffer, dstPosition, vertexBuffer.Normals != null ? SpanLike.Wrap<Vector3>(vertexBuffer.Normals.Bytes) : default);
Apply(arrayManager, vertexBuffer, dstPosition, vertexBuffer.Normals != null ? vertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1) : default);
}
public void Apply(VertexBuffer vertexBuffer, SpanLike<Vector3> dstPosition, SpanLike<Vector3> dstNormal)
public void Apply(NativeArrayManager arrayManager, VertexBuffer vertexBuffer, NativeArray<Vector3> dstPosition, NativeArray<Vector3> dstNormal)
{
var jointsBuffer = vertexBuffer.Joints;
var joints = (jointsBuffer != null || jointsBuffer.Count == 0)
? SpanLike.Wrap<SkinJoints>(jointsBuffer.Bytes)
: SpanLike.Create<SkinJoints>(vertexBuffer.Count) // when MorphTarget only
? jointsBuffer.Bytes.Reinterpret<SkinJoints>(1)
: arrayManager.CreateNativeArray<SkinJoints>(vertexBuffer.Count) // when MorphTarget only
;
var weightsBuffer = vertexBuffer.Weights;
var weights = (weightsBuffer != null || weightsBuffer.Count == 0)
? SpanLike.Wrap<Vector4>(weightsBuffer.Bytes)
: SpanLike.Create<Vector4>(vertexBuffer.Count) // when MorphTarget only
? weightsBuffer.Bytes.Reinterpret<Vector4>(1)
: arrayManager.CreateNativeArray<Vector4>(vertexBuffer.Count) // when MorphTarget only
;
var positionBuffer = vertexBuffer.Positions;
var position = SpanLike.Wrap<Vector3>(positionBuffer.Bytes);
var position = positionBuffer.Bytes.Reinterpret<Vector3>(1);
bool useNormal = false;
if (dstNormal.Length > 0)
@@ -148,7 +149,7 @@ namespace VrmLib
if (useNormal)
{
var normalBuffer = vertexBuffer.Normals;
var normal = normalBuffer != null ? SpanLike.Wrap<Vector3>(normalBuffer.Bytes) : dstNormal;
var normal = normalBuffer != null ? normalBuffer.Bytes.Reinterpret<Vector3>(1) : dstNormal;
var src = new Vector4(normal[i], 0); // 方向ベクトル
var dst = Vector4.Zero;
if (w.X > 0) dst += Vector4.Transform(src, m_matrices[j.Joint0]) * w.X * factor;
@@ -190,7 +191,7 @@ namespace VrmLib
if (InverseMatrices != null)
{
var sb = new StringBuilder();
var matrices = SpanLike.Wrap<Matrix4x4>(InverseMatrices.Bytes);
var matrices = InverseMatrices.Bytes.Reinterpret<Matrix4x4>(1);
var count = 0;
// var rootMatrix = Matrix4x4.Identity;
// if (Root != null)
@@ -221,7 +222,7 @@ namespace VrmLib
}
}
public void Replace(Node src, Node dst)
public void Replace(NativeArrayManager arrayManager, Node src, Node dst)
{
var removeIndex = Joints.IndexOf(src);
if (removeIndex >= 0)
@@ -229,11 +230,11 @@ namespace VrmLib
Joints[removeIndex] = dst;
// エクスポート時に再計算させる
CalcInverseMatrices();
CalcInverseMatrices(arrayManager);
}
}
public void CalcInverseMatrices()
public void CalcInverseMatrices(NativeArrayManager arrayManager)
{
// var root = Root;
// if (root == null)
@@ -243,8 +244,8 @@ namespace VrmLib
// root.CalcWorldMatrix(Matrix4x4.Identity, true);
// calc inverse bind matrices
var matricesBytes = new Byte[Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count];
var matrices = SpanLike.Wrap<Matrix4x4>(new ArraySegment<byte>(matricesBytes));
var matricesBytes = arrayManager.CreateNativeArray<Byte>(Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count);
var matrices = matricesBytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < Joints.Count; ++i)
{
// var w = Joints[i].Matrix;
@@ -254,7 +255,7 @@ namespace VrmLib
matrices[i] = Joints[i].InverseMatrix;
}
}
InverseMatrices = new BufferAccessor(new ArraySegment<byte>(matricesBytes), AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
InverseMatrices = new BufferAccessor(arrayManager, matricesBytes, AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
}
static void Update(ref float weight, ref ushort index, int[] indexMap)
@@ -276,38 +277,38 @@ namespace VrmLib
}
}
/// <summary>
/// nullになったjointを除去して、boneweightを前に詰める
/// </summary>
public void FixBoneWeight(BufferAccessor jointsAccessor, BufferAccessor weightsAccessor)
{
var map = Joints.Select((x, i) => ValueTuple.Create(i, x)).Where(x => x.Item2 != null).ToArray();
var indexMap = Enumerable.Repeat(-1, Joints.Count).ToArray();
{
for (int i = 0; i < map.Length; ++i)
{
indexMap[map[i].Item1] = i;
}
}
Joints.RemoveAll(x => x == null);
// /// <summary>
// /// nullになったjointを除去して、boneweightを前に詰める
// /// </summary>
// public void FixBoneWeight(BufferAccessor jointsAccessor, BufferAccessor weightsAccessor)
// {
// var map = Joints.Select((x, i) => ValueTuple.Create(i, x)).Where(x => x.Item2 != null).ToArray();
// var indexMap = Enumerable.Repeat(-1, Joints.Count).ToArray();
// {
// for (int i = 0; i < map.Length; ++i)
// {
// indexMap[map[i].Item1] = i;
// }
// }
// Joints.RemoveAll(x => x == null);
var joints = jointsAccessor.GetSpan<SkinJoints>();
var weights = weightsAccessor.GetSpan<Vector4>();
for (int i = 0; i < joints.Length; ++i)
{
var j = joints[i];
var w = weights[i];
// var joints = jointsAccessor.GetSpan<SkinJoints>();
// var weights = weightsAccessor.GetSpan<Vector4>();
// for (int i = 0; i < joints.Length; ++i)
// {
// var j = joints[i];
// var w = weights[i];
Update(ref w.X, ref j.Joint0, indexMap);
Update(ref w.Y, ref j.Joint1, indexMap);
Update(ref w.Z, ref j.Joint2, indexMap);
Update(ref w.W, ref j.Joint3, indexMap);
// Update(ref w.X, ref j.Joint0, indexMap);
// Update(ref w.Y, ref j.Joint1, indexMap);
// Update(ref w.Z, ref j.Joint2, indexMap);
// Update(ref w.W, ref j.Joint3, indexMap);
joints[i] = j;
weights[i] = w;
}
// joints[i] = j;
// weights[i] = w;
// }
CalcInverseMatrices();
}
// CalcInverseMatrices();
// }
}
}

View File

@@ -196,33 +196,33 @@ namespace VrmLib
return vb;
}
public SpanLike<SkinJoints> GetOrCreateJoints()
{
var buffer = Joints;
if (buffer == null)
{
buffer = new BufferAccessor(
new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(SkinJoints)) * Count]),
AccessorValueType.UNSIGNED_SHORT,
AccessorVectorType.VEC4, Count);
Add(JointKey, buffer);
}
return SpanLike.Wrap<SkinJoints>(buffer.Bytes);
}
// public SpanLike<SkinJoints> GetOrCreateJoints()
// {
// var buffer = Joints;
// if (buffer == null)
// {
// buffer = new BufferAccessor(
// new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(SkinJoints)) * Count]),
// AccessorValueType.UNSIGNED_SHORT,
// AccessorVectorType.VEC4, Count);
// Add(JointKey, buffer);
// }
// return SpanLike.Wrap<SkinJoints>(buffer.Bytes);
// }
public SpanLike<Vector4> GetOrCreateWeights()
{
var buffer = Weights;
if (buffer == null)
{
buffer = new BufferAccessor(
new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(Vector4)) * Count]),
AccessorValueType.FLOAT,
AccessorVectorType.VEC4, Count);
Add(WeightKey, buffer);
}
return SpanLike.Wrap<Vector4>(buffer.Bytes);
}
// public SpanLike<Vector4> GetOrCreateWeights()
// {
// var buffer = Weights;
// if (buffer == null)
// {
// buffer = new BufferAccessor(
// new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(Vector4)) * Count]),
// AccessorValueType.FLOAT,
// AccessorVectorType.VEC4, Count);
// Add(WeightKey, buffer);
// }
// return SpanLike.Wrap<Vector4>(buffer.Bytes);
// }
static bool HasSameKeys<T>(Dictionary<string, T> lhs, Dictionary<string, T> rhs)
{
@@ -237,48 +237,48 @@ namespace VrmLib
return true;
}
public void Append(VertexBuffer v)
{
var keys = VertexBuffers.Keys.ToList();
// public void Append(VertexBuffer v)
// {
// var keys = VertexBuffers.Keys.ToList();
var lastCount = Count;
// var lastCount = Count;
// v から VertexBufferfs に足す
foreach (var kv in v.VertexBuffers)
{
if (VertexBuffers.TryGetValue(kv.Key, out BufferAccessor buffer))
{
// used
keys.Remove(kv.Key);
if (buffer.Count != lastCount)
{
throw new ArgumentException();
}
}
else
{
// add empty
var byteLength = lastCount * kv.Value.Stride;
buffer = new BufferAccessor(new ArraySegment<byte>(new byte[byteLength]), kv.Value.ComponentType, kv.Value.AccessorType, lastCount);
if (buffer.Count != lastCount)
{
throw new ArgumentException();
}
VertexBuffers.Add(kv.Key, buffer);
}
// // v から VertexBufferfs に足す
// foreach (var kv in v.VertexBuffers)
// {
// if (VertexBuffers.TryGetValue(kv.Key, out BufferAccessor buffer))
// {
// // used
// keys.Remove(kv.Key);
// if (buffer.Count != lastCount)
// {
// throw new ArgumentException();
// }
// }
// else
// {
// // add empty
// var byteLength = lastCount * kv.Value.Stride;
// buffer = new BufferAccessor(new ArraySegment<byte>(new byte[byteLength]), kv.Value.ComponentType, kv.Value.AccessorType, lastCount);
// if (buffer.Count != lastCount)
// {
// throw new ArgumentException();
// }
// VertexBuffers.Add(kv.Key, buffer);
// }
buffer.Append(kv.Value);
}
// buffer.Append(kv.Value);
// }
// 足されなかったキーに同じ長さを詰める
foreach (var key in keys)
{
var dst = VertexBuffers[key];
dst.Extend(v.Positions.Count);
}
// // 足されなかったキーに同じ長さを詰める
// foreach (var key in keys)
// {
// var dst = VertexBuffers[key];
// dst.Extend(v.Positions.Count);
// }
ValidateLength();
}
// ValidateLength();
// }
public void Resize(int n)
{

View File

@@ -20,15 +20,15 @@ namespace VrmLibTests
model.NodeAdd(node1, node0);
Assert.AreEqual(2, model.Nodes.Count);
var node2 = new Node("node2");
model.NodeReplace(node0, node2);
Assert.AreEqual(2, model.Nodes.Count);
Assert.AreEqual(node2, model.Nodes[1]);
Assert.AreEqual(1, node2.Children.Count);
// var node2 = new Node("node2");
// model.NodeReplace(node0, node2);
// Assert.AreEqual(2, model.Nodes.Count);
// Assert.AreEqual(node2, model.Nodes[1]);
// Assert.AreEqual(1, node2.Children.Count);
model.NodeRemove(node1);
Assert.AreEqual(1, model.Nodes.Count);
Assert.AreEqual(0, node2.Children.Count);
// model.NodeRemove(node1);
// Assert.AreEqual(1, model.Nodes.Count);
// Assert.AreEqual(0, node2.Children.Count);
}
}
}