Здравствуйте, Кодт, Вы писали:
К>Как растут ледяные узоры на стекле? К>Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
Немного домыслено и подправлено, чтобы получилось покрасивее.
Здравствуйте, Кодт, Вы писали:
К>Как растут ледяные узоры на стекле? К>Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
С моим ником не мог не попробовать Скринсейверы не люблю потому получился exe
Не знаю насколько это на иней похоже, наверно совсем не похоже, в общем вот
P.S. писал под VC7.1 без неё может и не пойти
Здравствуйте, Кодт, Вы писали:
К>Для полного щастья: К>- когда узор дорисовывается до упора, очистить экран и начать по второму кругу
Было сделано раньше.
К>- прятать курсор
Уже сделано
К>- ловить все события от мышки и клавки
Сделано
К>- сделать чуть-чуть более контрастный фон
Шаг роста стал не 2 пикселя, а 1 — стало контрастнее.
Ещё маленько изменён алгоритм. Лучики теперь умирают от старости. Так на мой взгляд узор покрасивше получается.
К>Может, исходник кинешь? Напильником доработаем
Как растут ледяные узоры на стекле?
Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
XSH>Шаг роста стал не 2 пикселя, а 1 — стало контрастнее.
XSH>Ещё маленько изменён алгоритм. Лучики теперь умирают от старости. Так на мой взгляд узор покрасивше получается.
Однако, было бы забавным добавить немного физики. По моему разумению, кристаллы растут не только "в даль", но и "в ширь". Получаются длинные узкие треугольники, преломляющие свет. Самым примитивным способом это можно сэмулировать, если разбить треугольник на два — слева и справа от направления роста. Слева он должен бть чуть темнее, справа — чуть светлее. Но здесь все не так просто. Преломление лучей на реальном узоре заметно, если только узор достаточно старый и прошел несколько стадий замерзания/подтаивания. На "свежих" узорах кристаллы очень мелкие и в общем похожи на то, что реализовано.
Кроме того, красивые узоры получаются, когда в силу неких причин, распределение влаги на стекле существенно неравномерно. То есть, например, на бутылке водки, вынутой из морозильника узоров не получается — на ней просто равномерно конденсируется влага из воздуха и тут же замерзает. И вообще, условия возникновения узоров довольно сложны. Но главное условие на мой взгляд — влаги в воздухе должен быть абсолютный минимум, иначе стекло быстро запотевает и равномерно замерзает. Минимум влаги как раз и создает условия "неравномерности" — затравок для образования кристаллов на стекле полно, но мелкие кристаллы успевают испаряться, прежде чем "наберут силу".
Чтобы сэмулировать "неравномерности", надо экспериментировать, например, предварительно заполнить "стекло" крупным турбулентным шумом, эмулирующим "благоприятность" для роста кристаллов: http://www.w3.org/TR/SVG11/filters.html#feTurbulence
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, yeti, Вы писали:
Y>>Не знаю насколько это на иней похоже, наверно совсем не похоже, в общем вот
К>Что-то я не понял: оно загружает процессор на 95%, а картинка практически не меняется.
...а потом глядь — винт-то инеем весь покрылся, а проц — медным тазом...
Здравствуйте, Пономарёв Иван, Вы писали:
ПИ>новая версия :user:
ПИ>1. Подчищен код и убрана утечка памяти :shuffle: ПИ>2. Добавлена имитация возникновения новых центров кристаллизации ПИ>3. Длина лучиков стала поменьше (соответственно, лучиков стало больше и программа -- медленнее).
Несколько придирчевых замечаний:
1. Не обрабатываются оконные сообщения (Вставь куда-нибудь Application.ProcessMessages — и всё пройдёт)
2. Если на форму бросить TImage и рисовать на его канве, а не на канве формы, то рисунок будет сохраняться при перерисовке формы (т.е. после Alt+Tab, Alt+Tab)
3. Чего-то они отпочковываются только в одну сторону... смотрится как что-то закручивающееся :)
4. Центры кристалицайии не всегда в пределах окна.
5. Поставь Position у формы в какое-нибудь приличное значение, типа poScreenCenter, а то она появляется у меня где-то наполовину за краем экрана :)
6. Мне показалось, или лучики всё таки иногда пересекаются?
Как избавится от тормозов:
Первый вариант: можно использовать для хранения лучиков не простой список, а что-нибудь типа квадродерева. Но это муторно и лениво.
Второй вариант — как это у меня сделано: лучик каждый раз растёт на 1 пиксель и перед тем как пиксель поставить, он проверяет окрестность на свободность. Эта проверка — банальное сравнение цвета пикселя с цветом фона. Таким образом проверка "можно ли лучику вырасти" осуществляется за O(1), а не за O(n), как у тебя.
Для сравнения, квадродеревья дадут сложность что-то около O(log(n)) для этой операции.
PS. Я всё жду, когда же тут появится вариант, который:
а) имеет какое-нибудь отношениие к модели роста инея на стекле
б) будет красиво смотреться в качестве ScreenSaver-а.
Здравствуйте, Пономарёв Иван, Вы писали:
ПИ>Би-дерево -- знаю, а вот квадро... Век живи -- век учись, как говорится Попробую что-нибудь на эту тему почитать. Или может напишешь в двух словах, как это (применительно к данной задаче)?
Суть в том, чтобы весь экран разбить на несколько областей, так, чтобы лучики там примерно равномерно распределились. После этого, чтобы понять пересекается ли лучик с кем-то, достаточно проверить только лучики из той же области (ну и ещё из граничных областей, если лучик пересекает границу области). Такую структуру данных сложнее поддерживать, но она даёт выигрышь по времени.
Квадродеревья — это одна из реализаций данного подхода. Тут область бьется на две части по горизонтали и ещё на две по вертикали (т.е. в сумме на четыре). Каждый из полученных квадрантов если он содержит слишком много элементов, делится точно также. В результате, получим дерево, в листьях которого лежат небольшие массивы лучиков (небольшие означает количество эл-ов меньше заданной константы K). Высота дерева порядка log(n). То есть поиск нужного листа займет O(log(n)). Можно подбирать константу K так, чтобы вся процедура поиска пересечения была тоже O(log(n)).
Подробнее я пожалуй не смогу рассказать. Я с ними и не работал то ни разу...
Можешь спросить у hemmul, который по его словам как раз квадродеревья и использует.
PS. А зачем все эти пляски со связными списками? Чем тебе TObjectList не угодил? Он же заведомо эфективнее чистой динамики. И ходить по нему можно в любом направлении, хоть по спирали
. К>Давайте в этом попробуем кое-что другое.
Я даже боюсь представить, что мы нарисуем к 2010 году
К>Как растут ледяные узоры на стекле? К>Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
Что-то типа волнового алгоритма просится. Только двумерное пространство стекла топологически преобразуется — все точки проростания сводятся в одну (из нее начинается фронт волны). Т.е. расстояние между любыми такими точками равно нулю. А расстояние между остальными — минимуму из "прямого расстояния" и "расстояния через ближайшие точки проростания". Это как телепортеры на карте стратегии.
Конечно надо еще подумать насчет не дискретности пространства и переменной длины лучей.
. К>Давайте в этом попробуем кое-что другое.
К>Как растут ледяные узоры на стекле? К>Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
К>Вот такая тема для скринсейвера Возьмётесь?
Что-то я не то с рекурсией делаю... rundll32 зависает при переключение скринсейверов
I'm the hero I'm back
With weapons and with magic spells
Здравствуйте, Crab, Вы писали:
C>Что-то я не то с рекурсией делаю... rundll32 зависает при переключение скринсейверов
Ну если ты всё рисуешь в одном глубоком погружении, то конечно. А кто будет оконные события обрабатывать?
Тут нужно или делать машину состояний, или многопоточное (многофиберное?) приложение.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Crab, Вы писали:
C>>Что-то я не то с рекурсией делаю... rundll32 зависает при переключение скринсейверов
К>Ну если ты всё рисуешь в одном глубоком погружении, то конечно. А кто будет оконные события обрабатывать? К>Тут нужно или делать машину состояний, или многопоточное (многофиберное?) приложение.
. К>Давайте в этом попробуем кое-что другое.
К>Как растут ледяные узоры на стекле? К>Всё начинается с нескольких точек кристаллизации, из которых прорастают ледяные лучики. Затем от каждого лучика появляются ветки — прямо и ±60°. Когда ветка упирается в уже имеющийся ледяной узор, её рост прекращается.
К>Вот такая тема для скринсейвера Возьмётесь?
вот :shuffle:
никак не прочитал у NeHe туториал о том, как скринсейверы делать... так-что уж exe-шником если позолите
P.S. интересно а как сделать эффект запотевшего стекла...
Здравствуйте, hemmul, Вы писали:
H>никак не прочитал у NeHe туториал о том, как скринсейверы делать...
Ищем в MSDN по строкам scrnsave.lib/scrnsave.h Надо написать 3 callback функции из которых одна это простая оконная процедура, а две другие могут быть пустыми.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, hemmul, Вы писали:
H>>вот :shuffle:
A>У меня всё размазалось и проц на 100% загрузился. Ограничений по разрешению нет? У меня рабочее 1600х1200 — не много?
У меня всё нормально запустилось. Только ме-е-едленно. И лучики почти всегда друг-друга "пробивают" насквозь, вместо того, чтобы останавливаться.
А вообще, понятно, что идея в том голом виде, в котором она была предложена, не даёт красивой картинки... Надо её как-то развивать и домысливать. Например, случайности добавить.
Здравствуйте, XopoSHiy, Вы писали:
XSH>Здравствуйте, adontz, Вы писали:
A>>У меня всё размазалось и проц на 100% загрузился. Ограничений по разрешению нет? У меня рабочее 1600х1200 — не много?
многовато будет
XSH>У меня всё нормально запустилось. Только ме-е-едленно. И лучики почти всегда друг-друга "пробивают" насквозь, вместо того, чтобы останавливаться.
да, это точно — медленно потому что я пересечения каждого лучика со всеми отсальными по дереву проверяю (кроме его родителей и детей, но всё равно ясно что долго очень). а вот пробивают они друг друга насквозь не всегда: я сделал так, что если точка пересечения отстоит от конца луча менее чем на N поцентов — луч останавливается... если нет — продолжает ползти (т.е. это зачит, что если луч А въехал в бок лучу Б, то луч А остоновится, а Б продолжит ползти...)
XSH>А вообще, понятно, что идея в том голом виде, в котором она была предложена, не даёт красивой картинки... Надо её как-то развивать и домысливать. Например, случайности добавить.
пока -- только для единственного центра кристаллизации.
Идея такова: имеется очередь "лучиков" на связном списке. Проходимся по списку, для каждого "лучика" проверяем, не пересекся ли он с другими. Если пересекся, то корректируем его длину и отрисовываем. Если не пересекся -- то отрисовываем, а также добавляем 2 лучика (его продолжение и отпочковавшийся) в конец очереди.
Думаю, надо 1. доработать модель, выдающую случайные длины "прямого" и "отпочкованного" лучиков. 2. Сделать для нескольких центров кристаллизации 3. Что-то придумать, чтобы не тестировать текущий лучик на пересечение со всем списком, а только с той частью, где пересечение наиболее вероятно
Здравствуйте, XopoSHiy, Вы писали:
XSH>Как избавится от тормозов: XSH>Первый вариант: можно использовать для хранения лучиков не простой список, а что-нибудь типа квадродерева. Но это муторно и лениво.
так и делаем-с...
XSH>Второй вариант — как это у меня сделано: лучик каждый раз растёт на 1 пиксель и перед тем как пиксель поставить, он проверяет окрестность на свободность. Эта проверка — банальное сравнение цвета пикселя с цветом фона. Таким образом проверка "можно ли лучику вырасти" осуществляется за O(1), а не за O(n), как у тебя.
класс! где Вы раньше были?
XSH>1. Не обрабатываются оконные сообщения (Вставь куда-нибудь Application.ProcessMessages — и всё пройдёт)
Да вставлено, вставлено всё равно он ждет, когда метод отрисовки закончится. Я думаю, что в следующей версии надо выносить отрисовку в отдельную нить. Так, чтобы можно было выбрать "STOP" и "PAUSE"
XSH>2. Если на форму бросить TImage и рисовать на его канве, а не на канве формы, то рисунок будет сохраняться при перерисовке формы (т.е. после Alt+Tab, Alt+Tab)
Можно, я знаю. Но TImage -- он хранит свой битмап в памяти. Я из соображений минимизации ресурсов сделал отрисовку на форме. Ведь, если это будет скринсейвер -- то не всё ли равно?
XSH>3. Чего-то они отпочковываются только в одну сторону... смотрится как что-то закручивающееся
Да. Пока только в одну сторону. Я уже думал о том, что надо бы в обе стороны, причем сделать, как у тебя -- лучик "хранит" информацию о том, куда он почкуется, и переход на другую сторону осуществляется с малой вероятностью. Я, наверное, так сделаю в следующей версии (наряду с пунктом 1)
XSH>4. Центры кристалицайии не всегда в пределах окна.
У меня немного некорректно там передается информация о размерах окна, это я подправлю.
XSH>5. Поставь Position у формы в какое-нибудь приличное значение, типа poScreenCenter, а то она появляется у меня где-то наполовину за краем экрана
Справедливое замечание. Но делалось-то всё как? На самую что ни на есть скорую руку, лишь бы работало
XSH>6. Мне показалось, или лучики всё таки иногда пересекаются?
Нет, не показалось. Объясняю, почему. У меня программа ищет (аналитически!) для каждого лучика тот лучик, который с ним пересекается. Когда находится первый, поиск прекращается. При этом, могут существовать лучики, с которыми текущий пересекается раньше. Чтобы этого избежать, я не должен прекращать поиск на первом попавшемся лучике, а проработать всю очередь до конца. Если б то была серьёзная программа для научных исследований, я б так и сделал... А пока... пока моя прога не работает достаточно быстро, я решил забить на этот эффект.
XSH>Как избавится от тормозов: XSH>Первый вариант: можно использовать для хранения лучиков не простой список, а что-нибудь типа квадродерева. Но это муторно и лениво.
Би-дерево -- знаю, а вот квадро... Век живи -- век учись, как говорится Попробую что-нибудь на эту тему почитать. Или может напишешь в двух словах, как это (применительно к данной задаче)? На самом деле, первое, что я хочу попробовать -- это сделать список двусвязным и проходить его при поиске не с начала, а с конца. Ведь наиболее вероятно, что лучик пересекается с тем, который недавно был отрисован и находится рядом в очереди. Возможно, это так -- надо эксериментировать.
XSH>Второй вариант — как это у меня сделано: лучик каждый раз растёт на 1 пиксель и перед тем как пиксель поставить, он проверяет окрестность на свободность. Эта проверка — банальное сравнение цвета пикселя с цветом фона. Таким образом проверка "можно ли лучику вырасти" осуществляется за O(1), а не за O(n), как у тебя.
Я заметил, как у тебя сделано. Но так я делать не хочу Я хочу получить именно структуру в памяти, по которой всегда можно отрисовать узор, увеличить его до нужного масштаба...
XSH>Для сравнения, квадродеревья дадут сложность что-то около O(log(n)) для этой операции.
Можешь написать в двух словах идею?
XSH>PS. Я всё жду, когда же тут появится вариант, который: XSH>а) имеет какое-нибудь отношениие к модели роста инея на стекле XSH>б) будет красиво смотреться в качестве ScreenSaver-а.
Здравствуйте, XopoSHiy, Вы писали:
XSH>Здравствуйте, Пономарёв Иван, Вы писали:
ПИ>>Би-дерево -- знаю, а вот квадро... Век живи -- век учись, как говорится Попробую что-нибудь на эту тему почитать. Или может напишешь в двух словах, как это (применительно к данной задаче)?
XSH>Суть в том, чтобы весь экран разбить на несколько областей, так, чтобы лучики там примерно равномерно распределились. После этого, чтобы понять пересекается ли лучик с кем-то, достаточно проверить только лучики из той же области (ну и ещё из граничных областей, если лучик пересекает границу области). Такую структуру данных сложнее поддерживать, но она даёт выигрышь по времени.
XSH>Квадродеревья — это одна из реализаций данного подхода. Тут область бьется на две части по горизонтали и ещё на две по вертикали (т.е. в сумме на четыре). Каждый из полученных квадрантов если он содержит слишком много элементов, делится точно также. В результате, получим дерево, в листьях которого лежат небольшие массивы лучиков (небольшие означает количество эл-ов меньше заданной константы K). Высота дерева порядка log(n). То есть поиск нужного листа займет O(log(n)). Можно подбирать константу K так, чтобы вся процедура поиска пересечения была тоже O(log(n)).
XSH>Подробнее я пожалуй не смогу рассказать. Я с ними и не работал то ни разу... XSH>Можешь спросить у hemmul, который по его словам как раз квадродеревья и использует.
я немного не это имел ввиду под своими квадродеревьями — дело в том, что у меня сама _снежинка_ предсавляет собой дерево (для каждого элемента от 0 до 3 сыновей).
а насчёт деления области тут надо хорошо подумать: в статическом случае, безусловно, (би-)(квадро-)(окто-)(...-)деревья дают сушественный выигрыш во времени. но в нашем случае размер некоторых отрезков постоянно увеличивается — поэтому каждый раз приходится проверять: "а не пришло ли время переместить этот отрезок из текушего элемента квадродерева в родительский?". в лучшем случае это приведёт к созданию/удалению в соответствуюших элементах одного указателя (на отрезок). кроме этого, если пересечений будет наблюдатся мало — то снежинка будет разрастаться и вскоре большинство отрезков будет уже не в листьях дерева а где-то в его середине тогда вся оптимизация коту под хвост! ну а если плотность снежинок очень велика, они часто делятся и.т.д. то без квадродеревьев никуда! так как последнее намного красивее, и, наверное и требуется в задаче, то скорее всего действительно стоит заюзать этот самый space-partitioning...
на самом деле там сложного ничего нет (или я когда-то что-то не понял! но почему-то до сих пор работает ):
в основном тоже самое что говорил XopoSHiy:
в случае _равномерного_ квадродерева, которое тут имхо сойдёт, достаточно создать дерево, каждый элемент которого содержит:
* информацию о своём bounding-boxе (в нашем 2Д случае — мин и макс значения х и у) (bounding boxы детей получаются делением родительского на 4 равные части)
* указатели на 4 дочерних элемента (если они есть)
* список отрезков снежинки которые содержатся в этом и только в этом элементе (т.е. помешаются в него самого и не помешяются ни в одного из его детей)
+ как говорилось выше указатель на родительский элемент (из-за того что узоры у нас растуть...)
а теперь при проверках на пересечения начинается самое интересное: для отрезка А мы по идее должны проверять его перечесения только с теми отрезками, которые содержатся в элементах дерева которые пересекает А, начиная с базового. Ясно, что в худшем случае таких элементов будет — текуший и все 4 его дочерние. в лучшем — лишь 1 дочерний... лучший случай, опять таки, наблюдается тогда, когда отрезков много и все они маленькие (e.i. расположены ближе к листьям дерева).
но, как ранее верно заметил XopoSHiy:
лучик каждый раз растёт на 1 пиксель и перед тем как пиксель поставить, он проверяет окрестность на свободность. Эта проверка — банальное сравнение цвета пикселя с цветом фона.
— безусловно намного проше и быстрее вяких там деревьев (даже если отрезок растёт больше чем на 1 пиксель)
но, если на следуюший год будет предложена задача замоделировать трёхмерное залединение стекла — придётся юзать октодеревья...
P.S. вместо "снежинка" — читать "ледяной узор"
P.S. насчёт квадродеревьев была отличная статья на gamedev.ru, 100% будет и на gamedev.net и gamasutra.com! искать в сторону space partitioning, quadtree...
удачи!
Здравствуйте, XopoSHiy, Вы писали:
XSH>Только посколько ScreenSaver-ы писать не умею (и учиться не хочу , то это просто exe-шник похожий на scr. XSH>http://www.rsdn.ru/File/19050/xMasFrost.rar (160 KB)
В принципе, уже хорошо. Осталось только переименовать в .scr — и скринсейвер готов
Для полного щастья:
— когда узор дорисовывается до упора, очистить экран и начать по второму кругу
— прятать курсор
— ловить все события от мышки и клавки
— сделать чуть-чуть более контрастный фон
Здравствуйте, yeti, Вы писали:
Y>Не знаю насколько это на иней похоже, наверно совсем не похоже
Ну если картинка на зимнюю тему, то может и похоже, а вот если взять знойную девушку, то как бы и не совсем.
Глючки: у меня картинка вся не влезла — обрезалось. Черный фон на картинке — не очистился.