Сайт о телевидении

Сайт о телевидении

» » Unity вращение объекта. Погружение в скрипты игрового движка Unity3d, ч.1

Unity вращение объекта. Погружение в скрипты игрового движка Unity3d, ч.1

Rotations in 3D applications are usually represented in one of two ways, Quaternions or Euler angles. Each has its own uses and drawbacks. Unity uses Quaternions internally, but shows values of the equivalent Euler angles in the inspector to make it easy for you to edit.

The Difference Between Euler Angles and Quaternions

Euler Angles

Euler angles have a simpler representation, that being three angle values for X, Y and Z that are applied sequentially. To apply a Euler rotation to a particular object, each rotation value is applied in turn, as a rotation around its corresponding axis.

  • Benefit : Euler angles have an intuitive “human readable” format, consisting of three angles.
  • Benefit : Euler angles can represent the rotation from one orientation to another through a turn of more than 180 degrees
  • Limitation : Euler angles suffer from Gimbal Lock . When applying the three rotations in turn, it is possible for the first or second rotation to result in the third axis pointing in the same direction as one of the previous axes. This means a “degree of freedom” has been lost, because the third rotation value cannot be applied around a unique axis.

Quaternions

Quaternions can be used to represent the orientation or rotation of an object. This representation internally consists of four numbers (referenced in Unity as x, y, z & w) however these numbers don’t represent angles or axes and you never normally need to access them directly. Unless you are particularly interested in delving into the mathematics of Quaternions , you only really need to know that a Quaternion represents a rotation in 3D space and you will never normally need to know or modify the x, y & z properties.

In the same way that a Vector can represent either a position or a direction (where the direction is measured from the origin), a Quaternion can represent either an orientation or a rotation - where the rotation is measured from the rotational “origin” or “Identity ”. It because the rotation is measured in this way - from one orientation to another - that a quaternion can’t represent a rotation beyond 180 degrees.

  • Benefit : Quaternion rotations do not suffer from Gimbal Lock.
  • Limitation : A single quaternion cannot represent a rotation exceeding 180 degrees in any direction.
  • Limitation : The numeric representation of a Quaternion is not intuitively understandable.

In Unity all Game Object rotations are stored internally as Quaternions, because the benefits outweigh the limitations.

In the Transform Inspector however, we display the rotation using Euler angles, because this is more easily understood and edited. New values entered into the inspector for the rotation of a Game Object are converted “under the hood” into a new Quaternion rotation value for the object.

As a side-effect, it is possible in the inspector to enter a value of, say, X: 0, Y: 365, Z: 0 for a Game Object’s rotation. This is a value that is not possible to represent as a quaternion, so when you hit Play you’ll see that the object’s rotation values change to X: 0, Y: 5, Z: 0 (or thereabouts). This is because the rotation was converted to a Quaternion which does not have the concept of “A full 360-degree rotation plus 5 degrees”, and instead has simply been set to be oriented in the same way as the result of the rotation.

Implications for Scripting

When dealing with handling rotations in your scripts, you should use the Quaternion class and its functions to create and modify rotational values. There are some situations where it is valid to use Euler angles, but you should bear in mind: - You should use the Quaternion Class functions that deal with Euler angles - Retrieving, modifying, and re-applying Euler values from a rotation can cause unintentional side-effects.

Creating and Manipulating Quaternions Directly

Unity’s Quaternion class has a number of functions which allow you to create and manipulate rotations without needing to use Euler angles at all. For example:

Добавление случайных элементов в игру

Сделать так, чтобы объект вращался вокруг своей оси очень просто, для этого есть функция Rotate. Кроме обычного вращения, еще можно сделать орбиту, по которой будет задано вращение относительно другого объекта, здесь поможет функция RotateAround, достаточно указать цель, ось и скорость. Но что если, нужно чтобы вращение управлялось с помощью мышки? Например, есть некая планета и надо, чтоб камера крутилась вокруг нее. Именно это мы попробуем реализовать в сегодняшнем скрипте. Дополнительно, сделаем небольшую модификацию, чтобы вращение какого-нибудь объекта тоже управлялось мышкой.

C# скрипт CameraRotateAround:

Using UnityEngine; using System.Collections; public class CameraRotateAround: MonoBehaviour { public Transform target; public Vector3 offset; public float sensitivity = 3; // чувствительность мышки public float limit = 80; // ограничение вращения по Y public float zoom = 0.25f; // чувствительность при увеличении, колесиком мышки public float zoomMax = 10; // макс. увеличение public float zoomMin = 3; // мин. увеличение private float X, Y; void Start () { limit = Mathf.Abs(limit); if(limit > 90) limit = 90; offset = new Vector3(offset.x, offset.y, -Mathf.Abs(zoomMax)/2); transform.position = target.position + offset; } void Update () { if(Input.GetAxis("Mouse ScrollWheel") > 0) offset.z += zoom; else if(Input.GetAxis("Mouse ScrollWheel") < 0) offset.z -= zoom; offset.z = Mathf.Clamp(offset.z, -Mathf.Abs(zoomMax), -Mathf.Abs(zoomMin)); X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity; Y += Input.GetAxis("Mouse Y") * sensitivity; Y = Mathf.Clamp (Y, -limit, limit); transform.localEulerAngles = new Vector3(-Y, X, 0); transform.position = transform.localRotation * offset + target.position; } }
Итак, у нас тут есть цель target , вокруг которой будем крутить камеру. Чувствительность мышки, регулируется переменной - sensitivity . И конечно же, предусмотрено смещение offset , на старте, нужно установить позицию таргета и добавить смещение. По поводу, limit , это ограничение по оси Y , если значение будет больше 90, то картинка начнет глючить, поэтому присутствует страховка. Вешаем скрипт на камеру, указываем объект + смещение и собственно смотрим, что получилось.

Если нам нужно вращать объект мышкой, то сделаем упрощенный вариант этого скрипта.

Назовем его ObjectRotate:

Using UnityEngine; using System.Collections; public class ObjectRotate: MonoBehaviour { public float sensitivity = 3; // чувствительность мышки private float X, Y; void Update () { X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity; Y += Input.GetAxis("Mouse Y") * sensitivity; Y = Mathf.Clamp (Y, -90, 90); transform.localEulerAngles = new Vector3(-Y, X, 0); } }
Этот скрипт вешаем на тот объект, который хотим вращать.

3

В настоящее время я пытаюсь использовать Unity 3D, и у меня возникла проблема. Проблема в том, что у меня есть автомобиль, который движется по дороге, а затем, когда он достигает угла, я хотел бы, чтобы он повернул за угол и повернул модель, основываясь на ее текущей скорости.

Вот код, у меня есть для перемещения объекта вперед:

Velocity += (_velocity * Time.deltaTime) + (_acceleration/2f) * Time.deltaTime * 2f; _velocity = Mathf.Clamp(_velocity, 0f, MaxVelocity); Vector3 position = this.transform.position; position += -this.transform.forward * _velocity * Time.deltaTime; this.transform.position = position;

Переменные объявляются как члены класса:

Private const float MaxVelocity = 10; private float _velocity; private float _acceleration;

Это, кажется, работает хорошо для продвижения вперед. Если бы я применил поворот, он мог бы выглядеть нормально для определенной скорости, но если скорость изменится, то вращение кажется быстрым или медленным.

Что бы я хотел (но полностью не удалось выполнить), когда придет время для поворота, тогда я бы посмотрел на скорость и вычислил плавное вращение, поэтому, когда объект совершает поворот, он всегда будет в конечном итоге независимо от того, насколько быстро он приближается к углу.

Я пробовал несколько вариантов, за бесчисленные часы, но мне не повезло!

Любые идеи?

UPDATE # 1 :

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

Из-за того, что я разработал вращение LERP с текущего направления в новое направление, сделал трюк (вид!). Итак, я создал поведение называется VehicleController и в методе Awake я добавил следующее:

Target = this.transform.rotation * Quaternion.Euler(0f, 90f, 0f);

Это дало мне цель вращение относительно моего текущего вращения, то есть мое вращение было бы равным _target для меня, чтобы быть лицом в желаемое направление. Затем я добавил следующее к методу FixedUpdate:

// Rotate if(_doTurn) { this.transform.rotation = Quaternion.Lerp(this.transform.rotation, _target, Time.fixedDeltaTime * _velocity); }

Это выполняется фактическое вращение. Ключевой частью была установка третьего параметра Time.fixedDeltaTime * _velocity . Это означало, что моя скорость вращения соответствовала моей скорости.

Мой последний FixedUpdate метод выглядел следующим образом:

// Forward _velocity += (_velocity * Time.deltaTime) + (_acceleration/2f) * Time.fixedDeltaTime * 2f; _velocity = Mathf.Clamp(_velocity, 0f, MaxVelocity); Vector3 position = this.transform.position; position += -this.transform.forward * _velocity * Time.fixedDeltaTime; this.transform.position = position; // Rotate if(_doTurn) { this.transform.rotation = Quaternion.Lerp(this.transform.rotation, _target, Time.fixedDeltaTime * _velocity); }

В этом примере я имел BoxCollider , который вызвал поворот, так что в методе OnTriggerEnter я просто установить _doTurn в true .

В настоящее время существует несколько вещей с этим:

  1. После поворота я должен был исправить позиционирование и немного вращения. Значения были примерно на 0,2, но я не мог заметить каких-либо странностей.
  2. Этот подход дает быстрое сменное изменение в направлении, которое не было тем, чем я действительно был после.В идеале мне нужна была ситуация, когда поворот был бы постепенным под определенным углом и заканчивался бы в той же точке. Но, честно говоря, все выглядит нормально, и теперь меня заставляет двигаться дальше! :)

Что касается # 1 Я думаю, что я должен был исправить некоторые из значений положения/поворота, потому что я использовал BoxCollider , чтобы вызвать поворот, так что может быть лучше всего подходит.

  • 1 ответ
  • Сортировка:

    Активность

1

Самый простой способ повернуть объект в направлении его скорости - представлять поворот в качестве вектора. Физика Юнити делает это внутренне, но, к сожалению, не позволит вам получить доступ к любой из этих переменных. Вместо этого вы можете просто применить Torque, который сделает все для вас (неплохо использовать физический движок и самостоятельно применять физику).

Сначала получите требуемое вращение.

Vector3 DesiredRotation = Quaternion.LookRotation(rigidbody.Velocity).EulerAngles;

Затем найти вращение вам нужно повернуть, чтобы попасть:

Vector3 RotationSteering = DesiredRotation - rigidbody.rotation;

Normalize RotationSteering так что вы можете получить больше контроля над степенью вращения:

RotationSteering.Normalize();

Multiply вращения управляя любой суммой, на которую вы хотите повернуть.

RotationSteering *= 30;

Применить силу затем $:

Rigidbody.AddTorque (RotationSteering);

Я не уверен, как Unity обрабатывает крутящий момент, но это физика путь. Если вы хотите полный контроль, вы можете установить вращение вручную, но это приводит к множеству неудобных вещей. Вам также придется изменить скорость вращения для реалистичных столкновений. Просто придерживайтесь стандартного (хотя и ошибочного) колеса и не изобретайте его повторно. У вас будет меньше головных болей.