Рассчитать границы коробки, включая вращение

введите описание изображения здесь

Я работаю над системой столкновений для моей игры, в которой используются нестандартные коллайдеры. Я использовал это, чтобы создать ограничивающую рамку для столкновений.

Я получаю проблему для ящиков, где для создания ящика были использованы правильные и прямые значения. В противном случае он работает нормально. У любого есть идея, как включить правый и прямой векторы в вычисление 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
 }

Коробка меняет свою позицию, когда я применяю кватернион для преобразования

2 ответа

Решение

Вам нужно будет объединить ориентацию блока (сохраненную как Право и Вперед) с трансформацией мира. Нечто подобное должно работать:

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 раздражающе левша, вам, возможно, придется немного поиграться со знаками и порядком объединения, или, возможно, использовать rt вместо fwd в SetLookRotation)

Обновление: после обсуждения в чате, это, кажется, окончательная рабочая версия.

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

Давайте переопределим эту проблему с точки зрения классов, которые изначально доступны в рамках Unity3D. Если вы достаточно хорошо понимаете математику, вы можете взять ее и адаптировать для других используемых вами классов.

Если все, что вам нужно, это ограничивающий ось ограничивающий прямоугольник (или AABB), то вы можете легко получить это из любого Renderer или же Collider через их соответствующие bounds свойства. Это быстрое решение, которое будет достаточно во многих случаях.

Некоторые другие ограничительные рамки выражены в локальном пространстве - например, 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]);
}
Другие вопросы по тегам