Enr*_*era 4 c# unity-game-engine
如何找到与轴对齐的两个立方体相交的体积?立方体可以具有不同的尺寸和位置。(我添加一张图片来显示两个立方体的简单示例)
经过深入研究,我非常确定Unity中不存在用于此目的的特定函数,解决这个问题的唯一方法是数理逻辑。例如,我的第一个想法是:
找到立方体“交点”的 8 个顶点(图中的 B)。
尝试用这个顶点构建一个新的立方体。
求立方体“交点”的大小和体积。
Unity 允许查找:
此处提供文档: https: //docs.unity3d.com/ScriptReference/Bounds.html
但是,我找不到一种方法来获得每个立方体的顶点。其次,一个逻辑函数可以找到所找到的 16 个顶点中的 8 个是用于构建立方体“交点”的正确顶点。
你有什么帮助或建议吗?
如果正如你所说,立方体将始终与 Unity 世界轴对齐(=> 边界 = 对撞机/渲染器体积),你可能可以简单地执行类似的操作
你得到的是重叠框的新的最小和最大点。
这是足够的信息
通过将这些最小值和最大值之间的向量的各个分量相乘来计算体积。
通过获取每个轴的最小值和最大值之间的所有排列来获取所有顶点。
就像是
public class OverlapArea
{
public readonly Vector3 min;
public readonly Vector3 max;
public readonly float volume;
public Vector3 frontBottomLeft => min;
public readonly Vector3 frontBottomRight;
public readonly Vector3 frontTopLeft;
public readonly Vector3 frontTopRight;
public readonly Vector3 backBottomLeft;
public readonly Vector3 backBottomRight;
public readonly Vector3 backTopLeft;
public Vector3 backTopRight => max;
public readonly Bounds bounds;
public OverlapArea(Bounds a, Bounds b)
{
// The min and max points
var minA = a.min;
var maxA = a.max;
var minB = b.min;
var maxB = b.max;
min.x = Mathf.Max(minA.x, minB.x);
min.y = Mathf.Max(minA.y, minB.y);
min.z = Mathf.Max(minA.z, minB.z);
max.x = Mathf.Min(maxA.x, maxB.x);
max.y = Mathf.Min(maxA.y, maxB.y);
max.z = Mathf.Min(maxA.z, maxB.z);
frontBottomRight = new Vector3(max.x, min.y, min.z);
frontTopLeft = new Vector3(min.x, max.y, min.z);
frontTopRight = new Vector3(max.x, max.y, min.z);
backBottomLeft = new Vector3(min.x, min.y, max.z);
backBottomRight = new Vector3(max.x, min.y, max.z);
backTopLeft = new Vector3(min.x, max.y, max.z);
// The diagonal of this overlap box itself
var diagonal = max - min;
volume = diagonal.x * diagonal.y * diagonal.z;
bounds.SetMinMax(min, max);
}
public static bool GetOverlapArea(Bounds a, Bounds b, out OverlapArea overlapArea)
{
overlapArea = default;
// If they are not intersecting we can stop right away ;)
if (!a.Intersects(b)) return false;
overlapArea = new OverlapArea(a, b);
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,为了获得重叠信息,您可以这样做,例如
// I intentionally used the Bounds as parameters for the method because you can
// either use the Renderer bounds
var boundsA = cubeA.GetComponent<Renderer>().bounds;
// or use Collider bounds in your case they should be equal
var boundsB = cubeB.GetComponent<Collider>().bounds;
if(GetOverlapArea(boundsA, boundsB, out var overlap))
{
// Now in overlap you have all the information you wanted
}
Run Code Online (Sandbox Code Playgroud)
现在为了真正获得重叠网格(如果那是你要去的地方)你有两个选择
使用给定的边缘点并自己实际创建一个网格(注意顶点位于世界空间中,因此对象本身或任何父对象上不应缩放)
...
var mesh = new Mesh
{
vertices = new[]
{
overlapArea.frontBottomLeft,
overlapArea.frontBottomRight,
overlapArea.frontTopLeft,
overlapArea.frontTopRight,
overlapArea.backBottomLeft,
overlapArea.backBottomRight,
overlapArea.backTopLeft,
overlapArea.backTopRight
},
triangles = new[]
{
// Front
0, 2, 1,
1, 2, 3,
// Back
5, 7, 4,
4, 7, 6,
// Left
4, 6, 2,
4, 2, 0,
// Right
1, 7, 5,
1, 3, 7,
// Top
2, 7, 3,
2, 6, 7,
// Bottom
0, 4, 1,
1, 4, 5
}
}
Run Code Online (Sandbox Code Playgroud)
作为一个小演示
public class Example : MonoBehaviour
{
public Renderer CubeA;
public Renderer CubeB;
public Material overlapMaterial;
private MeshFilter overlap;
private readonly Vector3[] overlapVertices = new Vector3[8];
public void Awake()
{
overlap = new GameObject("Overlap", typeof(MeshRenderer)).AddComponent<MeshFilter>();
var overlapMesh = new Mesh
{
vertices = overlapVertices,
triangles = new[]
{
// Front
0, 2, 1,
1, 2, 3,
// Back
5, 7, 4,
4, 7, 6,
// Left
4, 6, 2,
4, 2, 0,
// Right
1, 7, 5,
1, 3, 7,
// Top
2, 7, 3,
2, 6, 7,
// Bottom
0, 4, 1,
1, 4, 5
}
};
overlap.mesh = overlapMesh;
overlap.GetComponent<Renderer>().material = overlapMaterial;
}
public void Update()
{
if (OverlapArea.GetOverlapArea(CubeA.bounds, CubeB.bounds, out var overlapArea))
{
overlap.gameObject.SetActive(true);
overlap.mesh.vertices = new[]
{
overlapArea.frontBottomLeft,
overlapArea.frontBottomRight,
overlapArea.frontTopLeft,
overlapArea.frontTopRight,
overlapArea.backBottomLeft,
overlapArea.backBottomRight,
overlapArea.backTopLeft,
overlapArea.backTopRight
};
overlap.mesh.RecalculateBounds();
}
else
{
overlap.gameObject.SetActive(false);
}
}
}
Run Code Online (Sandbox Code Playgroud)
或者您可以使用已经存在的原始立方体(默认的 Unity 立方体)并将其设置为正确的坐标并像这样缩放它
overlapVisualizer.transform.position = overlap.bounds.center;
// note we set the local scale so there should be no parent scaling
overlapVisualizer.transform.localScale = overlap.bounds.size;
Run Code Online (Sandbox Code Playgroud)
再看一个小演示
public class Example : MonoBehaviour
{
public Renderer CubeA;
public Renderer CubeB;
public Transform overlap;
public void Update()
{
if (OverlapArea.GetOverlapArea(CubeA.bounds, CubeB.bounds, out var overlapArea))
{
overlap.gameObject.SetActive(true);
overlap.position = overlapArea.bounds.center;
overlap.localScale = overlapArea.bounds.size;
}
else
{
overlap.gameObject.SetActive(false);
}
}
}
Run Code Online (Sandbox Code Playgroud)