Часть 6. Ось всенаправленного движения

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

В настоящее время наши волны движутся только вдоль оси X. Хотя мы могли бы заставить это работать внутри Unity, используя повороты, лучшее и более надежное решение — позволить шейдеру обрабатывать любую потенциальную ось. Для этого нам понадобится немного магии тригонометрии.

Сначала нам нужно предоставить нашему шейдеру дополнительную информацию. Пройдемся по месту в мировом пространстве, где наш щелчок мыши столкнулся с моделью, и местонахождению в мировом пространстве центра модели. Добавьте следующие строки сразу после того, как мы установили controlTime в ноль.

На этот раз вместо использования SetFloat мы используем SetVector, потому что мы передаем трехмерный вектор, а не число с плавающей запятой. Следует отметить, что _ModelOrigin и _ImpactOrigin на самом деле еще не существуют в нашем шейдере, давайте это исправим. Как обычно, определите переменные шейдера стандартным способом; один раз в разделе свойств и один раз внутри подшейдера.

Здорово! Теперь у нас есть доступ к позиции модели и позиции удара. Затем давайте создадим новый вектор float4 с именем direction, который представляет направление, в котором наша волна будет двигаться по модели. Добавьте эту строку вверху функции vert.

_ModelOrigin_ImpactOrigin даст нам волну, которая движется от места удара к центру модели.

Наше определение origin теперь нуждается в значительных изменениях. Мы возьмем базовую формулу, которую сейчас применяем к компоненту x, и применим ее ко всем векторам. «1.0», которое мы использовали в качестве начала нашей волны, теперь может быть представлено как _ImpactOrigin. _ControlTime * _ImpactSpeed могут оставаться в основном одинаковыми, за исключением того, что они просто скаляры, поэтому, чтобы перенести их в трехмерное пространство и задать им направление, умножьте их на наш вектор direction. Мы также заменили «-» в формуле на «+», так как информация о направлении теперь содержится внутри direction. Это дает нам окончательную формулу.

float4 origin = _ImpactOrigin + _ControlTime * _ImpactSpeed * direction;

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

Точно так же, как раньше мы использовали unity_ObjectToWorld для переноса позиции нашей вершины в мировое пространство, теперь мы делаем обратное и используем unity_WorldToObject для переноса координат нашей мировой позиции в пространство модели.

В начале этого раздела я упомянул «магию тригонометрии». Наш оператор модификации вершины в настоящее время выглядит так.

Обратите внимание на часть формулы v.vertex.x? Все это отлично работает, пока мы хотим, чтобы наши волны двигались только вдоль этой оси x. Чтобы избавиться от этого, нам нужно значение, представляющее ось, по которой движется наша волна от точки удара до начала координат модели. Мы назовем это значение оси impactAxis. Его значение равно следующей формуле.

Магия тригонометрии

Объяснение того, что происходит с этой формулой, к сожалению, выходит за рамки этой статьи. И я не смог бы объяснить это удовлетворительным образом, если бы это было так. Но если вам очень любопытно, формула была адаптирована из этого ответа StackOverflow. С P, представленным v.vertex, D, представленным l_direction, и A, представленным l_ImpactOrigin.

Теперь, когда у нас есть эта ось воздействия, нам больше не нужно полагаться на v.vertex.x внутри нашей функции модификации вершин. Итак, давайте заменим его нашей новой ImpactAxis.

На этом этапе вы сможете запустить Unity и протестировать приложение. Щелкните в любом месте сферы, и из этого места должна появиться новая волна.

Невидимая сфера

Если при первом запуске приложения ваша сфера исчезла, щелкните там, где она должна быть, и она должна появиться снова. Это просто означает, что ваш _ImpactOrigin начинается с (0,0,0,0). Чтобы исправить это, выберите сферу в редакторе Unity, разверните компонент JellyMaterial в нижней части Инспектора и измените источник удара на (-5,0,0,0).

Окончательный код вашего шейдера должен выглядеть так.

Часть 7 этой серии можно найти здесь.

Первоначально опубликовано на heliosinteractive.com 2 марта 2018 г.