Mатематические кривые в 3D
Мне стало интересно посмотреть на математические кривые в 3-х мерном пространстве. Для этого я начал разбираться с Matrix3D и прочей трехмерной оснасткой в action script. Получилась вот такая штуковина:
Все последующие изображения генерятся автоматически на основе рандомных параметров. Для того чтобы сбросить и начать сначала кликните на изображении. При движении мышкой меняется ракурс (если кто не понял… :)).
В ходе работы над этой штуковиной, выяснилось, что сведений имеющихся в справочном руководстве о Matrix3D совершенно недостаточно, ну а в справке по функциям и подавно нет никаких примеров.
Идеологически понятно, как решать этот вопрос, но вот как конкретно в деталях это делается я не знал. Поиски привели меня на мой любимый wonderfl.net, и вот этот, невероятный, офигенный, трехмерный мегафеерверк дал мне ответы на все мои вопросы.
Итак, несколько слов об алгоритме. Во-первых, флеш «умеет» рисовать только в двумерном пространстве. Трехмерное api позволяет потом повернуть нарисованный примитив в трехмерном пространстве. Увы, все примеры в справочном руководстве по as3 посвящены только разбору этого варианта. Соответственно в лоб задача не решается.
А решается она традиционным путем. Сначала нужно построить кривую в трехмерном пространстве, т.е. получить массив точек, описывающих кривую, затем спроецировать ее на плоскость, и уже используя массив двумерных координат нарисовать кривую с помощью drawPath.
Вся соль состояла, чтобы понять, как именно использовать трехмерную математику флеша в этих целях, как я уже говорил, я отыскал такой пример.
Само преобразование трехмерных координат в двумерные производится с помощью Utils3D.projectVectors:
Utils3D.projectVectors (projectionMatrix, curveVertices, ProjectedCurveVertices, uvts);
В качестве аргументов скармливаем ей матрицу трансформации projectionMatrix, массив трехмерных координат curveVertices и массив ProjectedCurveVertices, который функция заполнит двумерными координатами, четвертый параметр uvts - массив координат для маппинга текстур, в данном случае я никак не использовал.
Матрица трансформации, в свою очередь создается с использованием PerspectiveProjections.
1 2 3 4 5 6 7 8 | private function setupProjectionMatrix():void { perspective.fieldOfView = 75; projectionMatrix.identity(); projectionMatrix.appendRotation(viewRotationY, Vector3D.Y_AXIS); projectionMatrix.appendRotation(viewRotationX, Vector3D.X_AXIS); projectionMatrix.appendTranslation(0, 0, perspective.focalLength); projectionMatrix.append(perspective.toMatrix3D()); |
correctMatrix3DMultiplyBug(projectionMatrix);
Utils3D.projectVectors(projectionMatrix, curveVertices, ProjectedCurveVertices, uvts);
}
Интересно, что в приведенном примере есть специальная заплатка корректирующая баг в математике умножения флешовых трехмерных матриц:
1 2 3 4 5 6 7 8 9 10 11 12 | private function correctMatrix3DMultiplyBug(matrix:Matrix3D):void { // see http://bugs.adobe.com/jira/browse/FP-670 var m1:Matrix3D = new Matrix3D(Vector.([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 ])); var m2:Matrix3D = new Matrix3D(Vector.([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ])); m1.append(m2); if (m1.rawData[15] == 20) { var rawData:Vector. = matrix.rawData; rawData[15] /= 20; matrix.rawData = rawData; } } |
Поскольку меня всегда чрезвычайно заботит внешний вид моих творений я добавил небольшой трюк со следами от кривой при ее движении. Для этого перед отрисовкой следующего кадра я смешивал свой выходной битмап с клипом из библиотеки содержащим изображение радиального градиента, а потом блюрил результат. В результате на картинке возникает едва заметный след при резких движениях.
1 2 3 |
(Если просто обрабатывать картинку блюром, то довольно быстро она вся окрашивается в цвет кривой, поэтому надо каждый раз добавлять фон.)
Вот такие чудеса. Для любителей экспериментов:
Исходники Математических кривых в 3D. (Flash CS4)
UPDATE
Усовершенствованная версия мат. кривых в 3D с эффектом DOF.
Subscribe to the RSS feed and have all new posts delivered straight to you.
Деян, привет. Я поправил ссылку. Скачивайте на здоровье!