Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Рендеринг воды и нечто вроде metaballs (http://www.flasher.ru/forum/showthread.php?t=127628)

Герыч 19.07.2009 01:48

Рендеринг воды и нечто вроде metaballs
 
Уже около месяца в свободное время от прошедшей сессии и поездки во Владикавказ к родне я пытаюсь запрогать воду. Сейчас передо мной стоит задача отображения воды на экране. Вода - 100-200 частиц, которые движутся, взаимодействую друг с другом.

Сейчас добился немного похожего на воду вида... но всё это происходит слишком медленно.
Вот мои примеры:
100 частиц
150 частиц
200 частиц

Тут есть примеры без прорисовки воды. Скорость заметно различается...

Для рисования всего этого дела я поступаю так:

Код AS3:

                        var particleBitmap:BitmapData=canvas.bitmapData;
                        var w:uint=canvas.width;
                        var h:uint=canvas.height;
                        var rect:Rectangle=new Rectangle(0, 0, w, h);
                        var m:Matrix;
                        var i:int;
                        var p:BaseParticle;
 
                        particleBitmap.lock();
                        particleBitmap.fillRect(new Rectangle(0, 0, w, h), 0);
 
                        bubbles.clear();
 
                        for (i=0; i<ptCount; i++)
                        {
                                p=pt[i];
                                m=new Matrix();
                                m.createGradientBox(50, 50, 0, p.xx-25, p.yy-25);
                                bubbles.beginGradientFill(GradientType.RADIAL, [0xFF,0xFF], [1,0], [60, 255],m);                    //рисую полупрозрачные кружки от центра к краям
                                bubbles.drawCircle(p.xx, p.yy, 25);
                                bubbles.endFill();
                        }
 
                        particleBitmap.draw(bubblesShape);
                        particleBitmap.threshold(particleBitmap,rect, new Point(0, 0), "<", 0xA0000000);        //отсекаю всё слишком прозрачное
                        particleBitmap.colorTransform(rect,new ColorTransform(1,1,1,1,0,0,0,255));              //убираю прозрачность
                        particleBitmap.unlock();

По идее код близок к metaballs, да и результат такой же. Теперь вопрос:
кто-нибудь может придумать быстрее?

etc 19.07.2009 10:35

GlowFilter?

Герыч 19.07.2009 13:36

не, GlowFilter не тот результат даёт. Да и работает так же медленно..

WRC_S 19.07.2009 13:57

Глянь это http://www.silin.fatal.ru/#AS3/filters/ripple

Герыч 19.07.2009 15:40

последнее совсем не на ту тему...

alatar 19.07.2009 17:51

http://asluv.com/2007/09/20/interact...s3-experiment/

Яски 19.07.2009 21:09

Во флеш отрисовка очень медленная, а тем более работа с битмапой. Можно сильно ускорить алгоритм, если удастся решить задачу только математикой, без отрисовки. Т.е. аналитически находить границу воды и рисовать только ее. Можно попытаться немного ускорить алгоритм, использовав PixelBender, но не факт что ускорение будет иметь место.

Герыч 20.07.2009 00:46

Цитата:

математикой, без отрисовки
единственное, что я знаю-это metaballs. В принципе тут я делаю это же. Если это делать математикой, то выходит медленней.

Мысли были на тему metabal+marching squares. но тут опять проблема: если делать размер сетки мелким-получаем медленную прорисовку(много вычислений), если делать крупную-то marching squares будет рисовать некрасивые фигурки..

alatar 20.07.2009 00:59

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

Герыч 20.07.2009 01:04

уже сделал) то был набросок кода, но скорость заметно не изменилась. Ещё вместо рисования одного и того же кружка в разных местах
Код AS3:

                                bubbles.beginGradientFill(GradientType.RADIAL, [0xFF,0xFF], [1,0], [60, 255],m);                    //рисую полупрозрачные кружки от центра к краям
                                bubbles.drawCircle(p.xx, p.yy, 25);
                                bubbles.endFill();

я рисую только один и перерисовываю его в нужном месте с помощью draw, но это сильно не меняет..

ещё добавлю) может я не совсем понимаю, как работает прорисовка во флэше, т.е. вообще сами Bitmap'ы и все display object'ы, но как я понял скорость работы treshold зависит от того, нарисовано ли что-нито на битмапе или нет)

alatar 20.07.2009 01:14

А как она может не зависеть? Если все пиксели не проходят проверку, код будет выполняться быстрее, так как не выполняются операции над пикселями.

Герыч 20.07.2009 11:43

а там Bitmap устроен так, что если ничего на нём не нарисовать, то в нём не будет пикселей вообще?

iflamberg 20.07.2009 16:26

Искал что-то свое, нашел случайно.
http://www.petrileskinen.fi/Actionscript/Metaballs.php

Может пригодится? =/ Тормозит, правда, еще больше чем у тебя, но может это из-за освещения.

Герыч 20.07.2009 17:17

Попробовал его способ(вместо treshold сделать ColorMatrixFilter), вышло раза в 3 медленней..

iflamberg 20.07.2009 17:23

ну, нужно для начал определеить узкое место. Является ли им threshold, или все таки
Код:

                        bubbles.beginGradientFill(GradientType.RADIAL, [0xFF,0xFF], [1,0], [60, 255],m);                    //рисую полупрозрачные кружки от центра к краям
                                bubbles.drawCircle(p.xx, p.yy, 25);
                                bubbles.endFill();

И я все таки, бы попробовал рисовать элементы мувиками, накладывать вместо градиентов glow на родительский мувик элементов и делать threshold на полученом мувике. Все таки glow ты один раз наложешь, а градиенты ты друг за другом рисуешь.

Герыч 20.07.2009 17:42

от градиентов в цикле я избавился. Теперь его я 1 раз рисую до начала симуляции:
Код AS3:

                        bubble=this.bubbleShape.graphics;
                        bubble.clear();
 
                        m=new Matrix();
                        m.createGradientBox(2*r, 2*r, 0, -r, -r);
                        bubble.beginGradientFill(GradientType.RADIAL, [0xFF,0xFF], [1,0], [30, 255],m);
                        bubble.drawCircle(0, 0, r);
                        bubble.endFill();


потом уже при рисовании:
Код AS3:

                        var i:int;
                        var p:BaseParticle;
                        var m:Matrix;
                        m=new Matrix();
 
                        for (i=0; i<ptCount; i++)
                        {
                                p=pt[i];
                                m.tx=p.xx;
                                m.ty=p.yy;
                                bmp.draw(bubbleShape,m);
                        }
 
                        var rect:Rectangle=new Rectangle(0, 0, w, h);
                        bmp.threshold(bmp,rect, new Point(0, 0), "<", 0xA0000000)
                        bmp.unlock();


iflamberg 20.07.2009 17:45

Тут, короче, оптимизировать нечего =) Ну кроме заменить for на while (i--) - говорят он быстрее. Или написать более быстрый программный аналог threshold =/

Герыч 20.07.2009 17:55

неее) щас посмотрел, что жрёт время.. цикл-50-60 мс, всё остальное 1-2 мс.
В чём тогда проблема? я не понимаю... вот это
Код AS3:

bmp.draw(bubbleShape,m);

занимает по времени 0.3 мс примерно.. есть ли какой-нибудь более быстрый способ рисования готовой картинки на bmp?

iflamberg 20.07.2009 18:01

Ну 50мс - это довольно много. Собственно - это падение до 20 fps.

Яски 20.07.2009 18:03

сopyPixels быстрее

Герыч 20.07.2009 18:18

copyPixels, как я понял, тупо копирует значения пикселей. А мне надо именно накладывать одно на другое. Сама идея метода в том, что вокруг капли делается круг с растущей от центра прозрачностью. Когда 2 круга рядом, между ними изображение становится менее прозрачным. Получается слияние капелек. Может я неверно понял работу copyPixels, но я даже проверил и ничего дельного не получил..

VVall 20.07.2009 18:34

copyPixels не совсем тупо копирует, он учитывает альфа-канал. То есть, вам надо нарисовать градиентный круг в альфа-канале, а RGB залить сплошным цветом.

Герыч 20.07.2009 18:42

Опа, я сильно ошибся про CopyPixels! Надо было просто FillRect сделать! fps вырос на 10!

iflamberg 20.07.2009 18:47

покаж, покаж

Герыч 20.07.2009 18:55

Зацените скорость! 100,150,200,300. Можно мышкой их толкать.

iflamberg 20.07.2009 18:58

это офигенно! Веса им только чуть-чуть добавить и вязкости.

Герыч 20.07.2009 19:00

Спасибо! это уже другая тема) А быстроты прорисовки я добился! Ура)

Яски 20.07.2009 19:30

Круто, молодец! А можешь их уменьшить и больше кол-во сделать?

Герыч 20.07.2009 19:47

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

MonkDead 20.07.2009 20:13

Герыч, молодец.
Когда вы подняли тему 200 шариков у меня показывали 17FPS, теперь 108. Серьезно постарались, респект и удачи вам в дальнейших опытах. Оптимизация великая вещь :)

Герыч 20.07.2009 22:52

Спасибо) у меня 108 не выдаёт.. у меня на 46 держится. Но может это и к лучшему, что у меня не оч быстрый комп)

AL.exe 21.07.2009 01:28

У меня ~70-80 на Core2duo 2.4, винда

Сделано потрясно, респект.

MonkDead 21.07.2009 02:23

AL.exe, хм у меня как бы тоже самое, странный разброс :)

AL.exe 21.07.2009 04:08

Возможно наврал, может быть, там 2.1. У меня столько компов, что я путаюсь :)

Добавлено через 1 минуту
Вы, наверное, 200 шаров смотрите, а не 300 :)

MonkDead 21.07.2009 11:32

Цитата:

Вы, наверное, 200 шаров смотрите, а не 300
Да, именно про них и писал, так как демки на 300 шаров в самом начале не было, а я проводил сравнительный анализ оптимизации.

Кстати 300 шаров показывают так же как и у вас 70-80 :)

Герыч 21.07.2009 12:34

Ну у вас и компы...) интересно, а у среднего пользователя, какая скорость?

А ещё сегодня возник вопрос. Сколько реально кадров в секунду на экране показывается? Т.е. есть ли смысл просчитывать графику для лишних кадров, если их никто не увидит? Вся моя симуляция фактически находится в ENTER_FRAME листенере. И в нём и физика считается и графика(то что было выше рассмотрено)

VVall 21.07.2009 12:46

Реально - зависит от монитора и того, как вы сделали синхронизацию. Если просто ENTER_FRAME, то частота ограничена установленным stage.frameRate. У современных TFT частота обновления экрана около 75 Гц, у CRT может быть все 150 (также зависит от разрешения).

Alex Lexcuk 21.07.2009 13:14

>>Реально - зависит от монитора и того, как вы сделали синхронизацию. Если просто ENTER_FRAME, то частота ограничена установленным stage.frameRate. У современных TFT частота обновления экрана около 75 Гц, у CRT может быть все 150 (также зависит от разрешения).

На частоту монитора флешу пофонарю, так-же как и монитору на флеш плеер.
Просто все раскидывается и отрисовуется ,только то, что в данный момент, а фреймы идут типа таймера.

Герыч 21.07.2009 13:24

то есть я сделал правильно поместив просчёт физики и прорисовку в одном месте??

VVall 21.07.2009 13:28

Цитата:

Сообщение от Alex Lexcuk (Сообщение 836996)
На частоту монитора флешу пофонарю, так-же как и монитору на флеш плеер.

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

Цитата:

Сообщение от Герыч (Сообщение 836999)
то есть я сделал правильно поместив просчёт физики и прорисовку в одном месте??

Нет.


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

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