bool GetNormal(Ray ray, Bounds bounds, out Vector3 point, out Vector3 normal)
{
point = Vector3.zero;
normal = Vector3.zero;
if(bounds.IntersectRay(ray,out float distance))
{
point = ray.GetPoint(distance);
var offset = bounds.center - point;
Vector3 absOffset = default;
absOffset.x = Mathf.Abs(offset.x);
absOffset.y = Mathf.Abs(offset.y);
absOffset.z = Mathf.Abs(offset.z);
// 假定相交点在AABB对角
if (Mathf.Approximately(absOffset.x, absOffset.y) && Mathf.Approximately(absOffset.y, absOffset.z))
{
for (int i = 0; i < 3; i++)
{
normal = Vector3.zero;
normal[i] = -Mathf.Sign(offset[i]);
// 这里可替换为自定义的体素碰撞计算
if (!Physics.Raycast(point - normal * 0.1f, normal, out var _, 1))
{
point[i] = bounds.center[i] + normal[i] * bounds.extents[i];
return true;
}
}
return false;
}
int one, two;
for (int i = 0; i < 3; i++)
{
one = (i + 1) % 3;
two = (i + 2) % 3;
if (absOffset[i] > absOffset[one])
{
if (absOffset[i] > absOffset[two])
{
normal[i] = -Mathf.Sign(offset[i]);
// 假定一个面有碰撞
if (Physics.Raycast(point - normal * 0.1f, normal, out var _, 0.15f))
{
i = absOffset[one] > absOffset[two] ? one : two;
}
normal = Vector3.zero;
normal[i] = -Mathf.Sign(offset[i]);
// 交点修正
// 在边界相交点的计算有时会出现误差。表现为在盒子表面反复陷入去然后弹出来
// 这里是为了保证在盒子表面
point[i] = bounds.center[i] + normal[i] * bounds.extents[i];
return true;
}
// 是否在边界
else if (Mathf.Approximately(absOffset[i], absOffset[two]))
{
normal[i] = -Mathf.Sign(offset[i]);
if (Physics.Raycast(point - normal * 0.1f, normal, out var _, 0.15f))
i = two;
normal = Vector3.zero;
normal[i] = -Mathf.Sign(offset[i]);
point[i] = bounds.center[i] + normal[i] * bounds.extents[i];
return true;
}
}
}
}
return false;
}
08-06
9487
