Для проекта в Unity3D я пытаюсь трансформировать все объекты в мире, меняя кадры. Это означает, что исходная точка нового кадра поворачивается, перемещается и масштабируется в соответствии с исходной точкой старого кадра, а затем эта операция применяется ко всем другим объектам (включая старую исходную точку). Для этого мне нужна обобщенная трехмерная (таким образом, 4x4) матрица преобразования.
Я рассмотрел использование встроенного в Unity метода Matrix4x4.TRS(), но он кажется бесполезным, поскольку он применяет только перемещение, вращение и масштабирование к определенной точке. То, что я ищу, - это изменение кадров, в котором новый кадр имеет другое происхождение, поворот и масштаб по сравнению с исходным.
Чтобы визуализировать проблему, я сделал небольшой GIF (сейчас у меня есть рабочая версия в 3D, без использования Матрицы и без какого-либо вращения): https://gyazo.com/8a7ab04dfef2c96f53015084eefbdb01
Значения для каждой сферы:
Origin1 (Red Sphere)
Before:
Position (-10, 0, 0)
Rotation (0,0,0)
Scale (4,4,4)
After:
Position (10, 0, 0)
Rotation (0,0,0)
Scale (8,8,8)
-
Origin2 (Blue Sphere)
Before:
Position (-20, 0, 0)
Rotation (0,0,0)
Scale (2,2,2)
After:
Position (-10, 0, 0)
Rotation (0,0,0)
Scale (4,4,4)
-
World-Object (White Sphere)
Before:
Position (0, 0, 10)
Rotation (0,0,0)
Scale (2,2,2)
After:
Position (30, 0, 20)
Rotation (0,0,0)
Scale (4,4,4)
В настоящее время я просто беру вектор между двумя исходными точками, масштабирую его до разницы между двумя исходными точками, а затем применяю его поверх новой позиции исходной (первой) исходной точки. Это, конечно, не будет работать, если вращение применяется к любому из двух источников.
// Position in original axes
Vector3 positionBefore = testPosition.TestPosition - origin.TestPosition;
// Position in new axes
Vector3 positionAfter = (positionBefore * scaleFactor) + origin.transform.position;
То, что я ищу, - это матрица, которая может это сделать (и включать вращение, так что Origin2 поворачивается до поворота Origin1 до преобразования, а все остальные объекты перемещаются в свои правильные положения).
Есть ли способ сделать это, не выполняя полный расчет для каждого вектора (т.е. преобразовывая позицию перед вектором)? Его необходимо применять к (очень) большому количеству объектов в каждом кадре, поэтому его необходимо (достаточно) оптимизировать.
Обновлено: масштабирование ВСЕГДА будет одинаковым.
Здесь нет отношений родитель-потомок. На самом деле, в конечном результате нет даже игровых объектов, только Данные (сущности).





Могут быть и другие решения, но вот что я бы сделал
Оберните свои объекты в следующую иерархию
WorldAnchorObject
|- Red Sphere
|- Blue Sphere
|- White Sphere
Убедитесь, что на WorldAnchorObject есть
position: 0,0,0
rotation: 0,0,0
localScale: 1,1,1
позиционировать/вращать/масштабировать Сферы (теперь это будет происходить относительно WorldAnchorObject)
Теперь все, что осталось, это преобразовать WorldAnchorObject -> он будет перемещать, масштабировать и вращать все остальное, сохраняя при этом относительные преобразования.
Как именно вы переместите мировой якорь, зависит от вас. Я думаю, вы хотите всегда центрировать и нормализовать определенный дочерний объект. Может быть, что-то вроде
public void CenterOnObject(GameObject targetCenter)
{
var targetTransform = targetCenter.transform;
// The localPosition and localRotation are relative to the parent
var targetPos = transform.localPosition;
var targetRot = targetTransform.localRotation;
var targetScale = targetTransform.localScale;
// First reset everything
transform.position = Vector3.zero;
transform.rotation = Quaternion.Idendity;
transform.localScale = Vector3.one;
// set yourself to inverted target position
// After this action the target should be on 0,0,0
transform.position = targetPos * -1;
// Scale yourself relative to 0,0,0
var newScale = Vector3.one * 1/targetScale.x;
ScaleAround(gameObject, Vector3.zero, newScale);
// Now everything should be scaled so that the target
// has scale 1,1,1 and still is on position 0,0,0
// Now rotate around 0,0,0 so that the rotation of the target gets normalized
transform.rotation = Quaternion.Inverse(targetRotation);
}
// This scales an object around a certain pivot and
// takes care of the correct position translation as well
private void ScaleAround(GameObject target, Vector3 pivot, Vector3 newScale)
{
Vector3 A = target.transform.localPosition;
Vector3 B = pivot;
Vector3 C = A - B; // diff from object pivot to desired pivot/origin
float RS = newScale.x / target.transform.localScale.x; // relative scale factor
// calc final position post-scale
Vector3 FP = B + C * RS;
// finally, actually perform the scale/translation
target.transform.localScale = newScale;
target.transform.localPosition = FP;
}
Теперь вы называете это передачей одного из детей, например, например.
worldAnchorReference.CenterOnObject(RedSphere);
должно привести к тому, чего вы хотели достичь. (Взломал это на моем смартфоне, поэтому никаких гарантий, но если возникнут проблемы, я могу проверить это, как только снова буду с ПК. ;))
Нельзя использовать иерархию. Это математическая проблема, а не проблема Unity-Transform. ECS (unity.com/unity/features/job-system-ECS) даже не имеет преобразований
Неважно.. Пришлось применить вращение и масштабирование к переводу перед созданием TRS. Д'О
Я не совсем понял ... но вы знаете, что вам нужно изменить только один родительский объект, а все остальное привязать к нему как дочернее в иерархии?