public override string ToString() { if (InverseMatrices != null) { var sb = new StringBuilder(); var matrices = SpanLike.Wrap <Matrix4x4>(InverseMatrices.Bytes); var count = 0; // var rootMatrix = Matrix4x4.Identity; // if (Root != null) // { // rootMatrix = Root.InverseMatrix; // } for (int i = 0; i < matrices.Length; ++i) { var m = matrices[i] * Joints[i].Matrix; if (!IsIdentity(m)) { ++count; } } if (count > 0) { sb.Append($"{count}/{Joints.Count} is not normalized"); } else { sb.Append($"{Joints.Count} joints normalized"); } return(sb.ToString()); } else { return($"{Joints.Count} joints without InverseMatrices"); } }
// 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].X = span[i].X; array[i].Y = span[i].Y; array[i].Z = span[i].Z; array[i].W = span[i].W; } return(array); } default: throw new NotImplementedException(); } }
void Apply(VertexBuffer vertexBuffer) { var dstPosition = SpanLike.Wrap <Vector3>(vertexBuffer.Positions.Bytes); // Span<Vector3> emptyNormal = stackalloc Vector3[0]; Apply(vertexBuffer, dstPosition, vertexBuffer.Normals != null ? SpanLike.Wrap <Vector3>(vertexBuffer.Normals.Bytes) : default); }
// Index用 public int[] GetAsIntArray() { if (AccessorType != AccessorVectorType.SCALAR) { throw new InvalidOperationException("not scalar"); } 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); } case AccessorValueType.UNSIGNED_INT: return(SpanLike.Wrap <Int32>(Bytes).ToArray()); default: throw new NotImplementedException(); } }
List <ValueTuple <int, Triangle> > > SplitTriangles(Mesh src) { var triangles = src.Triangles.ToArray(); var morphUseCount = new int[triangles.Length]; // 各モーフ foreach (var morph in src.MorphTargets) { if (morph.VertexBuffer.Count == 0) { // 無効 continue; } // POSITIONが使っているtriangleのカウンターをアップさせる var positions = SpanLike.Wrap <Vector3>(morph.VertexBuffer.Positions.Bytes); for (int i = 0; i < triangles.Length; ++i) { ref var triangle = ref triangles[i]; if (positions[triangle.Item2.Vertex0] != Vector3.Zero) { ++morphUseCount[i]; } if (positions[triangle.Item2.Vertex1] != Vector3.Zero) { ++morphUseCount[i]; } if (positions[triangle.Item2.Vertex2] != Vector3.Zero) { ++morphUseCount[i]; } } }
static void ReverseX(BufferAccessor ba) { if (ba.ComponentType != AccessorValueType.FLOAT) { throw new Exception(); } if (ba.AccessorType == AccessorVectorType.VEC3) { var span = SpanLike.Wrap <Vector3>(ba.Bytes); for (int i = 0; i < span.Length; ++i) { span[i] = span[i].ReverseX(); } } else if (ba.AccessorType == AccessorVectorType.MAT4) { var span = SpanLike.Wrap <Matrix4x4>(ba.Bytes); for (int i = 0; i < span.Length; ++i) { span[i] = span[i].ReverseX(); } } else { throw new NotImplementedException(); } }
public SpanLike <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)); }
/// <summary> /// BoneSkinningもしくはMorphTargetの適用 /// <summary> public void Skinning(VertexBuffer vertexBuffer = null) { m_indexOfRoot = (ushort)Joints.IndexOf(Root); var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue; if (addRoot) { m_indexOfRoot = (ushort)Joints.Count; Joints.Add(Root); } if (m_matrices == null) { m_matrices = new Matrix4x4[Joints.Count]; } if (InverseMatrices == null) { CalcInverseMatrices(); } else { if (addRoot) { var inverseArray = SpanLike.Wrap <Matrix4x4>(InverseMatrices.Bytes).ToArray(); var concat = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray(); InverseMatrices.Assign(concat); } } var inverse = InverseMatrices.GetSpan <Matrix4x4>(); // if (Root != null) // { // var rootInverse = Root.InverseMatrix; // var root = Root.Matrix; // for (int i = 0; i < m_matrices.Length; ++i) // { // m_matrices[i] = inverse[i] * Joints[i].Matrix * rootInverse; // } // } // else { for (int i = 0; i < m_matrices.Length; ++i) { var inv = i < inverse.Length ? inverse[i] : Joints[i].InverseMatrix; m_matrices[i] = inv * Joints[i].Matrix; } } if (vertexBuffer != null) { Apply(vertexBuffer); } }
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 static BufferAccessor Create <T>(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)); for (int i = 0; i < list.Length; ++i) { span[i] = list[i]; } AccessorValueType componentType = default(AccessorValueType); AccessorVectorType accessorType = default(AccessorVectorType); if (t == typeof(Vector2)) { componentType = AccessorValueType.FLOAT; accessorType = AccessorVectorType.VEC2; } else if (t == typeof(Vector3)) { componentType = AccessorValueType.FLOAT; accessorType = AccessorVectorType.VEC3; } else if (t == typeof(Vector4)) { componentType = AccessorValueType.FLOAT; accessorType = AccessorVectorType.VEC4; } else if (t == typeof(Quaternion)) { componentType = AccessorValueType.FLOAT; accessorType = AccessorVectorType.VEC4; } else if (t == typeof(SkinJoints)) { componentType = AccessorValueType.UNSIGNED_SHORT; accessorType = AccessorVectorType.VEC4; } else if (t == typeof(int)) { componentType = AccessorValueType.UNSIGNED_INT; accessorType = AccessorVectorType.SCALAR; } else { throw new NotImplementedException(); } return(new BufferAccessor( new ArraySegment <byte>(bytes), componentType, accessorType, list.Length)); }
// 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(); } }
/// <summary> /// UVのVを反転する。 => V = 1.0 - V /// </summary> static void UVVerticalFlip(this Model model) { foreach (var g in model.MeshGroups) { foreach (var m in g.Meshes) { var uv = m.VertexBuffer.TexCoords; if (uv != null) { var span = SpanLike.Wrap <Vector2>(uv.Bytes); for (int i = 0; i < span.Length; ++i) { span[i] = span[i].UVVerticalFlip(); } } } } }
// Skin.Normalize public static void ApplyRotationAndScaling(this Mesh mesh, Matrix4x4 m) { m.Translation = Vector3.Zero; var position = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Positions.Bytes); var normal = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Normals.Bytes); for (int i = 0; i < position.Length; ++i) { { var dst = Vector4.Transform(new Vector4(position[i], 1), m); position[i] = new Vector3(dst.X, dst.Y, dst.Z); } { var dst = Vector4.Transform(new Vector4(normal[i], 0), m); normal[i] = new Vector3(dst.X, dst.Y, dst.Z); } } }
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()); default: throw new NotImplementedException(); } }
public void CalcInverseMatrices() { // var root = Root; // if (root == null) // { // root = Joints[0].Ancestors().Last(); // } // 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)); for (int i = 0; i < Joints.Count; ++i) { // var w = Joints[i].Matrix; // Matrix4x4.Invert(w, out Matrix4x4 inv); if (Joints[i] != null) { matrices[i] = Joints[i].InverseMatrix; } } InverseMatrices = new BufferAccessor(new ArraySegment <byte>(matricesBytes), AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count); }
static Animation LoadAnimation(string name, Bvh.Bvh bvh, Model model, float scalingFactor) { var animation = new Animation(name); Dictionary <string, BvhNodeCurves> pathMap = new Dictionary <string, BvhNodeCurves>(); for (int i = 0; i < bvh.Channels.Length; ++i) { var channel = bvh.Channels[i]; if (!bvh.TryGetPathWithPropertyFromChannel(channel, out Bvh.Bvh.PathWithProperty prop)) { throw new Exception(); } if (!pathMap.TryGetValue(prop.Path, out BvhNodeCurves curves)) { curves = new BvhNodeCurves(); pathMap.Add(prop.Path, curves); } curves.Set(prop.Property, channel); } // setup time var timeBytes = new byte[Marshal.SizeOf(typeof(float)) * bvh.FrameCount]; var timeSpan = SpanLike.Wrap <Single>(new ArraySegment <byte>(timeBytes)); var now = 0.0; for (int i = 0; i < timeSpan.Length; ++i, now += bvh.FrameTime.TotalSeconds) { timeSpan[i] = (float)now; } var times = new BufferAccessor(new ArraySegment <byte>(timeBytes), AccessorValueType.FLOAT, AccessorVectorType.SCALAR, bvh.FrameCount); foreach (var(key, nodeCurve) in pathMap) { var node = Model.GetNode(model.Root, key); var bvhNode = GetNode(bvh.Root, key); var curve = new NodeAnimation(); if (nodeCurve.LocalPositionX != null) { var values = new byte[Marshal.SizeOf(typeof(Vector3)) * nodeCurve.LocalPositionX.Keys.Length]; var span = SpanLike.Wrap <Vector3>(new ArraySegment <byte>(values)); for (int i = 0; i < nodeCurve.LocalPositionX.Keys.Length; ++i) { span[i] = new Vector3 { X = nodeCurve.LocalPositionX.Keys[i] * scalingFactor, Y = nodeCurve.LocalPositionY.Keys[i] * scalingFactor, Z = nodeCurve.LocalPositionZ.Keys[i] * scalingFactor, }; } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC3, span.Length) }; curve.Curves.Add(AnimationPathType.Translation, sampler); } if (nodeCurve.EulerX != null) { var values = new byte[Marshal.SizeOf(typeof(Quaternion)) * nodeCurve.EulerX.Keys.Length]; var span = SpanLike.Wrap <Quaternion>(new ArraySegment <byte>(values)); Func <Quaternion, BvhNodeCurves, int, Quaternion> getRot = (q, c, i) => q; foreach (var ch in bvhNode.Channels) { var tmp = getRot; switch (ch) { case Channel.Xrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, ToRad(c.EulerX.Keys[i]))); }; break; case Channel.Yrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, ToRad(c.EulerY.Keys[i]))); }; break; case Channel.Zrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, ToRad(c.EulerZ.Keys[i]))); }; break; default: // throw new NotImplementedException(); break; } } for (int i = 0; i < nodeCurve.EulerX.Keys.Length; ++i) { span[i] = getRot(Quaternion.Identity, nodeCurve, i); } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC4, span.Length) }; curve.Curves.Add(AnimationPathType.Rotation, sampler); } animation.AddCurve(node, curve); } return(animation); }
/// <summary> /// * Position, Normal の Z座標に -1 を乗算する /// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算 /// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する /// </summary> static void ReverseAxisAndFlipTriangle(this Model model, Reverser reverser, bool ignoreVrm) { foreach (var g in model.MeshGroups) { foreach (var m in g.Meshes) { foreach (var(k, v) in m.VertexBuffer) { if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey) { reverser.ReverseBuffer(v); } else if (k == VertexBuffer.TangentKey) { // I don't know } } switch (m.IndexBuffer.ComponentType) { case AccessorValueType.UNSIGNED_BYTE: FlipTriangle(SpanLike.Wrap <Byte>(m.IndexBuffer.Bytes)); break; case AccessorValueType.UNSIGNED_SHORT: FlipTriangle(SpanLike.Wrap <UInt16>(m.IndexBuffer.Bytes)); break; case AccessorValueType.UNSIGNED_INT: FlipTriangle(SpanLike.Wrap <UInt32>(m.IndexBuffer.Bytes)); break; default: throw new NotImplementedException(); } foreach (var mt in m.MorphTargets) { foreach (var(k, v) in mt.VertexBuffer) { if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey) { reverser.ReverseBuffer(v); } if (k == VertexBuffer.TangentKey) { // I don't know } } } } } // 親から順に処理する // Rootは原点決め打ちのノード(GLTFに含まれない) foreach (var n in model.Root.Traverse().Skip(1)) { n.SetMatrix(reverser.ReverseMatrix(n.Matrix), false); } // 親から順に処理したので不要 // model.Root.CalcWorldMatrix(); foreach (var s in model.Skins) { if (s.InverseMatrices != null) { reverser.ReverseBuffer(s.InverseMatrices); } } foreach (var a in model.Animations) { // TODO: } }
public void Apply(VertexBuffer vertexBuffer, SpanLike <Vector3> dstPosition, SpanLike <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 ; var weightsBuffer = vertexBuffer.Weights; var weights = (weightsBuffer != null || weightsBuffer.Count == 0) ? SpanLike.Wrap <Vector4>(weightsBuffer.Bytes) : SpanLike.Create <Vector4>(vertexBuffer.Count) // when MorphTarget only ; var positionBuffer = vertexBuffer.Positions; var position = SpanLike.Wrap <Vector3>(positionBuffer.Bytes); bool useNormal = false; if (dstNormal.Length > 0) { useNormal = vertexBuffer.Normals != null && dstNormal.Length == dstPosition.Length; } for (int i = 0; i < position.Length; ++i) { var j = joints[i]; var w = weights[i]; var sum = (w.X + w.Y + w.Z + w.W); float factor; if (sum > 0) { factor = 1.0f / sum; } else { factor = 1.0f; j = new SkinJoints(m_indexOfRoot, 0, 0, 0); w = new Vector4(1, 0, 0, 0); } if (j.Joint0 == ushort.MaxValue) { w.X = 0; } if (j.Joint1 == ushort.MaxValue) { w.Y = 0; } if (j.Joint2 == ushort.MaxValue) { w.Z = 0; } if (j.Joint3 == ushort.MaxValue) { w.W = 0; } { var src = new Vector4(position[i], 1); // 位置ベクトル var dst = Vector4.Zero; if (w.X > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint0]) * w.X * factor; } if (w.Y > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint1]) * w.Y * factor; } if (w.Z > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint2]) * w.Z * factor; } if (w.W > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint3]) * w.W * factor; } dstPosition[i] = new Vector3(dst.X, dst.Y, dst.Z); } if (useNormal) { var normalBuffer = vertexBuffer.Normals; var normal = normalBuffer != null?SpanLike.Wrap <Vector3>(normalBuffer.Bytes) : 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; } if (w.Y > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint1]) * w.Y * factor; } if (w.Z > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint2]) * w.Z * factor; } if (w.W > 0) { dst += Vector4.Transform(src, m_matrices[j.Joint3]) * w.W * factor; } dstNormal[i] = new Vector3(dst.X, dst.Y, dst.Z); } } }
// Meshを連結する。SingleMesh で使う public static void Append(this Mesh mesh, VertexBuffer vertices, BufferAccessor indices, List <Submesh> submeshes, List <MorphTarget> targets, int[] jointIndexMap, int rootIndex = -1, Matrix4x4 matrix = default(Matrix4x4)) { var lastCount = mesh.VertexBuffer != null ? mesh.VertexBuffer.Count : 0; // index buffer if (mesh.IndexBuffer == null) { var accessor = new BufferAccessor(new ArraySegment <byte>(new byte[0]), AccessorValueType.UNSIGNED_INT, indices.AccessorType, 0); mesh.IndexBuffer = accessor; mesh.IndexBuffer.Append(indices, 0); } else { mesh.IndexBuffer.Append(indices, lastCount); } { var submeshOffset = mesh.SubmeshTotalDrawCount; for (int i = 0; i < submeshes.Count; ++i) { var submesh = submeshes[i]; mesh.Submeshes.Add(new Submesh(submeshOffset, submesh.DrawCount, submesh.Material)); submeshOffset += submesh.DrawCount; } } // vertex buffer var vertexOffset = 0; if (mesh.VertexBuffer == null) { mesh.VertexBuffer = vertices; } else { vertexOffset = mesh.VertexBuffer.Count; mesh.VertexBuffer.Append(vertices); } if (jointIndexMap != null && mesh.VertexBuffer.Joints != null && mesh.VertexBuffer.Weights != null) { // JOINT index 参照の修正 var joints = SpanLike.Wrap <SkinJoints>(mesh.VertexBuffer.Joints.Bytes).Slice(vertexOffset); var weights = SpanLike.Wrap <Vector4>(mesh.VertexBuffer.Weights.Bytes).Slice(vertexOffset); FixSkinJoints(joints, weights, jointIndexMap); } else { var position = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Positions.Bytes).Slice(vertexOffset); var normal = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Normals.Bytes).Slice(vertexOffset); var joints = mesh.VertexBuffer.GetOrCreateJoints().Slice(vertexOffset); var weights = mesh.VertexBuffer.GetOrCreateWeights().Slice(vertexOffset); // Nodeの姿勢を反映して // JOINT と WEIGHT を追加する FixNoSkinJoints(joints, weights, rootIndex, position, normal, matrix); } // morph target foreach (var target in targets) { if (string.IsNullOrEmpty(target.Name)) { continue; } foreach (var kv in target.VertexBuffer) { if (kv.Value.Count != target.VertexBuffer.Count) { throw new Exception("different length"); } } var found = mesh.MorphTargets.FirstOrDefault(x => x.Name == target.Name); if (found == null) { // targetの前に0を足す found = new MorphTarget(target.Name); found.VertexBuffer = target.VertexBuffer.CloneWithOffset(lastCount); mesh.MorphTargets.Add(found); foreach (var kv in found.VertexBuffer) { if (kv.Value.Count != mesh.VertexBuffer.Count) { throw new Exception(); } } } else { found.VertexBuffer.Resize(lastCount); // foundの後ろにtargetを足す found.VertexBuffer.Append(target.VertexBuffer); foreach (var kv in found.VertexBuffer) { if (kv.Value.Count != mesh.VertexBuffer.Count) { throw new Exception(); } } } } }
/// <summary> /// * Position, Normal の Z座標に -1 を乗算する /// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算 /// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する /// </summary> static void ReverseZAndFlipTriangle(this Model model, bool ignoreVrm) { foreach (var g in model.MeshGroups) { foreach (var m in g.Meshes) { foreach (var(k, v) in m.VertexBuffer) { if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey) { ReverseZ(v); } if (k == VertexBuffer.TangentKey) { // I don't know } } switch (m.IndexBuffer.ComponentType) { case AccessorValueType.UNSIGNED_BYTE: FlipTriangle(SpanLike.Wrap <Byte>(m.IndexBuffer.Bytes)); break; case AccessorValueType.UNSIGNED_SHORT: FlipTriangle(SpanLike.Wrap <UInt16>(m.IndexBuffer.Bytes)); break; case AccessorValueType.UNSIGNED_INT: FlipTriangle(SpanLike.Wrap <UInt32>(m.IndexBuffer.Bytes)); break; default: throw new NotImplementedException(); } foreach (var mt in m.MorphTargets) { foreach (var(k, v) in mt.VertexBuffer) { if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey) { ReverseZ(v); } if (k == VertexBuffer.TangentKey) { // I don't know } } } } } // 親から順に処理する // Rootは原点決め打ちのノード(GLTFに含まれない) foreach (var n in model.Root.Traverse().Skip(1)) { n.SetMatrix(n.Matrix.ReverseZ(), false); } // 親から順に処理したので不要 // model.Root.CalcWorldMatrix(); foreach (var s in model.Skins) { if (s.InverseMatrices != null) { ReverseZ(s.InverseMatrices); } } foreach (var a in model.Animations) { // TODO: } if (model.Vrm != null) { if (!ignoreVrm) { // LookAt if (model.Vrm.LookAt != null) { model.Vrm.LookAt.OffsetFromHeadBone = model.Vrm.LookAt.OffsetFromHeadBone.ReverseZ(); } // SpringBone if (model.Vrm.SpringBone != null) { foreach (var b in model.Vrm.SpringBone.Springs) { foreach (var c in b.Colliders) { for (int i = 0; i < c.Colliders.Count; ++i) { var s = c.Colliders[i]; switch (s.ColliderType) { case VrmSpringBoneColliderTypes.Sphere: c.Colliders[i] = VrmSpringBoneCollider.CreateSphere(s.Offset.ReverseZ(), s.Radius); break; case VrmSpringBoneColliderTypes.Capsule: c.Colliders[i] = VrmSpringBoneCollider.CreateCapsule(s.Offset.ReverseZ(), s.Radius, s.CapsuleTail.ReverseZ()); break; default: throw new NotImplementedException(); } } } b.GravityDir = b.GravityDir.ReverseZ(); } } } } }
public static IEnumerable <Node> GetRemoveNodes(this Model model) { var nodeUsage = model.Nodes.Select(x => new NodeUsage { HasMesh = x.MeshGroup != null, HumanBone = x.HumanoidBone, TreeHasHumanBone = x.Traverse().Any(y => y.HumanoidBone.HasValue), }) .ToArray(); var bones = model.Nodes.Where(x => x.HumanoidBone.HasValue).ToArray(); // joint use foreach (var meshGroup in model.MeshGroups) { var skin = meshGroup.Skin; if (skin != null) { foreach (var mesh in meshGroup.Meshes) { var joints = mesh.VertexBuffer.Joints; var weights = mesh.VertexBuffer.Weights; if (joints != null && weights != null) { var jointsSpan = SpanLike.Wrap <SkinJoints>(joints.Bytes); var weightsSpan = SpanLike.Wrap <Vector4>(weights.Bytes); for (int i = 0; i < jointsSpan.Length; ++i) { var w = weightsSpan[i]; var j = jointsSpan[i]; if (w.X > 0) { nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint0])].WeightUsed++; } if (w.Y > 0) { nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint1])].WeightUsed++; } if (w.Z > 0) { nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint2])].WeightUsed++; } if (w.W > 0) { nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint3])].WeightUsed++; } } } } } } // 削除されるNodeのうち、子階層に1つでも残るNodeがあればそのNodeも残す for (int i = 0; i < nodeUsage.Length; i++) { if (nodeUsage[i].Used) { continue; } var children = model.Nodes[i].Traverse(); nodeUsage[i].TreeHasUsedBone = children.Where(x => nodeUsage[model.Nodes.IndexOf(x)].Used).Any(); } var spring = model.Vrm?.SpringBone; if (spring != null) { foreach (var x in spring.Springs) { foreach (var y in x.Joints) { nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true; } foreach (var y in x.Colliders) { nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true; } } } var nodes = nodeUsage.Select((x, i) => (i, x)) .Where(x => !x.Item2.Used) .Select(x => model.Nodes[x.Item1]) .ToArray(); return(nodes); }
// // ArraySegment<byte> を新規に確保して置き換える // public void Append(BufferAccessor a, int offset = -1) { if (AccessorType != a.AccessorType) { System.Console.WriteLine(AccessorType.ToString() + "!=" + a.AccessorType.ToString()); throw new Exception("different AccessorType"); } // UNSIGNED_SHORT <-> UNSIGNED_INT の変換を許容して処理を続行 // 統合メッシュのprimitiveのIndexBufferが65,535(ushort.MaxValue)を超える場合や、変換前にindexBuffer.ComponetTypeがushortとuint混在する場合など if (ComponentType != a.ComponentType) { switch (a.ComponentType) { //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); 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); a = accessor; break; } default: throw new Exception("Cannot Convert ComponentType"); } } // 連結した新しいバッファを確保 var oldLength = Bytes.Count; ToByteLength(oldLength + a.Bytes.Count); // 後ろにコピー Buffer.BlockCopy(a.Bytes.Array, a.Bytes.Offset, Bytes.Array, Bytes.Offset + oldLength, a.Bytes.Count); Count += a.Count; if (offset > 0) { // 後半にoffsetを足す switch (ComponentType) { case AccessorValueType.UNSIGNED_SHORT: { var span = SpanLike.Wrap <UInt16>(Bytes.Slice(oldLength)); var ushortOffset = (ushort)offset; for (int i = 0; i < span.Length; ++i) { span[i] += ushortOffset; } } break; case AccessorValueType.UNSIGNED_INT: { var span = SpanLike.Wrap <UInt32>(Bytes.Slice(oldLength)); var uintOffset = (uint)offset; for (int i = 0; i < span.Length; ++i) { span[i] += uintOffset; } } break; default: throw new NotImplementedException(); } } }