Форум: "Игры";
Текущий архив: 2008.01.27;
Скачать: [xml.tar.bz2];
ВнизКак рисовать 3D и 2D объекты в одной сцене? Найти похожие ветки
← →
Creative (2006-12-12 16:05) [0]Есть процедура
procedure RenderScene:
begin
A.Render; // А и В - произвольные объекты
B.render;
end;
Метод Render объектов А и В обычную процедуру рисования
glPushMatrix;
...// трансформации
....//рисование
glPopMatrix;
НО: Объект А должен находиться в двумерном пространстве и иметь фиксированный размер и координату(например это какое то системное окошко, индикатор, кнопка и так далее), а объект B - находиться в трехмерном пространстве и подвергаться различного рода трансформациям (собственно объекты, которые видит пользователь).
Как совместить рисование первого и второго?
Мне кажется, что проблема в том, что в Resize можно описать только ОДНУ систему координат - либо glOrtho, либо gluPerspective, хотя возможно я и ошибаюсь.
← →
Fredy314 © (2006-12-12 18:52) [1]Ну так пусть будут системные окошка в перспективе, красиво расставить их в 3-Д чтоб все думали что так надо, а чтоб поворачивались вместе с камерой думаю сможешь сделать.
← →
Rial © (2006-12-12 19:58) [2]glOrtho или gluPerspective всего лишь выполняют
некоторые операции с матрицами OpenGL.
Надо сначала сделать
glLoadIdentify(), настроить все как надо
для Ortho, запомнить все текущие матрицы в
некоторую область памяти.
Теперь опять грузим единичную, настраиваем
все для режима перспективы и тоже ее сохраняем.
Теперь по мере необходимости загружаем нужные матрицы.
Вот и все, все просто :)
Вот вырезанный кусок кода, который может навести на
умную мысль:TGLMatrix = Array [0..3, 0..3] of GLFloat;
TGLMatrixes = record
Model : TGLMatrix;
Proj : TGLMatrix;
Tex : TGLMatrix;
end;
PGLMatrixes = ^ TGLMatrixes;
procedure riglSaveMatrix(Const PMatrixes : PGLMatrixes);
begin
With PMatrixes^ do begin
glGetFloatv(GL_PROJECTION_MATRIX, @Proj);
glGetFloatv(GL_MODELVIEW_MATRIX, @Model);
glGetFloatv(GL_TEXTURE_MATRIX, @Tex);
end;//With
end;
procedure riglLoadMatrix(Const PMatrixes : PGLMatrixes);
Var MatrixMode : GLInt;
begin
glGetIntegerv (GL_MATRIX_MODE, @MatrixMode);
With PMatrixes^ do begin
glMatrixMode(GL_PROJECTION);
glLoadMatrixF(@Proj);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixF(@Model);
glMatrixMode(GL_TEXTURE);
glLoadMatrixF(@Tex);
end;//With
glMatrixMode(MatrixMode);
end;
← →
RzCoDer © (2006-12-12 20:11) [3]glOrtho
← →
Creative (2006-12-13 10:32) [4]
> Теперь по мере необходимости загружаем нужные матрицы.
Я извиняюсь за тупой вопрос, я правильно понимаю, что на экране будет отображаться и объект, нарисованный в перспективе, и объект, нарисованный в орто? Загрузка последующей матрицы не стирает предыдущую?
А как в таком случае будет выглядеть ResizeScene? Ему ведь пофигу какие объекты и в какой момент нарисованы, он ведь просто пересчитывает размер области вывода и утанавливает какую-то одну проекцию. Не ставить же прорисовку в Resize?
← →
Vga © (2006-12-13 14:20) [5]> Я извиняюсь за тупой вопрос, я правильно понимаю, что на
> экране будет отображаться и объект, нарисованный в перспективе,
> и объект, нарисованный в орто? Загрузка последующей матрицы
> не стирает предыдущую?
Стирает, но все, что нарисовано с помощью первой матрицы останется. А с новой матрицей будет рисоваться поверх.
> А как в таком случае будет выглядеть ResizeScene? Ему ведь
> пофигу какие объекты и в какой момент нарисованы, он ведь
> просто пересчитывает размер области вывода и утанавливает
> какую-то одну проекцию. Не ставить же прорисовку в Resize?
Он даже не влияет на то, что уже нарисовано (не считая изменения вьюпорта). Resize влияет только на то, что будет нарисовано после него (если я правильно понял, как у тебя сделано). Тебе предлагают в Resize посчитать матрицы для данного разрешения и сохранить их в переменные. А потом при отрисовке грузить нужную матрицу (загрузил 3D, отрисовал трехмерные объекты, загрузил 2D, отрисовал двухмерные объекты).
← →
Creative (2006-12-13 16:03) [6]Я на правах примера поступила проще: написала процедуру DrawScene:
glPushMatrix;
glOrtho();
// манипуляции над матрицами
//отрисовка объекта
glPopMatrix;
glPushMatrix;
gluPerspective();
// манипуляции над матрицами
//отрисовка объекта
glPopMatrix;
Все рисуется именно так как надо, и я заметила, что в Resize вообще можно не ставить теперь пересчет матриц, кажется и так все ресайзится. Скажите - я что-то не упустила, это глупо?
И еще вопрос: не могу найти в документации - есть такой стиль окна, чтобы оно могло масштабироваться только пропорционально, или это самому задавать нало?
← →
RzCoDer © (2006-12-13 16:18) [7]лучше сначало рисовать 3D объект а после него уже всё 2D
← →
Creative (2006-12-13 16:39) [8]
> лучше сначало рисовать 3D объект а после него уже всё 2D
А почему? Это единственная претензия?
← →
MeF Dei Corvi © (2006-12-13 16:49) [9]
> А почему?
Потому, что при определенном стечении обстоятельств(например, при включенном DepthTest) 3д объект может перекрыть 2д, несмотря на то, что 2д нарисован позднее. Если я не прав, поправьте :)
> есть такой стиль окна, чтобы оно могло масштабироваться
> только пропорционально, или это самому задавать нало?
Насколько я знаю, такого стиля нет, хотя могу и ошибаться. Скорее всего, придётся регулировать это программно.
← →
Creative (2006-12-13 16:54) [10]Меня очень волнует реакция на вот это утверждение:
я заметила, что в Resize вообще можно не ставить теперь пересчет матриц, кажется и так все ресайзится
← →
MeF Dei Corvi © (2006-12-13 17:31) [11]
> Меня очень волнует реакция на вот это утверждение:
Что именно волнует? :) Смену проекции в Resize помещают только затем, чтобы уменьшить количество вычислений, производимых процессором и видеокартой, т.к. Resize вызывается только при смене размеров окна, когда Draw вызывается при перерисовке, а перерисовка обычно происходит во много раз чаще, чем Resize. В данном случае, менять проекцию придётся в любом случае. Если производительность - не критичный фактор(т.е. если пара миллисекунд не важна), то можно оставить как есть.
← →
Creative (2006-12-13 17:34) [12]
> MeF Dei Corvi © (13.12.06 16:49) [9]
> > А почему?Потому, что при определенном стечении обстоятельств(например,
> при включенном DepthTest) 3д объект может перекрыть 2д,
> несмотря на то, что 2д нарисован позднее. Если я не прав,
> поправьте :)
Вот кстати и вопрос на тему, что за чем рисовать: Я рисую 3D объект, потом 2D объект (квадрат), а потом хочу вывести надписть поверх квадрата (с помощью glPrint("Caption")). Но надпись явно лежит ПОД кнопкой. Почему и как с этим бороться?
← →
MeF Dei Corvi © (2006-12-13 17:41) [13]Попробуй так:
glPushMatrix;
gluPerspective();
...
glPopMatrix;
glDisable(GL_DEPTH_TEST);glPushMatrix;
glOrtho();
...
glPopMatrix;
glEnable(GL_DEPTH_TEST);
← →
Creative (2006-12-13 17:47) [14]
> MeF Dei Corvi © (13.12.06 17:41) [13]
Получилось, получилось!!!!!! Спасибо :-)
← →
Creative (2006-12-13 17:59) [15]А может кто-нибудь объяснить, почему угол наклона в направлении оси X задается именно отношением ширины области вывода к ее высоте?
← →
Piroxyline © (2006-12-13 19:16) [16]Имхо, это уже к создателям OpenGL"я
← →
Piroxyline © (2006-12-13 19:19) [17]Хотя, наверное, из-за подобной картины:
|
A\--| B
\ |
-------+-------
|\
C|-\ D
| \
koeff = AB/CD
Или что-то типа такого. По крайней мере, мы похожую картину сейчас по физике разбирали
← →
Creative (2006-12-14 11:13) [18]
> Rial © (12.12.06 19:58) [2]
Я попробовала написать сохранение матриц:type
TGLMatrix = Array [0..3, 0..3] of GLFloat;
TGLMatrixes = record
Model : TGLMatrix;
Proj : TGLMatrix;
Tex : TGLMatrix;
end;
PGLMatrixes = ^TGLMatrixes;
procedure SaveMatrix(Const PMatrixes : PGLMatrixes);
procedure LoadMatrix(Const PMatrixes : PGLMatrixes);
var
OrthoMatrix : PGLMatrixes;
PerspMatrix : PGLMatrixes;
implementation
procedure SaveMatrix(Const PMatrixes : PGLMatrixes);
begin
With PMatrixes^ do begin
glGetFloatv(GL_PROJECTION_MATRIX, @Proj);
glGetFloatv(GL_MODELVIEW_MATRIX, @Model);
glGetFloatv(GL_TEXTURE_MATRIX, @Tex);
end;//With
end;
procedure TCWnd.ResizeGLScene(Width, Height: integer);
begin
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glOrtho(0, Width, Height, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glViewport(0, 0, Width, Height);
SaveMatrix(OrthoMatrix);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(30, Width/Height, 1.0, 15.0);
glRotate(30,1.0,0.0,0.0);
glRotate(60,0.0,1.0,0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glViewport(0, 0, Width, Height);
SaveMatrix(PerspMatrix);
end;
Но вероятно я как то неправильно сделала, и PMatrixes^ = NIL. Поправьте меня, пожалуйста.
← →
Vga © (2006-12-14 12:50) [19]> [18] Creative (14.12.06 11:13)
А память под матрицы выделить? Либо GetMem(OrthoMatrix, SizeOf(TGLMatrixes)) и то же для второй. Еще можно убрать объявление PGLMatrixes и передавать TGLMatrixes как var в SaveMatrix и как const в Loadmatrix
← →
Creative (2006-12-14 12:56) [20]
> А память под матрицы выделить? Либо GetMem(OrthoMatrix,
> SizeOf(TGLMatrixes)) и то же для второй. Еще можно убрать
> объявление PGLMatrixes и передавать TGLMatrixes как var
> в SaveMatrix и как const в Loadmatrix
А я проше сделала (ладно, может и не проще, понятнее для меня) - сделала TGLMatrixes не рекордом, а классом и создала две переменные-объекты класса. Все работает, проекции грузятся, как раз то, что я хотела.
Этот способ не хуже?
Я кстати не мгу понять: почему в обоих процедурах (Save, Load) - аргумент - константа?
← →
Vga © (2006-12-14 13:40) [21]> [20] Creative (14.12.06 12:56)
> Я кстати не мгу понять: почему в обоих процедурах (Save,
> Load) - аргумент - константа?
Я тоже. Можно const оттуда убрать. Смысла передавать указатель по ссылке - не вижу.
← →
Rial © (2006-12-15 01:31) [22]> [21] Vga © (14.12.06 13:40)
> > [20] Creative (14.12.06 12:56)
> > Я кстати не мгу понять: почему в обоих процедурах (Save,
> > Load) - аргумент - константа?
> Я тоже. Можно const оттуда убрать. Смысла передавать указатель
> по ссылке - не вижу.
Нет, вы конечно правы.
Код с Const и без него будет сгенерирован компилятором
абсолютно идентичный.
Но вот только указатель это или нет - это тут очевидно.
А следить за каждой такой мелочью порой очень сложно :)
Если бы аргумент был TGLMatrixes - потери были бы налицо.
Так что это страховка на будущее.
> [10] Creative (13.12.06 16:54)
> Меня очень волнует реакция на вот это утверждение:
>
> я заметила, что в Resize вообще можно не ставить теперь
> пересчет матриц, кажется и так все ресайзится
Все дело в том, что в gluPerspective используется ArcTan.
А это достаточно медленная арифметическая операция, что иногда критично.
Resize иногда выполняется 2-3 раза за всю работу приложения.
> [20] Creative (14.12.06 12:56)
> А я проше сделала (ладно, может и не проще, понятнее для
> меня) - сделала TGLMatrixes не рекордом, а классом и создала
> две переменные-объекты класса.
Это правильнее безусловно. Но есть одна мелочь. Не исключаю,
что у меня кривые руки, но когда я переводил достаточно большой кусок
кода OpenGL на ООП (объектов вышло достаточно много), то потерял 20%
производительности. Так что главное - не "намельчить".
← →
Creative (2006-12-15 10:18) [23]
> Rial © (15.12.06 01:31) [22]
когда я переводил достаточно
> большой кусоккода OpenGL на ООП (объектов вышло достаточно
> много), то потерял 20%производительности. Так что главное
> - не "намельчить".
А как вы оцениваете производительность программы? Время выпорнения операций? Или что это?
Не намельчить - в смысле - не пытаться сделать классы из всего, чего только можно?
← →
Rial © (2006-12-15 16:40) [24]> [23] Creative (15.12.06 10:18)
> А как вы оцениваете производительность программы? Время
> выпорнения операций? Или что это?
1. Количество кадров, которые успевают отрисоваться.
Подходит только если кадры рисуются постоянно и нет
счетчика ограничейний. Способ самый ущербный.
2. Обжее время, затраченное на выполнение все операций
поделить на прошедшее время. Имеется ввиду не разовая
задача, конечно, а отрисовка с относительно постоянным
количеством кадров.
3.Операции считать. Можно посчитать с точностью до
+- 0.1 мс. Статистика, разные условия выполнения и т.п.
Статистику лучше считать временно дав RealTime.
> Не намельчить - в смысле - не пытаться сделать классы из
> всего, чего только можно?
Вот это в точку подмечено.
Особенно заметно это там, где производятся
арифметические рассчеты.
Если класс заменяет record с двумя полями,
а значение полей извлекаются через виртуальные методы
родителя, да еще через что то типаfunction GetValue : TValue;
begin
Result:=FValue;
end;
то тут почуствуешь в полной мере все "достоинства" ооп :)
Итог - замедление раз в 5-10.
← →
Creative (2006-12-15 16:50) [25]
> 1. Количество кадров, которые успевают отрисоваться.
FPS?
> нет счетчика ограничейний.
а что такое счетчик ограничений?
> Статистику
> лучше считать временно дав RealTime.
а что значит "временно дать RealTime"?
> Если класс заменяет
> record с двумя полями,а значение полей извлекаются через
> виртуальные методыродителя, да еще через что то типаfunction
> GetValue : TValue;begin Result:=FValue;end;то тут почуствуешь
> в полной мере все "достоинства" ооп :)Итог - замедление
> раз в 5-10.
Вот так так...а я то думала, чо расписывать извлечение значений полей через GetValue - это ужас как круто....
Я правильно понимаю, что использоваться рекорд - быстрее, а класс - многофункциональнее? Или есть еще принципиальные различия? Я напрмимер по странному стечению обстоятельств сначала научилась работать с классами, а про рекорды узнала позже, поэтому тебперь мне с ними трудно.
← →
Rial © (2006-12-15 17:28) [26]> [25] Creative (15.12.06 16:50)
> FPS?
Да, оно самое.
> а что такое счетчик ограничений?
Ну, например, счетчик такого типа, что не разрешает
перерисовывать экран чаще, чем раз в 20мс.
Вообще, имхо, лучше делать постоянное FPS,
потому как наверняка есть еще какие рассчеты,
а не только вывод на экран. А рассчеты наверняка
четко привязаны ко времени
(ну хотябы падение тела в реальном времени).
Смыла не вижу перерисовывать экран чаще, чем эго
содержимое должно изменяться.
> а что значит "временно дать RealTime"?
Приоритет процесса.procedure SetPriority(Const PriorityClass, ThreadClass : Integer);
Var ProcessID : DWORD;
ProcessHandle : THandle;
ThreadHandle : THandle;
begin
ProcessID;=GetCurrentProcessID;
ProcessHandle:=OpenProcess(PROCESS_SET_INFORMATION, False, ProcessID);
SetPriorityClass(ProcessHandle, PriorityClass);
ThreadHandle:=GetCurrentThread;
SetThreadPriority(ThreadHandle, ThreadClass)
end;
> Вот так так...а я то думала, чо расписывать извлечение значений
> полей через GetValue - это ужас как круто....
Круто, конечно.
Но это в итоге лишнии инструкции call и ret.
Так то, с т.з. переменных класса, это те же
поля записей.Name:=MyClass.FName;
Name:=MyRecord.Name;
- разницы особой нет.
Только в случае с классом получаем лишнюю инструкцию move,
ибо переменная MyClass - своего рода указатель на запись.
Может, я мелочный, конечно. Но, имхо, все эти мелочи
со временем могут в большой ком снежный сложиться.
> Я правильно понимаю, что использоваться рекорд - быстрее,
> а класс - многофункциональнее? Или есть еще принципиальные
> различия?
Ну, рекод - это не более чем более удобный доступ
к области памяти.
Например, есть Data : Pointer, в ней лежат Integer и 2 Byte.
Намного удобнее и понятнее сделать так:TRec = packed record
I : Integer;
B1, B2 : Byte;
end;
PRec = ^TRec;
...
PRec(Data)^.B2:=10;
Чем вот так:
PByteArray(Data)^[SizeOf(Integer) + SizeOf(Byte) * 2]:=10;
А класс - это нечто намного большее.
Слышали Вы про виртуальные, абстрактные методы и т.п.
Они разработку значительно упрощают.
И целостность данных позволяют грамотно обеспечить.
Все до тех пор, пока не идет война за каждый тик процессора :)
← →
MeF Dei Corvi © (2006-12-15 21:54) [27]
> > а что значит "временно дать RealTime"?
У меня такие процессы вешают всю систему сразу же :)
← →
Creative (2006-12-18 10:36) [28]
> Ну, рекод - это не более чем более удобный доступк
> области памяти.Например, есть Data : Pointer, в ней лежат
> Integer и 2 Byte.Намного удобнее и понятнее сделать так:
> TRec = packed record
> I : Integer;
> B1, B2 : Byte;end;
> PRec = ^TRec;
...
> PRec(Data)^.B2:=10;
> Чем вот так:PByteArray(Data)^[SizeOf(Integer)
> + SizeOf(Byte) * 2]:=10;
А почему PRec = ^TRec, а не Rec: TRec?
>А класс - это нечто намного большее.
> Слышали Вы про виртуальные, абстрактные методы и т.п.Они
> разработку значительно упрощают.И целостность данных позволяют
> грамотно обеспечить.Все до тех пор, пока не идет война за
> каждый тик процессора :)
А что тогда? Опять возвращаются к рекордам?
← →
Creative (2006-12-18 10:37) [29]
> У меня такие процессы вешают всю систему сразу же :)
А почему?
← →
Rial © (2006-12-18 14:04) [30]> [29] Creative (18.12.06 10:37)
> > У меня такие процессы вешают всю систему сразу же :)
> А почему?
Ну, по идее, если процесс получает RealTime и начинает усиленно
работать, что все процессорное время уходит только на него.
Не спасет даже Ctrl+Alt+Del. Но до таких крайностей не
обязательно же доводить :)
I>
> А почему PRec = ^TRec, а не Rec: TRec?
Ну так Data - указатель же.
Привести указатель с TRec не получится, а к указателю на TRec -
запросто. Точнее, получится, но придется копировать данные,
например, так:
Move(Data^, Rec, SizeOf(Rec));
что при больших размерах TRec не очень хорошо.
P.S. А почему Data - указатель ? :)
Ну а что это еще может быть, не понятно. Выделили память,
считали, например, и файла все в область памяти и бегаем
по указателю с разными смещениями.
> А что тогда? Опять возвращаются к рекордам?
Да нет. Я не совсем это имел ввиду.
Просто всему свое место. Не надо на одном зацикливаться.
Если разработка идет несколькими людьми, то классы
предпочтительнее. Или если проект очень большой и потом
будет сложно разобраться без классов (лучше большие
модули все же запихнуть в них).
А если человек один, и он уверен, что правильно
везде после использования финализирует переменные,
освободит память и т.п., то почему бы и не рекорды.
Что то много как то у меня слов получается, о больном потому что :)
← →
Creative (2006-12-18 14:34) [31]
> Что то много как то у меня слов получается, о больном потому
> что :)
почему о больном? не уверены, много вас или мало? :-)
← →
Rial © (2006-12-18 17:04) [32]Нет, уверен, меньше нас :)
Просто я все жду, когда же сюда сбегутся
защитники классов, ООП, VCL ...
Их же явно больше. Затопчут.
Ну да простит их всевышний, многие не ведают, что творят %)
Есть простой способ в Delphi кстати.
Там же можно посмотреть генерируемый asm - код.
Вот по нему очень легко понять, какой алгоритм
более оптимальный.
Страницы: 1 вся ветка
Форум: "Игры";
Текущий архив: 2008.01.27;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.037 c