Как: инвертировать диапазон (экспоненциальный спад)?
Недавно я столкнулся со сценарием, в котором мне нужно было масштабировать значение в зависимости от расстояния между двумя объектами (камерой и целью). Первоначальная проблема заключалась в том, что камера будет прыгать слишком далеко от положения x
позиционировать y
двигаясь к target
:
У меня есть эта часть вниз, но у меня проблема с тем, что значение слишком нервное, когда я подхожу ближе к объекту, который я просматриваю.
Первоначальная идея состояла в том, чтобы масштабировать расстояние увеличения в зависимости от того, насколько близко камера была к цели; это должно было предотвратить прохождение камерой через меш цели (или вершины в DirectX 11). Хотя в более традиционных системах для предотвращения этого используется коллайдерная система, это не традиционная система, и ее нельзя кодировать как таковую. Исходный код масштабирования был прямым:
float scale = 10000f;
if (delta < 0)
while (target.Scale + (delta / scale) < 0)
scale *= 10;
else
while (target.Scale + (delta / scale) > 3)
scale *= 10;
target.Scale += delta / scale;
target.World = Matrix.Scaling(target.Scale) * Matrix.Identity;
Несколько человек высказали несколько хороших замечаний относительно того, что попробовать, но на сегодняшний день (7/8/2018) у поста до сих пор нет рабочих ответов. Таким образом, я отказался от подхода и пришел к решению, которое работает, но по-другому.
Новая проблема: другой пользователь Stack-Overflow поделился идеей, что мне следует попробовать следующую строку кода:
Position += new Vector3(-1 * Math.Sign(e.Delta) * Math.Min(10000f, (Position.X - TargetPosition.X) / c, 0, 0));
куда c
некоторая константа больше или равна двум. Это была блестящая идея; это упростило исходный код и сохранило масштабирование (что не было ответом на замедление значения, но было началом).
Это привело к тому же вопросу в другом подходе; Как я могу замедлить мою камеру, когда она приближается к цели. Ну, как я играл со значениями для c
Я заметил, что чем больше c
чем медленнее будет зум. Затем я начал ломать голову над тем, что я должен использовать, чтобы скорректировать значение для c
, Ответ должен в значительной степени включать расстояние между камерой и целью; но проблема здесь в том, что расстояние между камерой и целью уменьшается по мере приближения, и увеличивается по мере удаления. Что приводит к:
Новый вопрос: как мне взять диапазон, такой как 3 - 1000
и инвертировать его самым простым способом, чтобы стать 1000 - 3
?
1 ответ
В поисках ответа я ползла сквозь паутину. В конце концов я пришел к тому, что был готов сдаться и в итоге попросил моего друга о помощи. Через час он перезвонил мне и рассказал об экспоненциальном затухании. В своем объяснении он в значительной степени процитировал страницу Википедии:
Количество подвержено экспоненциальному убыванию, если оно уменьшается со скоростью, пропорциональной ее текущему значению.
Математика за этим была по существу:
c = m - ((m - 3) / 1 + Math.Exp(-10 * ((d - 100) / (r - 100))));
куда c
константа нужна в вопросе, m
максимальное значение для диапазона, d
расстояние между камерой и целью, и r
это радиус цели.
Реализация была очень простой на данный момент; Я удалил весь старый код и переписал метод как таковой:
Vector3 direction = Position - TargetPosition;
float distance = direction.Length();
float radius = 50000000f;
// Prevent the camera from entering the target.
if (distance <= radius * 1.5 && e.Delta > 0)
return;
// Zooming out is always the same speed.
float speed = 3;
if (e.Delta > 0) {
float t = (distance - 100) / (radius - 100);
speed = 1000 - 997 / (1 + (float)Math.Exp(-10 * t)));
}
direction.Normalize();
Vector3 directionCopy = direction;
direction *= -(Math.Sign(e.Delta) * Math.Min(1000f, distance / speed));
Position = Position + direction;
Я хотел бы поблагодарить всех других пользователей Stack-Overflow за их помощь, и если кто-то считает, что может решить исходную проблему, не стесняйтесь дать ему шанс. Кроме того, если вы чувствуете, что у вас есть лучшее решение, не стесняйтесь поделиться им!