【问题标题】:Calculate bounds of a box including rotation计算框的边界,包括旋转
【发布时间】:2015-11-18 05:43:20
【问题描述】:

我正在为使用自定义碰撞器的游戏开发碰撞系统。我使用this 为碰撞创建边界框。

对于使用右值和前向值创建框的框,我遇到了问题。否则它工作正常。任何人都知道如何在计算立方体的 8 个点时包含右向量和前向量。

以下是我的积分计算代码:

 public static void GetBoundsPointsNoAlloc(BoxRegion bx, Matrix4x4 colliderBox4x4,Vector3[] points, Matrix4x4 mx) {
 Transform tr = Utils.FromMatrix4x4(ref DebugCollisionTestSphere.trans,mx);

 Vector3 v3Center = bx.center;
 Vector3 v3ext = bx.GetExtents();
 Vector3 right = bx.right;
 Vector3 forw = bx.forward;

   //Quaternion qua =Quaternion.LookRotation(bx.forward,Vector3.Cross     (bx.forward, bx.right));

   //tr.TransformDirection (bx.forward);
   //tr.localRotation = qua;
   tr.forward = bx.forward;
   tr.right =   bx.right;
   //tr.rotation = qua;

 points [0] = tr.TransformPoint (new Vector3 (v3Center.x - v3ext.x, v3Center.y + v3ext.y, v3Center.z - v3ext.z));  // Front top left corner
 points [1] = tr.TransformPoint (new Vector3 (v3Center.x + v3ext.x, v3Center.y + v3ext.y, v3Center.z - v3ext.z));  // Front top right corner
 points [2] = tr.TransformPoint (new Vector3 (v3Center.x - v3ext.x, v3Center.y - v3ext.y, v3Center.z - v3ext.z));  // Front bottom left corner
 points [3] = tr.TransformPoint (new Vector3 (v3Center.x + v3ext.x, v3Center.y - v3ext.y, v3Center.z - v3ext.z));  // Front bottom right corner
 points [4] = tr.TransformPoint (new Vector3 (v3Center.x - v3ext.x, v3Center.y + v3ext.y, v3Center.z + v3ext.z));  // Back top left corner
 points [5] = tr.TransformPoint (new Vector3 (v3Center.x + v3ext.x, v3Center.y + v3ext.y, v3Center.z + v3ext.z));  // Back top right corner
 points [6] = tr.TransformPoint (new Vector3 (v3Center.x - v3ext.x, v3Center.y - v3ext.y, v3Center.z + v3ext.z));  // Back bottom left corner
 points [7] = tr.TransformPoint (new Vector3 (v3Center.x + v3ext.x, v3Center.y - v3ext.y, v3Center.z + v3ext.z));  // Back bottom right corner
 }

当我应用四元数进行变换时,盒子正在改变它的位置

【问题讨论】:

    标签: unity3d rotation quaternions bounds qvector3d


    【解决方案1】:

    您需要将框的方向(存储为右和前)连接到世界变换。像这样的东西应该可以工作:

    Vector3 fwd=bx.forward.normalized(), rt=br.right.normalized(), up=fwd.Cross(rt);
    Quaternion qbox; qbox.SetLookRotation(fwd,up);
    tr.rotation = tr.rotation*qbox;
    

    (由于 Unity 是令人讨厌的左撇子,您可能不得不稍微调整一下符号和连接顺序,或者在 SetLookRotation 中使用 rt 而不是 fwd)

    更新:经过聊天中的讨论,这似乎是最终的工作版本。

    Quaternion quat = Quaternion.identity; 
    quat.SetLookRotation(bx.forward, Vector3.Cross(bx.forward,bx.right)); 
    points[0] = mx.MultiplyPoint3x4(quat * new Vector3(-bx.width/2,+bx.height/2,-bx.depth/2)+bx.center); 
    ...
    points[7] = mx.MultiplyPoint3x4(quat * new Vector3(+bx.width/2,-bx.height/2,+bx.depth/2)+bx.center);
    

    【讨论】:

    • 嗨,我实现了这个解决方案,但仍然有一些框区域在应用旋转时没有正确定位。请找到附图,在图像中黄色框旋转但8个角点有不同的位置dropbox.com/s/ezojb9vdd17nqq2/…
    • 尝试翻转串联,即 tr.rotation = qbox*tr.rotation
    • 嗯好吧,说实话,我自己从来没有使用过统一,但我使用了盒子转换,我遇到了你遇到的问题。似乎有报道称 SetLookRotation 被窃听了forum.unity3d.com/threads/…
    • 如果您拥有所有 3 个向量,您还可以通过将它们设置为列(或行,不确定它如何统一工作)来从它们构建一个旋转矩阵。似乎是 col 0=x=right, 1=y=up, 2=z=forward。最后一列应该是 'identity' (0,0,0,1) 然后这个矩阵应该与全局矩阵连接
    • 矩阵乘法让事情变得更糟,现在角落和游戏对象的位置之间有对数距离。
    【解决方案2】:

    让我们根据 Unity3D 框架中本机可用的类来重新定义这个问题。如果你对数学有足够的了解,你可以把它应用到你正在使用的其他课程中。

    如果您只需要axis-aligned bounding box(或AABB),那么您可以通过它们各自的bounds 属性从任何RendererCollider 轻松获取。这是一个快速的解决方案,在许多情况下就足够了。

    其他一些边界框在本地空间中表示 - 例如,Mesh 具有在本地空间中的 bounds 属性。无论出于何种原因,有时您会得到一个尺寸较大、向右和向前的盒子,您可能需要将该盒子的点转换到世界空间中。

    假设我们的盒子是这样的:

           size.x
       .+------+
     .' |    .'|
    +---+--+'  | size.y      (all around some point 'center')
    |   |  |   |
    |  ,+--+---+
    |.'    | .' size.z 
    +------+'   
    

    假设我们有一个以零为中心的单位立方体:

    Vector3 center = Vector3.zero;
    Vector3 size = Vector3.one;
    

    框的范围是其大小的一半:

    Vector3 extents = size * 0.5f;
    

    这使得计算框周围的八个点变得很容易:

    Vector3[] points = new Vector3[8];
    points[0] = center + new Vector3( extents.x,  extents.y,  extents.z);
    points[1] = center + new Vector3( extents.x,  extents.y, -extents.z);
    points[2] = center + new Vector3( extents.x, -extents.y,  extents.z);
    points[3] = center + new Vector3( extents.x, -extents.y, -extents.z);
    points[4] = center + new Vector3(-extents.x,  extents.y,  extents.z);
    points[5] = center + new Vector3(-extents.x,  extents.y, -extents.z);
    points[6] = center + new Vector3(-extents.x, -extents.y,  extents.z);
    points[7] = center + new Vector3(-extents.x, -extents.y, -extents.z);
    

    这些点仍然在本地空间中。我们只需要一个transform 组件就可以将它们转换为世界空间:

    for (int i=0; i<8; i++) {
        points[i] = transform.TransformPoint(points[i]);
    }
    

    【讨论】:

    • 嗨@rutter,我的盒子是自定义的,我无法从渲染器或对撞机中得到它。我的基本要求是将如图所示的右向量和前向量包括在8个点的计算中。
    • 我无法使用您的 BoxRegion 课程提供答案,因为您没有详细描述它。正如我所说:如果你对数学有足够的了解,你可以把它应用到你正在使用的其他课程中。
    • 这里是 box region 类dropbox.com/s/36fret8cp0o1lz2/Region.cs?dl=0 的链接,过去 2 天我一直在努力实现,但尝试过的事情可能不正确..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 2010-10-11
    • 2019-01-05
    • 1970-01-01
    • 2014-05-25
    • 1970-01-01
    • 2021-11-11
    相关资源
    最近更新 更多