Files
XRLib/Assets/Runtime Transform Gizmos/Scripts/Runtime Package Common/Utilities/Object2ObjectSnapData.cs
2025-06-19 19:24:30 +09:00

141 lines
6.5 KiB
C#

using UnityEngine;
using System;
using System.Collections.Generic;
namespace RTG
{
public class Object2ObjectSnapData
{
private GameObject _gameObject;
private AABB[] _snapAreaBounds = new AABB[Enum.GetValues(typeof(BoxFace)).Length];
private BoxFaceAreaDesc[] _snapAreaDesc = new BoxFaceAreaDesc[Enum.GetValues(typeof(BoxFace)).Length];
private List<Vector3> _vertsBuffer = new List<Vector3>();
public bool Initialize(GameObject gameObject)
{
if (gameObject == null || _gameObject != null) return false;
Mesh mesh = gameObject.GetMesh();
Sprite sprite = gameObject.GetSprite();
if (mesh == null && sprite == null) return false;
bool useMesh = true;
if (mesh == null) useMesh = false;
RTMesh rtMesh = null;
if (useMesh)
{
Renderer meshRenderer = gameObject.GetMeshRenderer();
if (meshRenderer == null || !meshRenderer.enabled) useMesh = false;
rtMesh = RTMeshDb.Get.GetRTMesh(mesh);
if (rtMesh == null) useMesh = false;
}
if (rtMesh == null && sprite == null) return false;
List<AABB> vertOverlapAABBs = BuildVertOverlapAABBs(gameObject, useMesh ? null : sprite, useMesh ? rtMesh : null);
if (vertOverlapAABBs.Count == 0) return false;
AABB modelAABB = useMesh ? rtMesh.AABB : ObjectBounds.CalcSpriteModelAABB(gameObject);
var aabbFaces = BoxMath.AllBoxFaces;
_gameObject = gameObject;
if (useMesh)
{
foreach (var aabbFace in aabbFaces)
{
AABB overlapAABB = vertOverlapAABBs[(int)aabbFace];
rtMesh.OverlapModelVerts(overlapAABB, _vertsBuffer);
Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace);
_snapAreaBounds[(int)aabbFace] = new AABB(facePlane.ProjectAllPoints(_vertsBuffer));
_snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace);
}
}
else
{
foreach (var aabbFace in aabbFaces)
{
if (aabbFace != BoxFace.Front && aabbFace != BoxFace.Back)
{
AABB overlapAABB = vertOverlapAABBs[(int)aabbFace];
List<Vector3> overlappedVerts = ObjectVertexCollect.CollectModelSpriteVerts(sprite, overlapAABB);
Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace);
overlappedVerts = facePlane.ProjectAllPoints(overlappedVerts);
_snapAreaBounds[(int)aabbFace] = new AABB(overlappedVerts);
_snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace);
}
else
{
_snapAreaBounds[(int)aabbFace] = AABB.GetInvalid();
_snapAreaDesc[(int)aabbFace] = BoxFaceAreaDesc.GetInvalid();
}
}
}
return true;
}
public BoxFaceAreaDesc GetWorldSnapAreaDesc(BoxFace boxFace)
{
Vector3 boxSize = _snapAreaBounds[(int)boxFace].Size;
boxSize = Vector3.Scale(boxSize, _gameObject.transform.lossyScale.Abs());
return BoxMath.GetBoxFaceAreaDesc(boxSize, boxFace);
}
public List<OBB> GetAllWorldSnapAreaBounds()
{
if (_gameObject == null) return new List<OBB>();
Transform objectTransform = _gameObject.transform;
var worldSnapOBBs = new List<OBB>(_snapAreaBounds.Length);
foreach (var aabb in _snapAreaBounds)
{
worldSnapOBBs.Add(new OBB(aabb, objectTransform));
}
return worldSnapOBBs;
}
public OBB GetWorldSnapAreaBounds(BoxFace boxFace)
{
if (_gameObject == null) return OBB.GetInvalid();
Transform objectTransform = _gameObject.transform;
return new OBB(_snapAreaBounds[(int)boxFace], objectTransform);
}
private List<AABB> BuildVertOverlapAABBs(GameObject gameObject, Sprite sprite, RTMesh rtMesh)
{
if (sprite == null && rtMesh == null) return new List<AABB>();
const float overlapAmount = 0.2f;
float halfOverlapAmount = overlapAmount * 0.5f;
AABB modelAABB = sprite != null ? ObjectBounds.CalcSpriteModelAABB(gameObject) : rtMesh.AABB;
Vector3 modelAABBSize = modelAABB.Size;
List<BoxFace> modelAABBFaces = BoxMath.AllBoxFaces;
const float sizeEps = 0.001f;
Vector3[] overlapAABBSizes = new Vector3[modelAABBFaces.Count];
overlapAABBSizes[(int)BoxFace.Left] = new Vector3(overlapAmount, modelAABBSize.y + sizeEps, modelAABBSize.z + sizeEps);
overlapAABBSizes[(int)BoxFace.Right] = new Vector3(overlapAmount, modelAABBSize.y + sizeEps, modelAABBSize.z + sizeEps);
overlapAABBSizes[(int)BoxFace.Bottom] = new Vector3(modelAABBSize.x + sizeEps, overlapAmount, modelAABBSize.z + sizeEps);
overlapAABBSizes[(int)BoxFace.Top] = new Vector3(modelAABBSize.x + sizeEps, overlapAmount, modelAABBSize.z + sizeEps);
overlapAABBSizes[(int)BoxFace.Back] = new Vector3(modelAABBSize.x + sizeEps, modelAABBSize.y + sizeEps, overlapAmount);
overlapAABBSizes[(int)BoxFace.Front] = new Vector3(modelAABBSize.x + sizeEps, modelAABBSize.y + sizeEps, overlapAmount);
var overlapAABBs = new List<AABB>();
for (int boxFaceIndex = 0; boxFaceIndex < modelAABBFaces.Count; ++boxFaceIndex)
{
BoxFace modelAABBFace = modelAABBFaces[boxFaceIndex];
Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(modelAABB.Center, modelAABB.Size, Quaternion.identity, modelAABBFace);
Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(modelAABB.Center, modelAABB.Size, Quaternion.identity, modelAABBFace);
Vector3 overlapCenter = faceCenter - faceNormal * halfOverlapAmount;
overlapAABBs.Add(new AABB(overlapCenter, overlapAABBSizes[boxFaceIndex]));
}
return overlapAABBs;
}
}
}