gpt4 book ai didi

c# - 如何找到两个轴对齐的立方体交点的体积和顶点?

转载 作者:行者123 更新时间:2023-12-05 02:38:34 26 4
gpt4 key购买 nike

如何找到与轴对齐的两个立方体交集的体积?立方体可以有不同的大小和位置。(我添加了一张图片来展示两个立方体的简单示例)

经过深入研究,我很确定Unity中不存在用于此目的的特定函数,解决此问题的唯一方法是数学逻辑。例如,我的第一个想法是:

  1. 找到立方体“交点”的 8 个顶点(图中的 B)。

  2. 尝试用这个顶点构建一个新的立方体。

  3. 求立方体“交点”的大小和体积。

Unity 允许查找:

  • 带有“Bounds.centre”的每个主立方体(图中的 A)的中心;
  • 每个主立方体(图中的 A)从立方体中心(边界大小的一半)到“Bounds.extents”的范围。

此处提供文档:https://docs.unity3d.com/ScriptReference/Bounds.html

但是,我找不到获得每个立方体顶点的方法。其次,一个逻辑函数可以找到找到的 16 个顶点中的 8 个是用于构建立方体“交点”的正确顶点。

你有什么帮助或建议吗?

图片: enter image description here

最佳答案

如果正如您所说,立方体将始终与 Unity 世界轴对齐(=> 边界 = 碰撞器/渲染器体积),您可以简单地做一些类似的事情

  • Bounds两个盒子的
  • minmax其中
  • => 使用最小值的最大值和最大值的最小值分别检查每个轴上有多少重叠

由此得到的是重叠框的新最小点和最大点。

这是足够的信息

  • 通过将这些最小值和最大值之间的向量的各个分量相乘来计算体积。

  • 通过获取每个轴的最小值和最大值之间的所有排列来获取所有顶点。

有点像

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;
}
}


因此,为了获得重叠信息,您可以执行以下操作

// 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
}

现在为了实际获得重叠网格(如果那是你要去的地方)你有两个选择

要么使用给定的边缘点,然后自己实际创建一个网格(注意顶点位于世界空间中,因此对象本身或任何父对象都不应缩放)

...

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
}
}

作为一个小演示

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);
}
}
}

enter image description here

或者您可以改为使用现有的原始立方体(默认的 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;

再次演示一下

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);
}
}
}

enter image description here

关于c# - 如何找到两个轴对齐的立方体交点的体积和顶点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69516211/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com