![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Анимация [D6, WinXP]
Аним © (2004-07-27 19:09:00)Вопрос общего плана:
Как можно сделать анимацию наиболее плавно?
Чтоб при передвижении объекта не было мельканий (при стирании и рисовки заново)?
Но с учетом того, что задний фон динамически меняется..
нужно любое:
алгоритм на словах.. основные функции.. в общем, любые мысли..
кто то ведь с этим уже сталкивался..
спасибо.
parovoZZ (2004-07-29 11:32:00) [21]На этом сайте лежит скринмэйт Joffa, там картинка рисуется на Image-е, при этом заметны мерцания, я же делаю всё с помощью апей. Ничего не мерцает. В обоих случаях буфер не применяется.
Огромное Кулясищще (2004-07-28 23:43:00) [22]> Видимо VCL сам себе на уме.
Видимо без буфера VCL делает то, что ты ему задаёшь делать, а именно: нарисовать на окне, обновить окно, нарисовать на окне, обновить окно.
Огромное Кулясищще (2004-07-28 23:40:00) [23]2 Аним:
> Рисую на канве.
Использую:
Canvas.Draw
Canvas.CopyRect
вывожу при помощи ч/б маски:
cmSrcAnd + cmSrcPaint
Ты мне скажи, что ты делаешь, чтобы у тебя мерцало. Не допираю никак.
> Как и какими средствами (через что, по-простому) можно добиться плавности как на твоей png?..
Нужно применить сглаживание к пикселю (antialiase). Грубо говоря, чем больше площадь лежит на одном из четырёх занимаемых пикселей, тем непрозрачней цвет.
parovoZZ (2004-07-28 23:39:00) [24]Да, я чего ещё подумал. В моём скринмэйте нет буферизации, но он всё равно не мерцает при перерисовке. Правда он написан полностью на апях. А вот попробовал убрать из вышеприведённого кода буфер, появились мерцания. Видимо VCL сам себе на уме.
А по поводу плавности: пиксель - это минимальная еденица отображения информации на мониторе. Хотим мы этого или не хотим, но перемещатся спрайт всё равно будет дискретно, но, как видно из рисунка, мы можем обмануть глаз и сделать перемещение как-бы плавным.
parovoZZ (2004-07-28 23:29:00) [25]А кто мешает перед перерисовкой формы скинуть её содержимое в какой-нибудь буфер?
А скринмэйт (экранный помошник) это всего-лишь окно, которое движется по экрану, а перерисовка окон, находящегося под ним, это забота вынды. По крайней мере, я ей так приказал делать.
Аним (2004-07-28 23:14:00) [26]Да, класс..
Нет, сложным вовсе не показалось.. )) просто с этим столкнуся впервые.. и литры нет..
а тут.. отличный пример! (еще и напрямую, через дискрипторы)
бошое спасибо.
я достиг такого же эффекта (не мерцания), но не напрямую (на канве рисовал).
Единственное:
В твоем примере все рисуется в буфере и выводится потом через дискриптор формы на нее же..
Т.е. инфа, кот. ранее была на форме, после вывода твоей графики, потеряна.
Я же говоря о динамическом фоне, я имел ввиду то, что до этого (вывода твоего спрайта) на форме кто-то мог что-то выводить сам.. да хоть кружок..
а твое все его затрет.
говоря о динамическом фоне, я имел ввиду то, что фон - не картинка, а чужой дескриптор, кот. я не контролирую.... он чужой.
он меняется и статически висеть в буфере у меня не может...
т.е. я полюбэ болжен восстанавливать его "чистоту" и вновь запоминать перед последующей прорисовкой.... я же не могу заляпать его своим спрайтом... )
поэтому и заинтересовал твой screenmate.. ведь он обязан не затирать "чужое".
Как это у тебя делается?!
или ты что-то иное под screenmate имеешь ввиду, не передвигающийся спрайт на экране (чужом дискрипроре)?!
2 Огромное Кулясищще © (28.07.04 22:58) [15]
Никто и не путал мерцание с плавностью передвижения..
Вопрос звучал
> Чтоб при передвижении объекта не было мельканий (при стирании
> и рисовки заново)?
> Но с учетом того, что задний фон динамически меняется..
и о том и о другом, как выяснилось.. :).
Но на тот момент я думал именно о мерцании..
Плавность также оч. важный момент.
У тебя есть мысли, - выскажи.. что за споры.. )
> объект движется рыками
Как и какими средствами (через что, по-простому) можно добиться плавности как на твоей png?..
На счет этого все понятно:
> меняется загрузка процессора, то анимация ускоряется или
> замедляется
> можно использовать OnIdle, мультимедийный таймер или потоки.
Огромное Кулясищще (2004-07-28 22:58:00) [27]> Зато речь шла о мельканиях, что одно и тоже в данном контексте.
Мелькание и плавность ну явно разные понятия. Можно на тех же BitBlt выводить изображение без мерцаний, но при этом не слишком быстро - и будет казаться, что объект движется рыками. Или же если во время анимации меняется загрузка процессора, то анимация ускоряется или замедляется. Этого тоже можно избежать.
> Не нравится таймер, можно использовать DirectDraw. Там всё быстро и плавно.
Если в DirectDraw использовать TTimer, то всё будет быстро, но никак не плавно. Кроме таких категоричных действий, можно использовать OnIdle, мультимедийный таймер или потоки.
> А плавность - плюс минус один пиксель, плавнее нельзя по определнию.
Увы, можно. Надеюсь, рисунок тебя убедит:
http://www.hot.ee/gelphi/pixel1.png
parovoZZ (2004-07-28 21:56:00) [28]Зато речь шла о мельканиях, что одно и тоже в данном контексте. Не нравится таймер, можно использовать DirectDraw. Там всё быстро и плавно. А плавность - плюс минус один пиксель, плавнее нельзя по определнию.
Огромное Кулясищще (2004-07-28 21:33:00) [29]2 parovoZZ:
> В примере движется фон, но поверх него выводится спрайт, который тоже движется. На моём компе с WinXP мерцаний замечено не было совсем. В принципе по началу может показаться всё сложным, но после некоторой практики всё станет понятным.
А по-моему о мерцаниях речь не шла. BitBlt что с канвой, что без канвы - практически одно и то же. А вот когда вывод подвешен на таймер - о плавности говорить не приходится.
parovoZZ (2004-07-28 21:08:00) [30]А по-моему для таких целей не следует использовать канвас, а обращаться напрямую через дескриптор компонента. Например, для формы:
var
DC : HDC;
begin
DC := GetDC (Form1.Handle);
end;
После чего можно непосредственно рисовать на форме, но все перерисовки должна брать на себя программа. Геморно, но цена: отсутствие мерцаний.
Создай пустую форму, на неё кинь таймер, интервал в принципе не критичен, можешь поставить 10-ку. Скопируй вот этот код (на скорую руку, поэтому замечания от мастеров только по делу):
unit Unit1;
interface
uses
Windows, Messages, Forms, Classes, ExtCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
k : integer;
Picture1, Picture2 : cardinal;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender: TObject);
var
DCBuffer : HDC;
DCForm : HDC;
DCImage : HDC;
BufferBitmap : HBitmap;
begin
if k > 500 then k := 1 else inc (k);//Для анимации
DCForm := GetDC (Form1.Handle);//Берём дескриптор формы
BufferBitmap := CreateCompatibleBitmap (DCForm, 500, 130);//Создаём совместимую с контекстом формы картинку в памяти (наш буфер)
DCImage := CreateCompatibleDC (DCForm);//создаём дополнительные дескрипторы
DCBuffer := CreateCompatibleDC (DCForm);
SelectObject (DCBuffer, BufferBitmap);//Выбираем в созданные
SelectObject (DCImage, Picture1);//дескрипторы картинки
BitBlt (DCBuffer, 5, 0, 500, 130, DCImage, 0, 0, SrcCopy);//В памяти сперва рисуем фон
SelectObject (DCImage, Picture2);
BitBlt (DCBuffer, k + 5, 0, 500, 130, DCImage, 0, 0, SrcCopy);//затем также в памяти рисуем спрайт
BitBlt (DCForm, k + 5, 0, 500, 130, DCBuffer, 0, 0, SrcCopy);//После чего всё переносим из памяти на форму
SelectObject (DCBuffer, BufferBitmap);
DeleteObject (BufferBitmap);
DeleteDC (DCBuffer);
DeleteDC (DCImage);
ReleaseDC (Form1.Handle, DCForm);//Ну и удаляем всё к чёрту
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Picture1 := LoadImage (0, 'fon.bmp', Image_Bitmap, 0, 0, LR_LOADFROMFILE or LR_CREATEDIBSECTION);//загружаем фон (размер не очень важен; у меня 640*480)
Picture2 := LoadImage (0, 'Sprite.bmp', Image_Bitmap, 0, 0, LR_LOADFROMFILE or LR_CREATEDIBSECTION);//загружаем спрайт (у меня 96*96)
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteObject (Picture1);
DeleteObject (Picture2);
end;
end.
Картинки должны лежать в той же папке, что и EXE, названия файлов должны совпадать с теми, которые указаны в функции BitBlt.
В примере движется фон, но поверх него выводится спрайт, который тоже движется. На моём компе с WinXP мерцаний замечено не было совсем. В принципе по началу может показаться всё сложным, но после некоторой практики всё станет понятным.
Аним (2004-07-28 15:05:00) [31]Почитал..
Оказывается я и делал вывод с бвойной буферизацией с исп. обычной маски (не программной)...
но это всек тому как быстрее, грамотнее рисовать кадры..
а как восстанавливать фон, чтобы поставить след. кард?
каким способом?
но нельзя хранить фон в буфере, а потом дважды буферизировать и поверх всего опять ставить (не восстанавливая того, куда нарисовали), поскольку фон за это время мог уже измениться (по сравнению с тем, что в буфере)...
и этот буфер (с фоном) надо обновлять перед тем, как исп. двойную буферизацию для след. кадра...
вот я и писал
> с учетом того, что задний фон динамически меняется..
а?
p.s.
всвязи с этим
2 parovoZZ © (27.07.04 21:34) [4]:
может кусок сурсника по этой теме.. ?
;D
Аним (2004-07-28 13:02:00) [32]Спасибо за ссылки.. читаем..
А вот ето:
> parovoZZ © (27.07.04 21:34) [4]
> GDI: BitBlt(), StrechBlt(), TransparentBlt() ну и так далее.
> Это низкоурвневые функции WinApi для работы с графикой.
> Я так скринмэйта замутил, мерцаний - полный 0.
моно хочь exe на почту.. посмотреть хочется..
parovoZZ (2004-07-28 02:46:00) [33]Ну на самом деле всё зависит от скорости анимации. Я обходился без WM_ERASEBKGND, и всё работало без мерцаний. Просто BitBlt рисует на контексте и забыват про это до следующей перерисовки. А перерисовка просто тупо накладывается на предыдущую, вот Вам и отсутствие мерцаний.
Knight (2004-07-28 02:06:00) [34]
> 1. Обработка сообщения окна WM_ERASEBKGND:
Можно и без этого, используя разные Инвалидейты...
parovoZZ (2004-07-27 23:19:00) [35]Сейчас последует вопрос: а что такое FastLib? Отвечаю: http://delphigfx.mastak.ru/libs.htm, в самом низу страницы. А по-моему и GDI не плохо справляется.
Egloo (2004-07-27 22:16:00) [36]Кстати, а почему закрыли кладовку? :/
Egloo (2004-07-27 22:02:00) [37]Да, FastLib - отличная альтернатива работы с TBitmap...
Все же если будешь делать без FL, советую следовать следующим пунктам:
1. Обработка сообщения окна WM_ERASEBKGND: Посылается для стирания фона окна (например, при изменении его размеров). Постоянная перерисовка фона, а затем наложение на фон твоей картинки приводит к неприятному мерцанию... Дабы фон не перерисовывался необходимо в процедуре-обработчике сообщения возвратить 0.
Делается это след. образом:
- в секции private своего компонента или формы объявить процедуру-обработчик:
private
...
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
...
- в разделе реализации просто вернуть 0:
procedure TSomeForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
Message.Result := 0;
end;
Теперь уже о закраске фона мы должны позаботиться сами (см.ниже)
2. Используйте двойную буферизацию выводимой графики: Машиной на последовательное наложение на форму, например, линий или залитых областей в реальном времени тратится определенное количество ресурсов, в следствие чего, заметны последовательность и мерцание... Чтобы этого избежать, необходимо все (включая фон, т.к. мы переопределили его дефолтную закраску) рисовать на битмапе в памяти и затем уже выводить полученную картинку на экран:
procedure TSomeForm.Paint;
var
memoryBitmap: TBitmap;
begin
inherited;
memoryBitmap := TBitmap.Create; // создаем битмап в памяти
try
memoryBitmap.Height := ClientRect.Bottom;
memoryBitmap.Width := ClientRect.Right;
// Рисуем фон
memoryBitmap.Canvas.Brush.Color := Self.Color;
...
... что-то, что нам необходимо нарисовать ...
...
// Копируем memoryBitmap на экран
Canvas.CopyRect(ClientRect, memoryBitmap.Canvas, ClientRect);
finally
memoryBitmap.Free; // уничтожаем временную картинку
end;
end;
Удачи! :)
parovoZZ (2004-07-27 21:34:00) [38]GDI: BitBlt(), StrechBlt(), TransparentBlt() ну и так далее. Это низкоурвневые функции WinApi для работы с графикой. Я так скринмэйта замутил, мерцаний - полный 0. Можно ещё здесь посмотреть http://delphigfx.mastak.ru/2d/012/2d_12.htm
Knight (2004-07-27 19:50:00) [39]Посмотри FastLib... для относительно простой графики самое оно... и ещё, мелькает у тебя скорее всего перерисовывающийся backgrount... смотри пример из в Delphi там есть.
Аним (2004-07-27 19:24:00) [40]Рисую на канве.
Использую:
Canvas.Draw
Canvas.CopyRect
вывожу при помощи ч/б маски:
cmSrcAnd + cmSrcPaint
это GDI ?
я не знаком с этой терминалогией.. :((
а что еще для канвы можно?..
рисую все в памяти, потом вывожу..
но это же все не то........
ну на счет этого
> делать буферизацию
нельзя поподробней..
литры у меня нет..
может ссылку на статью.. или что-нибудь.....
а вообще, можно при помощи DirectDraw на канву?