![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вращение спрайта ... [Delphi]
Sp@wN © (2003-09-14 15:21:00)Есть ли в DirectDraw процедура для аппаратного вращения изображения на IDirectDrawSurface? А то я полазил и в самой бибилиотеке и по форумам различным, не нашёл :( Неужели все так плохо и надо софтверно это все делать?
GrayFace (2004-04-11 07:30:00) [1]Перекидывать Bitmap в Texture главное не через Canvas.Pixels.
Sapersky, кинь, пожалуйста, пример D3D в DDraw мне на мыло.
Kid (2004-02-25 08:42:00) [2]Необходим алгоритм преобразования TriangleList в TriangleStrip
Sp@wN (2003-09-27 19:59:00) [3]Всем спасибо! Со спрайтом все.
Sapersky (2003-09-27 10:45:00) [4]Стал вращать координаты экрана, а затем уже перевожу в мировые, а раньше делал все в мировых.
Ну да, я это и имел в виду. Изначально всё задавать в мировых неудобно. Строчки в TransformQuad:
pos.x:=(xv / vpHDims.x * ScaleX) - 1 + (QPos.x / vpHDims.x);
pos.y:=2 - ((yv / vpHDims.y * ScaleY) + 1 + (QPos.y / vpHDims.y));
- как раз и есть перевод в мировые координаты. Вывел экспериментально, рассчитано на матрицы D3D по умолчанию (т.е. ничего менять не надо). О значении параметров я уже писал в предыдущем посте.
DefaultCoords - это константы, задающие квадрат для triangle strip:
DefaultCoords : TTexCoordSet =
((x: 0; y: 0), (x: 0; y: 1), (x: 1; y: 0), (x: 1; y: 1));
Вычитаем 0,5 - чтобы поместить квадрат в центр координат. Ещё он используется для задания текстурных координат. Хотя в TransformQuad и передаются TCoords, но обычно они равны как раз DefaultCoords.
Как наиболее эффективно загрузить картинку из файла на текстуру. Я пока делаю это в цикле по каждому пикселю
Я уже писал ранее:
Как перекидывать - особой разницы нет, хоть по пикселям, хоть GetDC/BitBlt(D3D7), хоть функциями D3DX/D3DXSprite(DX8). Это же делается один раз, в самом начале.
Для D3D7 оба метода должны быть в graph_files (DrawFDIBtoSurf, DrawFDIBtoSurfEx). По опыту могу сказать - по пикселям надёжнее, GetDC/BitBlt иногда (редко, но всё же) не работает.
Для D3D8 - D3DXCreateTextureFromFile вроде оно называется. Если не хочется использовать D3DX - опять же по пикселям.
Sp@wN (2003-09-26 23:39:00) [5]Сделал, теперь всё ок. Стал вращать координаты экрана, а затем уже перевожу в мировые, а раньше делал все в мировых.
Еще такой вопросец. Как наиболее эффективно загрузить картинку из файла на текстуру. Я пока делаю это в цикле по каждому пикселю.
Sp@wN (2003-09-26 18:04:00) [6]NailMan ©
> А градусы в радианы конвертишь?
Да. И вершины (4 вершины квадрата) вычисляются одновременно, по одной и той же формуле, так что не должно быть в этом пролемы.
Sapersky ©
> Если сделано по такому же принципу, что и в TransformQuad ...
Формула для вычисления смещений от центра поворота та же:
NewX:=OldX*CosA - OldY*SinA + Centre.X;
NewY:=OldX*SinA + OldY*CosA + Centre.Y;
Я долго над ней тормозил (с математикой совсем не в ладах :)), но вывел, а потом у тебя посмотрел.
А в остальном можно поподробнее, что за переменные и что вычисляется?
procedure TransformQuad(QPos : TRealPoint; vpHDims : TShortPoint; Rot, ScaleX, ScaleY : Single;
color : DWord; Const TCoords : TTexCoordSet;
Var vq : TVertexQuad);
Var
n : Integer;
xv, yv : Single;
sina, cosa : Extended;
begin
SinCos(Rot,sina,cosa);
For n:=0 to 3 do With vq[n] do begin
pos.x:=DefaultCoords[n].x - 0.5;
pos.y:=DefaultCoords[n].y - 0.5;
xv:=pos.x*CosA - pos.y*SinA;
yv:=pos.x*SinA + pos.y*CosA;
pos.x:=(xv / vpHDims.x * ScaleX) - 1 + (QPos.x / vpHDims.x);
pos.y:=2 - ((yv / vpHDims.y * ScaleY) + 1 + (QPos.y / vpHDims.y));
z:=0; c:=color;
tc:=TCoords[n];
end;
Вот она процедура. Что за ДефаултКоорд (я так понимаю - это старое положение точки), и что вычисляется после xv, yv?
Sapersky ©
> Хотя судя по симптомам... если растягивается всё время и "в бесконечность" ...
Нет, в бесконечность не растягивается, он все время возвращается на исходную позицию, и круг за кругом повторяются координаты все.
Причем изначально квадрат и выглядит как квадрат (угол поворота 0 радиан, если угодно), только при повороте растягивается.
Sapersky (2003-09-26 15:43:00) [7]Если сделано по такому же принципу, что и в TransformQuad, то там vpHDims - это половинаразмера окна (экрана), Scale - размер спрайта, вроде, в пикселях; Rot - угол в радианах.
Хотя судя по симптомам... если растягивается всё время и "в бесконечность" - тут либо с количеством (порядком) вершин проблемы, либо индексы сбились (если они используются).
NailMan (2003-09-26 13:04:00) [8]А градусы в радианы конвертишь?
Sp@wN (2003-09-26 12:41:00) [9]Все таки сделал в мировых координатах. Но! Я че то не понимаю как сделать следующее: у меня спрайт квадратный, я его вращаю, при этом его жутко колбасит, то есть при повороте на 90 градусов, он жутко растягивается (вероятно потому, что 800*600 разрешение), как от этого избавится?
Sapersky (2003-09-22 09:46:00) [10]от обилия кода у меня перегрузка началась
Да, пример малость запутанный, извиняюсь :) Поэтому см. толькоSpriteBuffer - его при желании можно приспособить к своему движку, не особо вникая во всё остальное (и даже не имея FastLIB). Хотя придётся повозиться, выдирая из разных мест используемые им типы и процедуры :)
можно отрисовать текстуру в координатах экрана? ТО есть с такими флагами - D3DFVF_VERTEX = D3DFVF_XYZRHW or D3DFVF_TEX1; У меня получается квадрат Малевича, текстуры нет
Вот-вот, сам в своё время столкнулся. Поэтому и перешёл на мировые координаты (см. TransformQuad в graph_utils). Но вот недавно нашёл пример, там рассчитывается эта самая RHW (опробовать не успел ещё):
http://www.mvps.org/directx/articles/blit3d.htm
NailMan (2003-09-22 09:31:00) [11]Только так и ресуют:
tVertex = packed record
XYZ : TD3DVector;
RHW : Single;
U,V : Single;
end;
var vert:^TVertex;
Далее заполняешь нужный тебе рект
//1 triangle
vert^.X:=Left;
vert^.Y:=Bottom;
Vert^.Z:=0;
Vert^.RHW:=1;
Vert^.UV:=d3dxvector2(0.08,0.92);//01
inc(vert);
vert^.X:=Left;
vert^.Y:=Top;
Vert^.Z:=0;
Vert^.RHW:=1;
Vert^.UV:=d3dxvector2(0.08,0.08);//00
inc(vert);
vert^.X:=Right;
vert^.Y:=Bottom;
Vert^.RHW:=1;
Vert^.Z:=0;
Vert^.UV:=d3dxvector2(0.92,0.92);//11
inc(vert);
vert^.X:=Right;
vert^.Y:=Top;
Vert^.Z:=0;
Vert^.RHW:=1;
Vert^.UV:=d3dxvector2(0.92,0.08);//10
inc(vert);
И отрисовывать его надо TRIANGLESTRIP
Sp@wN (2003-09-21 10:40:00) [12]http://delphigfx.mastak.ru/samples/samp70.rar
См. TSpriteBuffer. Группировки там, правда, нет, текстура устанавливается на весь буфер одна.
Посмотрел, от обилия кода у меня перегрузка началась :-) Подумаю чтобы что то такое использовать, надо ещё будет поизучать (книжку для начала, понять что написано хотя бы :)). У меня нет к сожалению библиотеке FastDIB, не получилось посмотреть результат ТО!
Ну и вопрос такой: можно отрисовать текстуру в координатах экрана? ТО есть с такими флагами - D3DFVF_VERTEX = D3DFVF_XYZRHW or D3DFVF_TEX1; У меня получается квадрат Малевича, текстуры нет. И если да, то координаты текстуры будут все равно 0..1?
Sapersky (2003-09-18 13:16:00) [13]А теперь моё, как обычно слегка противоположное :)
Просто уже написал в offline, обидно выкидывать :)
Если в DDraw для создания анимированного спрайта я мог все фрэймы загнать на одну поверхность, а потом выбирать нужный и копировать его на первичную поверхность, то как такую фишку сделать в D3D?
Точно так же, только с учётом специфических размеров текстур - степени двойки, желательно квадратная, желательно не более 256*256, хотя если рассчитывать на GF - можно больше, но в разумных пределах (вообще макс. размер для GF 4096*4096, но большие сильно тормозят).
Выбирать нужный - заданием текстурных координат, см. книжку.
Проблема с одновременной отрисовкой этих текстур. Если есть 30 текстур (30 спрайтов тобишь) и в текущем кадре их все надо вывести, то для каждой надо установить активность(SetTexture), потом вызвать метод DrawPrimitive.
Во-первых, см. ранее (текстур будет меньше), во-вторых, да, желательно группировать по текстурам.
Т.е, даже если придумать как заполнить буфер вершин не по 4 для каждого спрайта, а последовательно, с тем чтобы затем одним вызовом DrawPrimitive (D3DPT_TRIANGELESTRIP, 0, 4*NumberOfSprite)
Не triangle strip, а indexed triangle list. К сожалению, не см. книжку - там этого нет. В DX SDK должно быть... Пример со спрайтами (DX7, разумеется :)):
http://delphigfx.mastak.ru/samples/samp70.rar
См. TSpriteBuffer. Группировки там, правда, нет, текстура устанавливается на весь буфер одна.
NailMan (2003-09-18 10:42:00) [14]1. почитай про dirtyrect или около того в интерфейсе IDirect3DTexture, да и в самом IDirect3DDevice тоже.
Вроде как можно переключить текущую рамку в текстуре, с которой будет идти ее рендер, на новые координаты.
2. Да тебе придется делать 30 вызовов draw с новой текстурой, но!
Я у себя сделал так(правда для 3Д игры, но принцип тот же):
- Все текстуры грузятся в массивarray[0..xxx] of IDirect3DTexture8, параллельно ему есть массивarray[0..xxx] of string[64]куда я при загрузке я записываю имя текстуры.
- При создании объекта(у тебя спрайта) первым делом смотрим, а загружена ли в массив такая текстура? просто перебираем массив и сравниваем имя нужной текстуры с строками в массиве имен. Если нашлась, выдаем спрайту индекс найденой текстуры, если не нашлось, то грузим ее в массив и возвращаем индекс.
- заводим переменную LastTextureIndex и при рендере спрайта смотрим, а равен ли индекс текстуры спрайта LastTextureIndex-у? если равен то просто рендерим, если не равен, то устанавливаем текстуру(элемент массива текстур по индексу, который хранится в спрайте) и если она анимированная, то и соответсвующий текущий рект. Таким образом спрайты с одинаковым индексом текстуры лишних SetTexture делать не будут.
Естественно тебе придется сделать сортировку по индексу текстуры, дабы этот метод работал эффективно.
Sp@wN (2003-09-17 22:40:00) [15]C Direct3D возникают такие проблемы ...
1. Если в DDraw для создания анимированного спрайта я мог все фрэймы загнать на одну поверхность, а потом выбирать нужный и копировать его на первичную поверхность, то как такую фишку сделать в D3D? Тут есть текстура которая может быть полностью выведена вся сразу (я только начал изучать D3D, так что может есть способы?). То есть для каждого фрэйма мне нужно создать по текстуре??
2. Проблема с одновременной отрисовкой этих текстур. Если есть 30 текстур (30 спрайтов тобишь) и в текущем кадре их все надо вывести, то для каждой надо установить активность(SetTexture), потом вызвать метод DrawPrimitive. Т.е, даже если придумать как заполнить буфер вершин не по 4 для каждого спрайта, а последовательно, с тем чтобы затем одним вызовом DrawPrimitive (D3DPT_TRIANGELESTRIP, 0, 4*NumberOfSprite)все вывести, этого сделать не удастся из-за текстур. Как это скажется на производительности? И какие есть способы исправить положение?
pasha_676 (2003-09-17 09:46:00) [16]
> Если изображение перескакивает (8 вариантов поворота), то
> это вызывает раздражение уже через 5 минут.
Тут очень трудно спорить. Т.к. зависит не только от программиста, но и от художника-дизайнера. Извини, опять ссылаюсь на Дяблу - но там 8 направлений и ощущение плавности не потеряно. Правда это опять же за слуга больше художников.
Сделано (имхо)посредством анимации. Т.е. существует 8 направлений, но повороты из одного направление в соседнии - это анимационный спрайт. Очень качественно получается.
Sapersky (2003-09-17 00:58:00) [17]У этого объекта несколько процедур: Вращение, Альфа-Блендинг ... которым в качестве параметров передаются исходная поверхность и поверхность, куда нужно поместить результат (+ куча TRect).
C D3D проще сразу выводить на экран (хотя можно и в текстуру). Вращение, блендинг и прочее не являются отдельными фичами, а делаются видеокартой при выводе (на то оно и аппаратноеускорение), если задать соответствующие исходные данные и состояния девайса. Т.е. для 3D-ускорителя вообще нет понятия "повёрнутый/не повёрнутый" - на то он и 3D. С блендингом, в общем, тоже, хотя здесь уже идёт определённая нагрузка, особенно на видеопамять, так что если много чего сблендить - можно и GeForce затормозить :)
Как перекинуть DirectDrawSurface в Texture (или это вообще одно и то же?).
В D3D7 это та же самая поверхность, только созданная со специальным флагом и имеющая размеры = степеням двойки. В D3D8 и далее - отдельный интерфейс, но по сути - опять-таки поверхность, хотя Blt с ней сделать нельзя (можно Lock - см. эту самую книжку).
Как перекидывать - особой разницы нет, хоть по пикселям, хоть GetDC/BitBlt(D3D7), хоть функциями D3DX/D3DXSprite(DX8). Это же делается один раз, в самом начале.
MeF88 (2003-09-16 14:57:00) [18]А уменя стоит 32Мб ATI Rage Fury Pro 128 XPERT 2000 + Video In/Out Theatre =) И ничего Warcraft3 прет, как миленький, тока я все равно в СтарКрафт по модему играть больше люблю.
Основной её недостаток: нет пиксельных шейдеров, из-за этого скоро пойду за Radeon 9200, а лучше 9500. (О 256Мб 9800 Pro можно тока мечатать...)
Насчет излишней плавности в играх - тоже часто достает, хотя если её правильно реализовать, то будет неплохо.
P.S. ATi рулит... ;-)
JAGO (2003-09-16 14:24:00) [19]Вобщем переписываю под Direct3D.
Sp@wN (2003-09-16 14:20:00) [20]NailMan ©
> Вобщем если уж писать что-то хорошее на 2Д, то ориентиром выбирать карты не ниже TNT-TNT2, а лучше GF2 и от этого плясать.
Полностью согласен, и даже не по причинам которые там дальше приведены, а потому что сейчас на 80% компов стоит этот GeForce2MX (да не помянуть его в суе). Вообще встретить компьютер с видеокартой более худшей, ооооооченьпроблематично.
NailMan ©
> Что касаемо совмесимости - х.з. вроде как да.
Sapersky ©
> Минимальный кусок кода для добавления поддержки D3D в DDraw - 60 строк (получается аналог D3DXSprite из DX8). Хотя для того, чтобы работало более-менее быстро, нужно написать побольше, но в целом ничего нерешаемого.
Как бы я сделал поддержку вращения спрайта из DDraw с помощью D3D. Ввел бы дополнительный класс, который бы полностью отвечал за D3D, т.е. в его Create бы создавались все объекты Device, Buffer, Texture ... У этого объекта несколько процедур: Вращение, Альфа-Блендинг ... которым в качестве параметров передаются исходная поверхность и поверхность, куда нужно поместить результат (+ куча TRect).
Вот отсюда возникают проблемы:
- Как перекинуть DirectDrawSurface в Texture (или это вообще одно и то же?). У меня есть книжка DirectX в проектах Delphi (думаю все ее знают), так вот там автор, когда загружает текстуру, сначала загружает ее из файла в BitMap, а затем в цикле по пикселямперекидывает ее в Текстуру. Если делать так же с DirectDrawSurface -> Texture, то все выгоды 3Д теряются.
- Разворот текстуры происходит разворотом координат рамки, на которую она натянута (физического разворота массива пикселей не происходит???), как быть.
- + куча технических трудностей, которые я сейчас не вижу.
> Но раз уж переписывать, то переписывать основательно и избавляться от DDraw-овских корней.
Вот исходя из моего предыдущего пункта, похоже что так :(
pasha_676 ©
> Или же в любом соответствующем граф редакторе поворачиваещь сразу и помещаещь в доступные ресурсы в игре (как угодно хоть в bmp файло). Потом их выводишь в нужном порядке. Т.к. тебе в игре врядли потребуется больше 16 вариантов поворота (а то и 8), то способ вполне имеет право на жизнь (например применяется в Диабло1 и 2).
Из просмотра чужих игр я понял, что большую роль (если не главную) играет плавность и динамика. Если изображение перескакивает (8 вариантов поворота), то это вызывает раздражение уже через 5 минут. Поэтому, будь моя воля, я бы через 1 градус поворачивал.