// Magica Cloth 2. // Copyright (c) 2023 MagicaSoft. // https://magicasoft.jp using Unity.Mathematics; using UnityEngine; namespace MagicaCloth2 { /// /// VirtualMeshで利用される頂点のボーンウエイト /// これはUnity.BoneWeight構造体を再マッピングしたもの /// public struct VirtualMeshBoneWeight { public float4 weights; public int4 boneIndices; public bool IsValid => weights[0] >= 1e-06f; public VirtualMeshBoneWeight(int4 boneIndices, float4 weights) { this.boneIndices = boneIndices; this.weights = weights; } /// /// 有効なウエイト数 /// public int Count { get { if (weights[3] > 0.0f) return 4; if (weights[2] > 0.0f) return 3; if (weights[1] > 0.0f) return 2; if (weights[0] > 0.0f) return 1; return 0; } } public void AddWeight(int boneIndex, float weight) { if (weight < 1e-06f) return; // すでに登録済みならばウエイトのみ加算する int wcnt = 0; for (int i = 0; i < 4; i++) { float w = weights[i]; if (w == 0.0f) break; if (boneIndices[i] == boneIndex) { // ウエイト加算 w += weight; weights[i] = w; // ソート for (int j = i; j >= 1; j--) { if (weights[j] > weights[j - 1]) { // swap w = weights[j - 1]; weights[j - 1] = weights[j]; weights[j] = w; int x = boneIndices[j - 1]; boneIndices[j - 1] = boneIndices[j]; boneIndices[j] = x; } } return; } wcnt++; } // すでに登録されているウエイトより大きければ挿入する for (int i = 0; i < 4; i++) { float w = weights[i]; if (w == 0.0f) { weights[i] = weight; boneIndices[i] = boneIndex; return; } else if (weight > w) { // 挿入 for (int j = 2; j >= i; j--) { weights[j + 1] = weights[j]; boneIndices[j + 1] = boneIndices[j]; } weights[i] = weight; boneIndices[i] = boneIndex; return; } } } public void AddWeight(in VirtualMeshBoneWeight bw) { if (bw.IsValid) { for (int i = 0; i < 4; i++) { AddWeight(bw.boneIndices[i], bw.weights[i]); } } } /// /// ウエイトを合計1に調整する /// public void AdjustWeight() { if (IsValid == false) return; float total = math.csum(weights); Debug.Assert(total >= 1e-06f); float scl = 1.0f / total; weights *= scl; } public override string ToString() { return $"[{boneIndices}] w({weights})"; } } }