Конференция "Игры" » OpenGl Water Effect On Bitmap
 
  • Wladimir1987 © (11.04.13 16:19) [0]
    Уважаемые участники форума!
    Просьба знающих  OpenGL API помочь|подсказать как переделать найденный мной на форуме vingrad пример симуляции воды на битмапе, при движении курсора мыши в пределах его TRect-а. Сложность заключается в том, что алгоритм данного примера хоть и очень красиво и быстро благодаря OpenGL-у рисует воду, мне несовсем подходит ввиду реализации самого примера, а именно:
    1. Картинка загружается процедурой
    procedure LoadBitmap(Filename: String; out Width, Height: Cardinal; out pData: Pointer);
    взятой из GlScene правильно (судя по выходящих ширине и высоте), но в итоге отображается только часть картинки, при этом сильно увеличенная
    2. В пределах формы имеется чёрный фон
    Изображение: http://imageshack.us/photo/my-images/541/87793500.png/

    В общем хотелось бы что-то вроде http://imageshack.us/photo/my-images/32/17306035.png/
    Данный пример взят с http://www.delphisources.ru/pages/sources/graph/2006_year/water_effect.html
    Он не менее хорош, но очень сильно нагружает ЦПУ. Я убрал обаработку алгоритма воды в поток с низким приоритетом синхронизацией, чтоб не вешать приложение, но нагрузка на процессор никуда не делась и оставить её, я не могу тк считаю дурным тоном нагружать процессор будущего пользователя, зная что с использованием OpenGL можно возложить задачу на ГПУ.
    У меня к вам 2 просьбы. Либо помочь доработать пример с OpenGL (мне он больше нравится :) ) либо указать мне на возможности оптимизации второго примера, не в ущерб качеству симулируемой воды
    к сожалению чтение MSDN для понимания OpenGL процедур используемых в 1-м примере и изучение GlScene мне не помогло продвинуться дальше :(
    вот исходники 1-го и 2-го примера в одном архиве.7z: http://sendfile.su/793038

    Буду очень признателен за вашу помощь и наставления! :)

    Прошу прощения у администрации, если открыл данную тему не в том разделе.
  • Rouse_ © (11.04.13 18:08) [1]
    Может это подойдет: http://rouse.drkb.ru/tmp/wave.zip
    Это небольшая переделка одного из примеров небезызвестного Яна Хорна.
    Загрузка процессора в районе 2-3 процентов.
  • Rouse_ © (11.04.13 18:12) [2]
    хм, пардон, судя по первой картинке это мой пример и есть :)
  • Wladimir1987 © (11.04.13 18:30) [3]
    Rouse_
    спасибо, у меня в архиве выше тот же самый который я взял из Вашего сообщения на форуме http://forum.vingrad.ru/forum/topic-95403.html
    Кстати, там же я спрашивал о том же. Пример очень красивый, но мне не хватает знаний довести его до вида примера номер 2 :(
  • Rouse_ © (11.04.13 18:46) [4]
    К сожалению доработать не смогу, уж очень давно не работал в данном направлении, но у нас на форуме есть несколько спецов, к примеру "antonn" которым это сделать, что раз плюнуть :)
    Так что кастуй его в ветку :)
  • Wladimir1987 © (11.04.13 19:52) [5]
    Rouse_
    Ок, спасибо :)

    =========================================

    Уважаемая Администрация. Просьба перенести данную тему в раздел пользователя "antonn", в раздел "Игры", если я не ошибаюсь!
  • antonn © (11.04.13 21:47) [6]
    Да-да, перенесите в мой раздел! =)
    Я только с GDI имел дело, и когда пытался сделать себе "эффект падающей капли" то мучал как раз пример water_effect.zip из ссылок выше. По части производительности ничего особо не изменилось, и не смог победить "отражение от стенок", из-за чего забросил свое желание.
    Съедает в примере он одно ядро из-за того что расчет и прорисовка находятся в TMainForm.idle(). Можно использовать таймер для ограничения fps (поставить ему интервал 33, например), загружать процессор будет меньше, но и плавность анимации может потеряться. Для пущей оптимизации можно останавливать перерисовку если все волны "улеглись", и запускать ее когда запускается новая волна.
  • Rouse_ © (11.04.13 21:51) [7]

    > antonn ©   (11.04.13 21:47) [6]

    Хм, я что думал что ты как раз с OpenGL работаешь, значит запамятовал.
    Eraser, что-ли? :)
    Короче не помню - кто-то точно был, кто хорошо в теме :)
  • antonn © (11.04.13 22:07) [8]
    Sapersky может :)

    С таймером можно примерно так: http://antonn.com/fh/store/8vfclaqd.zip
  • Sapersky (12.04.13 01:42) [9]
    Как раз в OGL я довольно плохо разбираюсь... но раз уж сказали "может":
    Приблизить - уменьшить первое число в gluPerspective (угол камеры)
    Масштаб текстуры (после LoadTexture):
     glMatrixMode(GL_TEXTURE);
     glScalef(4,4,1); // подобрать первые два числа
     glMatrixMode(GL_MODELVIEW);

    Сотфвер можно ещё прилично разогнать, многопоточность хорошо помогает:
    https://docs.google.com/file/d/0B_vHqwd58bsUX1RJcUQ1ejRiNnc/edit?usp=sharing
    но всё равно, чтобы более-менее шевелилось в 1920*1080 - нужен наверное i5-i7 с полной загрузкой.
    (кстати, кто-нибудь знает, как в гугл-диске дать просто ссылку на скачивание файла, без просмотра содержимого архива?)
  • MBo © (12.04.13 06:05) [10]
    На fps WaterEffect наибольшее влияние оказывает процедура render - если ее содержимое закомментировать, у меня fps растёт от 35 до 113, однако процессор загружен полностью - для его разгрузки надо пересматривать организацию программы.
    Не исключено, что render можно оптимизировать, ускорив в 2-4 раза
  • antonn © (12.04.13 07:58) [11]
    тогда может кто подскажет как загасить "отражение от стенок" в софтварном варианте? :)
  • Павиа (12.04.13 08:45) [12]
    А вот эту статью о воде видели?
    http://www.uraldev.ru/articles/35/page/4
    Если не ошибаюсь, то автор
    http://forum.sources.ru/index.php?showuser=110064
  • Wladimir1987 © (12.04.13 09:58) [13]
    Sapersky
    с такой связкой удалось в какой-то мере избавиться от сильного увеличения, но изображений теперь 2 :)
       glEnable(GL_TEXTURE_2D);
       LoadTexture('picture.bmp', WaterTexture);
       glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
       glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
       glMatrixMode(GL_TEXTURE);
       glScalef(10,5,1); // подобрать первые два числа
       glMatrixMode(GL_MODELVIEW);
       Viscosity := 0.96;
    и настроил немного gluPerspective(40.0, Width/Height, 1.0, 100.0); (с 45.0 на 40.0) в процедуре. В итоге получилось: http://imageshack.us/photo/my-images/213/29667086.png/
    но уже лучше, спасибо

    antonn, MBo
    похоже на скорость 2 примера, а точнее на ресурсоёмкость влияет метод image.Picture.Bitmap.ScanLine в строке 332 согласно второму ответу на
    http://stackoverflow.com/questions/13583451/how-to-use-scanline-property-for-24-bit-bitmaps
  • Павиа (12.04.13 10:25) [14]

    > похоже на скорость 2 примера, а точнее на ресурсоёмкость
    > влияет метод image.Picture.Bitmap.ScanLine в строке 332
    > согласно второму ответу наhttp://stackoverflow.com/questions/13583451/how-
    > to-use-scanline-property-for-24-bit-bitmaps

    Не надо гадать на кофейной гуще из соседнего отдела.
    Берём профаллер и смотрим что тормазит. Видим что тормозит render причем равномерно на строчках с 515 по 546. более всего тормозит 516 строчка 17% остальные примерно по ~6%.
  • Павиа (12.04.13 10:29) [15]
    но всё равно, чтобы более-менее шевелилось в 1920*1080 - нужен наверное i5-i7 с полной загрузкой.
    Указателе плюс убирание медленных операций даст выигрыш в 10 раз. И параллельность а именно: потоковая(ядра) и SIMD (SSE)  даст прирост ещё 8 раз.
    У меня проц G620  выдаёт 150 fps на  323х323(по умолчанию) пикселей (500 fps без render).
  • antonn © (12.04.13 11:37) [16]
    в таких разрешениях софтварно и вывод битмапа на экран без тормозов уже не получится сделать
  • MBo © (12.04.13 14:26) [17]
    Небольшая модификация render (битмапы сделаны 32-битными!) у меня поднимает fps с 33 до 53

     procedure AddLight(Src, Dst: Pointer; light: Integer);
     asm
      movd xmm0, [Src]
      pxor xmm6, xmm6
      movd xmm1, light
      pshufd xmm1, xmm1, 0
      punpcklbw xmm0, xmm6
      punpcklwd xmm0, xmm6
      paddd xmm0, xmm1
      packssdw xmm0, xmm0
      packuswb xmm0, xmm0
      movd [Dst], xmm0
     end;

    begin
     bgbw := backgroundBitmap.width;
     bgbh := backgroundBitmap.Height;

     // Pour chaque colone
     for Y := 0 to bitmapHeight - 1 do begin

       for X := 0 to bitmapWidth - 1 do begin
         dx := waves[X + 1, Y].Height - waves[X, Y].Height;
         dy := waves[X, Y + 1].Height - waves[X, Y].Height;

         // Calcul dйformation
         r := waves[X, Y].Height + depth;
         xMap := X + round(dx * r);
         yMap := Y + round(dy * r);

         // Calcul lumiиre
         light := round((dx + dy) * lightIntensity);

         if xMap < 0 then
           xMap := - xMap;
         if xMap >= bgbw then
           xMap := xMap mod bgbw;

         if yMap < 0 then
           yMap := - yMap;
         if yMap >= bgbh then
           yMap := yMap mod bgbh;

         AddLight(@backgroundLines[yMap][xMap * 4], @bitmapLines[Y][X * 4], light);

        end;

  • Sapersky (12.04.13 14:45) [18]
    Ну да, у меня тоже наложение освещения (только 8->32) сделано через MMX. Потом выложу исходники, когда более-менее причешу.
    Хотя это не самое узкое место, просто в оригинале сделано криво - 6 вызовов функции на пиксель.

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

    тогда может кто подскажет как загасить "отражение от стенок" в софтварном варианте? :)

    Может, после каждой итерации присваивать крайним пикселям значения [крайних-1]?
    Отражение, как я понимаю, получается из-за того, что с краю всегда 0.
  • Sapersky (12.04.13 14:57) [19]
    с такой связкой удалось в какой-то мере избавиться от сильного увеличения, но изображений теперь 2 :)

    glTranslatef(0.5,0.5,0) к текстурной трансформации, или 0.5,0,0
  • antonn © (12.04.13 15:31) [20]
    да, кстати...

    > но нагрузка на процессор никуда не делась и оставить её,
    >  я не могу тк считаю дурным тоном нагружать процессор будущего
    > пользователя, зная что с использованием OpenGL можно возложить
    > задачу на ГПУ.

    имхо реализация на CPU и небольшая (ну или большая, как получится) загрузка его с лихвой перекроют собственные мучения с рендером и его вкрячиванием в программу, и возможными проблемами у пользователя потом (драйвера, другой мешающийся софт, железо (например на ноуте включение дискретной видеокарты может быть нежелательным для юзера))
  • Wladimir1987 © (13.04.13 11:35) [21]
    Sapersky

    > glTranslatef(0.5,0.5,0) к текстурной трансформации, или
    > 0.5,0,0

    с (0.5,0.5,0) очень сильное увеличение, а с (0.5,0,0) картинка получается однотонно серой :)

    antonn

    > имхо реализация на CPU и небольшая (ну или большая, как
    > получится) загрузка его с лихвой перекроют собственные мучения
    > с рендером и его вкрячиванием в программу, и возможными
    > проблемами у пользователя потом (драйвера, другой мешающийся
    > софт, железо (например на ноуте включение дискретной видеокарты
    > может быть нежелательным для юзера))

    исходил из того что OpenGL по умолчанию вместе с виндой идёт и процессор не грузит почти и видеокарту, ну или грузит последнюю, но несильно. Ну и он всё ж немного красивее
    Но в целом согласен и с радостью использую ЦПУ-шную реализацию! :) Надеюсь у Sapersky получится оптимизировать второй пример, а потом можно как Вы предложили фиксировать fps таймером скажем на 90, чтоб и загрузки процессора практически не было и анимация быстрая :
  • О-Сознание (13.04.13 15:02) [22]

    > Wladimir1987 ©   (11.04.13 16:19)  


    См. примеры шейдеров.
  • Sapersky (13.04.13 17:37) [23]
    Может, после каждой итерации присваивать крайним пикселям значения [крайних-1]?

    Хотя нет, в TMainForm.simulEdges() это и делается - но на отражения никак не влияет.

    с (0.5,0.5,0) очень сильное увеличение, а с (0.5,0,0) картинка получается однотонно серой :)

    Точно к текстурной трансформации добавляешь? Т.е. между
    glMatrixMode(GL_TEXTURE);
    и
    glMatrixMode(GL_MODELVIEW);
    если да - выложи свою текстуру.

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

    Совсем без нагрузки не получится, разве что в маленьком окне.
    Проверил ради интереса пример из [9] на 1920*1080 - как раз 90 FPS с полной загрузкой i5. Но не ко всякому 1920*1080 прилагается i5.
  • Wladimir1987 © (13.04.13 21:08) [24]

    > Точно к текстурной трансформации добавляешь? Т.е. между

    да, между, те код как и на пред. странице в сообщении нр. 13, только цифры менял. Текстура 256x256. Кстати, а можно сделать текстуру больше размером. Оригинальная картинка размером 337 на 590, но когда я загружаю её, то она тераяет цвета, а та что 256x256 растягивается и получается нечёткой
    вот текстура + оригинал http://sendfile.su/uploaded.php?ok=794400&err=0

    > Совсем без нагрузки не получится, разве что в маленьком
    > окне.
    > Проверил ради интереса пример из [9] на 1920*1080 - как
    > раз 90 FPS с полной загрузкой i5. Но не ко всякому 1920*1080
    > прилагается i5.

    Ну нагрузка будет это ни страшно, но скорость в 90 FPS при разрешении (внимание!) 1920*1080 и думаю это очень быстро! :)
    У меня i7 в ноуте и скорость при картинке 337 на 590 максимум 120+-10 fps
  • Sapersky (13.04.13 22:55) [25]
    "Выцветание" - это глюк загрузки картинки "некруглой" ширины. Если обрезать до 332, скажем - нормально загружается. Можно поправить функцию загрузки, но проще наверное найти нормальную загрузку OGL-текстуры в сети.
    За исключением этого размеры в принципе любые.

    Как бороться с раздвоенностью картинки при выводе в пропорциональном масштабе я не знаю. Теоретически должно помогать такое:
     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);  // или GL_CLAMP_TO_EDGE
     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
    но не помогает.
  • Wladimir1987 © (13.04.13 23:34) [26]
    Sapersky
    Ничего страшного, если пример с OGL трудно "оседлать" ;) то ну его!
    Можно узнать насчёт реализации на ЦПУ? На ЦПУ тоже очень классный пример!
    на прошлой странице Вы писали о

    > Хотя это не самое узкое место, просто в оригинале сделано
    > криво - 6 вызовов функции на пиксель.

    апдейт MBo пробовал, скорость обработки действительно возросла и хотел бы узнать насчет вашей оптимизации. Я был бы рад снижению нагрузки на цпу не в ущерб качеству, но в педелах разумного, те оптимизации алгоритма, настолько, насколько возможно!
  • Sapersky (16.04.13 12:34) [27]
    Выложил свой софтверный пример:
    http://pda.delphimaster.net/?id=1366101219&n=7
 
Конференция "Игры" » OpenGl Water Effect On Bitmap
Есть новые Нет новых   [134427   +38][b:0][p:0.002]