Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Zebestov

Рейтинг: 5.00. Голосов: 7.

Free Transform в два треугольника!

Запись от Zebestov размещена 22.03.2011 в 00:20
Обновил(-а) Zebestov 06.12.2013 в 07:11

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

С чего все началось?
Как-то давно я фантазировал об инструменте Free Transform. Мысль была такая: что если наш Free Transform — это (по некой идее) не тупое тягание вершин в 2d, а некая перспективная проекция нашей картинки, раскоряченной в 3d пространстве, да так, что вот как раз и выходит неправильный четырехугольник с корректной деформацией изображения по всей площади? Мысль показалась вполне себе близкой к реальности и я начал чертить, прикидывать, считать, снова чертить. Но у меня не выходило ровным счетом ничего похожего на правду.

Ну и чем все закончилось?
После многочисленных попыток лишить себя сна поисками тех самых координат XYZ, от которых я уже возьму нужные мне T (читаем доки), я вдруг понял, что нельзя быть таким честным — нужно просто подбирать, прикидывать, снова подбирать и опять примерять формулы нахождения сразу коэффициентов T. Поглядывая в свои «честные попытки», наиболее близкие по сути, я так или иначе пришел к результату, который в оформленном виде выглядит примерно так:

Код AS3:
function freeTransform(image:BitmapData, canvas:Graphics, p1:Point, p2:Point, p3:Point, p4:Point):void
{
        // Соотношение длин диагоналей.
        var diagonalRatio:Number = Point.distance(p1, p3) / Point.distance(p2, p4);
 
        // A, B и C параметры уравнения прямой для диагонали,
        // соединяющей точки p1 и p3.
        var a1:Number = p1.y - p3.y;
        var b1:Number = p3.x - p1.x;
        var c1:Number = p1.x * p3.y - p3.x * p1.y;
 
        // A, B и C параметры уравнения прямой для диагонали,
        // соединяющей точки p2 и p4.
        var a2:Number = p2.y - p4.y;
        var b2:Number = p4.x - p2.x;
        var c2:Number = p2.x * p4.y - p4.x * p2.y;
 
        // Точка пересечения диагоналей.
        var intersection:Point = new Point();
            intersection.x = -(c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1);
            intersection.y = -(a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);
 
        // Коэффициенты T, с помощью которых мы достигаем
        // нужного эффекта.
        var t1:Number = 1 / Point.distance(p3, intersection) * diagonalRatio;
        var t2:Number = 1 / Point.distance(p4, intersection);
        var t3:Number = 1 / Point.distance(p1, intersection) * diagonalRatio;
        var t4:Number = 1 / Point.distance(p2, intersection);
 
        // Заготавливаем данные, необходимые для отрисовки
        // треугольников.
        var vertices:Vector.<Number> = new Vector.<Number>();
            vertices.push(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
        var indices:Vector.<int> = new Vector.<int>();
            indices.push(0, 1, 2, 2, 3, 0);
        var uvtdata:Vector.<Number> = new Vector.<Number>();
            uvtdata.push(0, 0, t1, 1, 0, t2, 1, 1, t3, 0, 1, t4);
 
        // Рисуем два треугольника, представляющие собой
        // конечный результат.
        canvas.beginBitmapFill(image, null, false, true);
        canvas.drawTriangles(vertices, indices, uvtdata);
        canvas.endFill();
}
Итак, что мы имеем. У нас есть метод, который хочет от нас следующие данные:

image:BitmapData
Это и есть то изображение, которое мы подвергаем трансформации. Если вы желаете трансформировать не изображение, сделайте это изображением. Метод draw() вам в помощь.

canvas:Graphics
Это наш холст. В него мы будем отрисовывать результат, который представлен всего двумя треугольниками. В качестве этого аргумента нужно передавать ссылку на свойство graphics вашего шейпа, спрайта и т.д. (myCanvasShape.graphics, myCanvasSprite.graphics).

p1:Point, p2:Point, p3:Point, p4:Point
А это, собственно, список контрольных точек от верхней левой и по часовой стрелке.

Полагаю, этого кода и описания к нему достаточно, чтобы вы смогли управиться с этим самостоятельно.

Вот так это все выглядит:

FreeTransform-DEMO.swf   (291.9 Кб)


Остается лишь один момент. Метод производит корректную трансформацию только если четыре контрольные точки представляют собой выпуклый многоугольник. В том же фотошопе поступили следующим образом: они позволяют двигать точку так, чтобы получился угол больше 180* градусов, но если ты пытаешься завершить на этом трансформацию, они вываливают тебе алерт, мол "алёэ! ты как себе это представляешь?!".

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

Код AS3:
function isConvex(p1:Point, p2:Point, p3:Point):Boolean
{
	var a:Point = new Point(p1.x - p2.x, p1.y - p2.y);
	var b:Point = new Point(p3.x - p2.x, p3.y - p2.y);
 
	return ((a.x * b.y - a.y * b.x) <= 0);
}
p1:Point, p2:Point, p3:Point
Если смотреть изнутри угла, эти три точки будут идти по часовой стрелке. Вершиной, соответственно, является точка p2. Метод возвращает true, если угол меньше 180 градусов, и false в противном случае.

С помощью этого метода следует проверить все 4 угла:

Код AS3:
var convexTest1:Boolean = isConvex(p4, p1, p2);
var convexTest2:Boolean = isConvex(p1, p2, p3);
var convexTest3:Boolean = isConvex(p2, p3, p4);
var convexTest4:Boolean = isConvex(p3, p4, p1);
Эти четыре условия проверяют каждый угол четырехугольника p1-p2-p3-p4 на предмет "выпуклости", ну т.е. чтобы каждый угол был меньше 180 градусов (true).

Однако если противоположные углы p1 и p3 будут вогнуты оба, то это тоже допустимо! Ведь в контексте 4-угольника это просто означает, что рамка флипнулась по диагонали (которая проходит через p2 и p4). То же самое применимо и к углам p2 и p4.

Поэтому когда мы получили все результаты проверки каждого угла на выпуклость, условия допустимой трансформации уже будет выглядеть так:

Код AS3:
if (convexTest1 == convexTest3 && convexTest2 == convexTest4)
{
	// вызываем наш метод freeTransform(…)
}
else
{
	// сообщаем пользователю, что он гонит!
}
Ну вроде бы уже все рассказал да показал.
Успехов!


P.S.

Жалуются люди, говорят, мол, обманул я их про «точь-в-точь как в фотошопе». Настаивают. Проверить религия не позволяет, но чуют они подвох всем сердцем своим. И трансформация какая-то не интуитивная, и на дисплейсмент больше похоже. Другое дело фотошоп, говорят, там таки по-настоящему, говорят.

Ээх, ну как могу я не пойти навстречу массам да не развеять по ветру пыль сомнений.
Вот, полюбуйтесь:

AS3-VS-Photoshop.swf   (136.4 Кб)
Вложения
Тип файла: swf AS3-VS-Photoshop.swf (136.4 Кб, 890 просмотров)
Тип файла: swf FreeTransform-DEMO.swf (291.9 Кб, 911 просмотров)
Всего комментариев 20

Комментарии

Старый 22.03.2011 00:42 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Прикольно =)
Было бы здорово на основе этого реализовать что-то вроде сетки из контрольных точек. Давно сам хотел что-то похожее сделать, все руки недокрюки
Старый 22.03.2011 14:10 silin вне форума
silin
 
Аватар для silin
офигительно )
Старый 22.03.2011 14:19 cleptoman вне форума
cleptoman
 
Аватар для cleptoman
классно.
интересно,если пару x/y заменить на более читабельный point сильно прогнется производительность?
Старый 22.03.2011 14:27 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Ну в принципе от Point кроме удобства навара не будет, только производительность упадет (даже слишком сильное слово).
Другое дело, что контекст использования позволяет любую медлительность (в разумных пределах).
Старый 22.03.2011 15:17 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Я ленивый последнее время )
можешь залить демку swf`ку, что получилось? =)
Старый 22.03.2011 15:56 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Чуть позже сделаю обязательно. Надо, согласен.
А смотреть не на что — 100% Free Transform как в Photoshop (нет, ну т.е. абсолютно такой же).
Старый 22.03.2011 16:09 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Блин, видя это в окне флешплеера сразу тепло на душе )
Да и в будущем как понадобится - сюда полезу смотреть. Спасибо )
Старый 22.03.2011 18:42 samana вне форума
samana
 
Аватар для samana
Очень классно! Спасибо!
Старый 12.11.2012 19:28 djyamato вне форума
djyamato
 
Аватар для djyamato
Полезная тузла, спасибо
Старый 13.01.2013 17:49 djyamato вне форума
djyamato
 
Аватар для djyamato
А как-нибудь после тягания вершин можно получить данные о перспективных искажениях ?
Я имею ввиду, представить что это плоскость, но повернутая в 3Д пространстве (XYZ)
Как-нибудь получить эти повороты по XYZ можно ?
Старый 14.01.2013 14:58 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Если бы вершин было 3 - было бы всегда можно, потому что любые 3 вершины всегда образуют плоскость. С 4 и более вершинами такое работать не будт. Вернее - есть вероятность, что вершины расположены в соответствии с каким-то перспективным искажением, но равновероятно, что это не так.
Вообще можно разбить прямоугольник на 2 треугольника, посчитать отклонения нормалей для каждого из них и вывести среднее, и таким образом получить отклонение от фронтальной проекции.
Старый 04.12.2013 13:00 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Лучше поздно, чем никогда запилил демку!
Старый 04.12.2013 20:39 AlexLucas вне форума
AlexLucas
 
Аватар для AlexLucas
В шопе Free Transform это набор трансформаций, это похоже конкретно на Distort, и работает по ощущениям немного не как в шопе.
Есть ощущение 3D вращения, но оно будто происходит вокруг вершины которую мы тащим, а в шопе будто вокруг центра картинки. Как-то так
Старый 05.12.2013 12:12 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
AlexLucas, теория такая теория.
Ты вот не поленись и сравни эту трансформацию с той, что в фотошопе — ой как ты удивишься!
Старый 05.12.2013 22:44 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Добавил пруф про фотошоп
Старый 06.12.2013 01:15 Akopalipsis вне форума
Akopalipsis
Zebestov Спасибо Вам! И наверное не один я был бы рад, если бы, когда нибудь, Вы её доделали, как указали выше. Чтобы можно было взять и пользоваться. А то если честно, я крутил картинку, крутил и не чего не заметил, но слова о - "точка не "проваливалась"", как то пугают.
И даже не пугают, подталкивают на просьбу, доделать
Старый 06.12.2013 07:00 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Спасибо за отзыв, стараемся.
По поводу "проваливающейся точки" добавил код и логику размышлений. Но применение, все же, оставляю за вами
Старый 06.12.2013 13:02 Hauts вне форума
Hauts
 
Аватар для Hauts
Пруф шикарен.
Старый 08.12.2013 15:22 Кот Баюн вне форума
Кот Баюн
 
Аватар для Кот Баюн
вот если бы такая штука была во Flash IDE,
допустим в виде extension)
цены бы ей не было)
Старый 28.02.2016 01:11 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Полный код демки на wonderfl.
 

 


Часовой пояс GMT +4, время: 20:34.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.