327 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<GameObject> bodyObjects = new List<GameObject>();
public List<GameObject> clothingObjects = new List<GameObject>();
[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<SkinnedMeshRenderer>();
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<SkinnedMeshRenderer>();
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<SkinnedMeshRenderer>();
if (smr != null && smr.sharedMesh != null)
{
return smr.sharedMesh;
}
MeshFilter mf = obj.GetComponent<MeshFilter>();
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<int>();
var filteredVertices = new List<Vector3>();
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
}
}