using System; using System.Collections.Generic; using UnityEngine; using System.Linq; namespace StudioKafka.MeshSyncPro { public class MeshSyncProManager : MonoBehaviour { #region Zone型の定義 [Serializable] public class Zone { public Vector3 center; public Vector3 size; public bool active; public Color color; public Zone() { center = Vector3.zero; size = Vector3.one; active = true; color = Color.green; } public Zone(Vector3 zoneCenter, Vector3 zoneSize, bool isActive = true) { center = zoneCenter; size = zoneSize; active = isActive; color = Color.green; } public bool ContainsPoint(Vector3 point) { Vector3 min = center - size * 0.5f; Vector3 max = center + size * 0.5f; return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z; } } #endregion #region パブリックプロパティ(UIから設定される) [Header("対象オブジェクト")] public List bodyObjects = new List(); public List clothingObjects = new List(); [Header("検出設定")] [Range(0.0001f, 0.1f)] public float penetrationThreshold = 0.001f; [Range(-1f, 1f)] public float dotProductThreshold = 0.8f; [Header("修正設定")] [Range(0f, 10f)] public float influenceRadiusSteps = 1f; [Range(0, 10)] public int smoothingIterations = 2; [Range(0f, 1f)] public float smoothingFactor = 0.1f; [Header("検出ゾーン")] public Zone[] DetectionZones = new Zone[0]; #endregion #region プライベートフィールド private Dictionary<(GameObject, GameObject), int[]> penetratingIndicesResults = new Dictionary<(GameObject, GameObject), int[]>(); private Dictionary<(GameObject, GameObject), Vector3[]> penetratingVerticesResults = new Dictionary<(GameObject, GameObject), Vector3[]>(); private bool isInitialized = false; #endregion #region Unity ライフサイクル private void Awake() { Initialize(); } private void Start() { if (DetectionZones == null || DetectionZones.Length == 0) { CreateDefaultZone(); } } #endregion #region 初期化 private void Initialize() { if (isInitialized) return; penetratingIndicesResults = new Dictionary<(GameObject, GameObject), int[]>(); penetratingVerticesResults = new Dictionary<(GameObject, GameObject), Vector3[]>(); isInitialized = true; Debug.Log("[MeshSyncProManager] マネージャーが初期化されました"); } private void CreateDefaultZone() { DetectionZones = new Zone[] { new Zone(new Vector3(0f, 0.872f, -0.12f), new Vector3(0.2f, 0.07f, 0.2f)) { color = new Color(0f, 1f, 0f, 0.25f) } }; } #endregion #region メイン機能(UIから呼び出される) public void ApplyMeshCorrections() { Debug.Log("[MeshSyncProManager] 貫通検出を開始します"); ClearResults(); if (!ValidateInputs()) { Debug.LogWarning("[MeshSyncProManager] 入力が無効です。検出を中止します"); return; } int totalDetections = 0; foreach (GameObject bodyObj in bodyObjects.Where(obj => obj != null)) { SkinnedMeshRenderer bodyRenderer = bodyObj.GetComponent(); if (bodyRenderer == null) continue; foreach (GameObject clothingObj in clothingObjects.Where(obj => obj != null)) { Mesh clothingMesh = GetMeshFromGameObject(clothingObj); if (clothingMesh == null) continue; var detectionResult = Runtime.PenetrationDetectionCore.DetectPenetration( bodyRenderer, clothingMesh, clothingObj.transform, penetrationThreshold, dotProductThreshold ); if (detectionResult.IsSuccessful && detectionResult.PenetratingIndices.Length > 0) { var filteredResult = FilterByZones(detectionResult); var key = (bodyObj, clothingObj); penetratingIndicesResults[key] = filteredResult.PenetratingIndices; penetratingVerticesResults[key] = filteredResult.PenetratingVertices; totalDetections += filteredResult.PenetratingIndices.Length; Debug.Log($"[MeshSyncProManager] {bodyObj.name} と {clothingObj.name} 間で {filteredResult.PenetratingIndices.Length} 個の貫通を検出"); } } } Debug.Log($"[MeshSyncProManager] 検出完了: 合計 {totalDetections} 個の貫通頂点を検出しました"); } public void FixDetectedPenetrations(float pushOutDistance) { Debug.Log($"[MeshSyncProManager] 貫通修正を開始します(押し出し距離: {pushOutDistance:F4})"); int totalFixed = 0; foreach (var result in penetratingIndicesResults) { var key = result.Key; GameObject bodyObj = key.Item1; int[] penetratingIndices = result.Value; if (bodyObj != null && penetratingIndices != null && penetratingIndices.Length > 0) { SkinnedMeshRenderer bodyRenderer = bodyObj.GetComponent(); if (bodyRenderer != null) { Runtime.PenetrationFixEngine.FixPenetrationAdvanced( bodyRenderer, penetratingIndices, pushOutDistance, influenceRadiusSteps, smoothingIterations, smoothingFactor ); totalFixed += penetratingIndices.Length; Debug.Log($"[MeshSyncProManager] {bodyObj.name} の {penetratingIndices.Length} 個の頂点を修正しました"); } } } ClearResults(); Debug.Log($"[MeshSyncProManager] 修正完了: 合計 {totalFixed} 個の頂点を修正しました"); } #endregion #region 結果取得メソッド(UIから呼び出される) public Dictionary<(GameObject, GameObject), int[]> GetPenetratingIndicesResults() { return new Dictionary<(GameObject, GameObject), int[]>(penetratingIndicesResults); } public Dictionary<(GameObject, GameObject), Vector3[]> GetPenetratingVerticesResults() { return new Dictionary<(GameObject, GameObject), Vector3[]>(penetratingVerticesResults); } #endregion #region ヘルパーメソッド private bool ValidateInputs() { if (bodyObjects == null || bodyObjects.Count == 0) { Debug.LogError("[MeshSyncProManager] ボディオブジェクトが設定されていません"); return false; } if (clothingObjects == null || clothingObjects.Count == 0) { Debug.LogError("[MeshSyncProManager] 衣装オブジェクトが設定されていません"); return false; } return true; } private Mesh GetMeshFromGameObject(GameObject obj) { SkinnedMeshRenderer smr = obj.GetComponent(); if (smr != null && smr.sharedMesh != null) { return smr.sharedMesh; } MeshFilter mf = obj.GetComponent(); if (mf != null && mf.sharedMesh != null) { return mf.sharedMesh; } return null; } private Runtime.PenetrationDetectionCore.DetectionResult FilterByZones(Runtime.PenetrationDetectionCore.DetectionResult originalResult) { var activeZones = DetectionZones?.Where(z => z != null && z.active).ToArray(); if (activeZones == null || activeZones.Length == 0) { return originalResult; } var filteredIndices = new List(); var filteredVertices = new List(); for (int i = 0; i < originalResult.PenetratingIndices.Length; i++) { Vector3 vertex = originalResult.PenetratingVertices[i]; bool isInAnyZone = activeZones.Any(zone => zone.ContainsPoint(vertex)); if (isInAnyZone) { filteredIndices.Add(originalResult.PenetratingIndices[i]); filteredVertices.Add(originalResult.PenetratingVertices[i]); } } return new Runtime.PenetrationDetectionCore.DetectionResult { IsSuccessful = filteredIndices.Count > 0, PenetratingIndices = filteredIndices.ToArray(), PenetratingVertices = filteredVertices.ToArray(), RawPenetratingVertices = originalResult.RawPenetratingVertices, ErrorMessage = originalResult.ErrorMessage, DebugInfo = originalResult.DebugInfo }; } private void ClearResults() { penetratingIndicesResults.Clear(); penetratingVerticesResults.Clear(); } #endregion #region デバッグ private void OnDrawGizmos() { if (DetectionZones != null) { foreach (var zone in DetectionZones) { if (zone != null && zone.active) { Gizmos.color = zone.color; Gizmos.DrawWireCube(zone.center, zone.size); } } } } #endregion } }