141 lines
6.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|