Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Игры";
Текущий архив: 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
15-1198058994
BVV
2007-12-19 13:09
2008.01.27
HEX редактор


15-1198169940
Pazitron_Brain
2007-12-20 19:59
2008.01.27
Решил пользоваться скайп


2-1198611275
Kuvalda
2007-12-25 22:34
2008.01.27
Увеличение на единицу!


2-1198144416
Василий
2007-12-20 12:53
2008.01.27
Скомандовать файлу справки из приложения


15-1198175127
краснаЯ ГВАРДИЯ
2007-12-20 21:25
2008.01.27
задачи





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский