![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Полусфера на поверхности сферы (OpenGL) [Delphi, Windows]
Creative © (2006-11-28 14:34:00)Есть Сфера и есть полусфера. Как сделать следующую вещь:
Нарисовать полусфера таким образом стобы ее можно было возить по сфере , останавливая в произвольной точке?
Была мысль использовать для рисования полусферы gluSphere + glClipPlane, но при тех параметрах, которые принимает в себя glClipPlane, не могу понять, как заставить ее произвольно вертеться.
Подскажите что-нибудь.
ancara (2006-11-29 12:01:00) [81]ошибся, glGenList s
Creative (2006-11-29 11:54:00) [82]
> не, ListID надо сначала получить: ListID:=glGenList(1);
но компилятор пишет, что glGenList(1) - undeclared identifier
ancara (2006-11-29 11:42:00) [83]
> 1. procedure BuildList:
> ListID:=1;
не, ListID надо сначала получить: ListID:=glGenList(1);
потом мой код, там в нем уже есть glNewList
> 2. procedure Render:
вместо glCallList(1); надо glCallList(ListID);
ну в остальном вроде все верно, только в рендере сейчас PushMatrix и PopMatrix бессмыслены, ибо матрица и так остается неизменной, но если между ними будут преобразования сист. координат (glRotate или glTranslate или glScale) то тогда они будут иметь смысл.
ancara (2006-11-29 11:36:00) [84]
> А как узнать то и другое?
Да это вобщем-то и не обязательно знать, просто графич. движок может быть устроен таким образом, что у каждого объекта есть своя собственная матрица, однозначно определяющая его положение в пространстве, смещение относит. начала координат и его "вытянутость" по трем осям. В таком случае, перед рендерингом этого объекта, его не нужно будет последовательно крутить вокруг трех осей, затем смещать, затем масштабировать, а можно просто загрузить его собственную матрицу, сделать рендеринг и восстановить исходную, затем также со следующим... . Правда при передвижении или поворотах этого объекта, его матрицу придется перерасчитывать.
А насчет первого варианта, если известна матрица преобразований... ну я не знаю, но всякое в жизни бывает... Главное то, что есть такая возможность, матрицы перемножать! :))
Да, кстати я забыл перечислить, текущую матрицу можно прочитать ф-цией glGet с аргументом GL_MODELVIEW_MATRIX.
Creative (2006-11-29 11:09:00) [85]По поводу дисплейных списов. С первого раза, конечно ничего не заработало. Я правильно делаю:
1. procedure BuildList:
ListID:=1;
glNewList(ListID, GL_COMPILE);
......твой код рисования полусферы
glEndList;
2. procedure Render:
glPushMatrix();
glColor3f(255,255,255);
glCallList(1);
glPopMatrix();
Так?
Creative (2006-11-29 10:44:00) [86]
> В общем, чтобы не было аддитивности делаем так:
>glMatrixMode(GL_MODELVIEW);
>glPushMatrix;
>glRotate;
> - делаем рендеринг объекта в новой сист. коор.: glCallList,
> например;
Про рендеринг я впервые слышу, хотя что-то уже как-то рисую. Может это еще каким-то более известным способом делается?
> а можно glMultMatrix, если нам известна матрица
> преобразований,
> а можно вообще сразу glLoadMatrix, если нам известна
> результирующая матрица;
А как узнать то и другое?
ancara (2006-11-28 19:42:00) [87]
> а вы наверняка знаете
завязывай, давай на ты
> Так может просто в конструкторе его собирать?
Ну можно и в конструкторе, только сам код лучше разместить все таки в отдельном методе а из конструктора его вызывать, иначе как быть, если изменится радиус, например, или другие параметры геометрии? Его же опять надо будет вызвать...
> Кажется, эти списки для меня вообще предмет новый.
Ну знать их безусловно надо, но в будущем ориентируйся на DrawArrays и VBO (Vertex Buffer Object) - более гибкая штука, хотя бывают споры насчет того кто кого обгоняет, главное грамотно и в нужном месте применить, но это уже нюансы, для начала списки самое то.
> у меня есть два примитива на одной сцене. Как мне каждый
> из них повернуть на свой угол? А то мне кажется, что glPotate
> действует аддитивно.
Кароче так, в OpenGL есть три матрицы:
GL_PROJECTION - определяет параметры проекции пространства сцены на область вывода;
GL_TEXTURE - определяет параметры наложения текстур (масштаб смещение поворот)
и GL_MODELVIEW - определяет систему координат пространства сцены.
Так вот glRotate принимает от нас угол, на кот. будем поворачивать и вектор, вокруг которого крутить и по ним строит матрицу поворота.
Затем умножает текущую матрицу (GL_MODELVIEW) на матрицу поворота, в итоге матрица GL_MODELVIEW определяет уже повернутую систему координат.
Для взаимодействия с матрицами существуют функции:
glMatrixMode(GL_MODELVIEW или другая из тех трех) - выбрать матрицу, с которой будут производиться манипуляции;
glLoadIdentity - сделать текущую матрицу единичной;
glPushMatrix - поместить текущую матрицу в стек;
glMultMatrix - умножить тек. матрицу на нек. матрицу, результат будет записан в текущую;
glLoadMatrix - загрузить свою матрицу в текущую;
glPushMatrix - поместить еще одну текущую матрицу в стек, а та которая там была сдвинется на второе место соответственно:)) ;
Глубина стека матриц зависит от реализации OpenGL (от модели видеокарты кароче);
glPopMatrix - достать матрицу из стека и сделать ее текущей;
glPopMatrix - достать ту, самую первую матрицу :) из стека и сделать ее текущей;
Что-то я забыл перечислить... смотри RedBook, там все подробно :))
В общем, чтобы не было аддитивности делаем так:
- имеем начальную систему координат;
- работаем с матрицей MODELVIEW: glMatrixMode(GL_MODELVIEW);
- сохраняем текущ. матрицу в стек: glPushMatrix;
- крутим-вертим сист. коорд.:
- можно glRotate+glTranslate+glScale,
- а можно glMultMatrix, если нам известна матрица преобразований,
- а можно вообще сразу glLoadMatrix, если нам известна результирующая матрица;
- делаем рендеринг объекта в новой сист. коор.: glCallList, например;
- восстанавливаем сист. коорд. в исходную: glPopMatrix;
- ну и опять тоже самое начиная с glPushMatrix для следующего объекта...
Ну вот примерно так...
Creative (2006-11-28 18:06:00) [88]Кажется, эти списки для меня вообще предмет новый. Завтра будет много вопросов.
>
> Не, не надо ее в рендер ставить, добавь какой-нить метод
> типа BuildList (или ReBuildList), в нем будем строится список
> объекта (нажо стремиться делать это как можно реже, лучше
> вообще один раз:)) ). А в рендере надо просто вызвать этот
> список glCallList(номер списка) и фсио! :)
Так может просто в конструкторе его собирать?
ancara (2006-11-28 18:02:00) [89]
> какое количество списков мне нужно
ну это уже как удобней будет, если известно, что части какого-то объекта не будут перемащаться относит друг друга, то можно все это тела сделать одним списком. Ну если уж переместятся, то список можно пересобрать, но лучше этого избегать ибо ресурсоемко...
Как крайность, теоретически, можно конечно и всю сцену одним списком собрать, но тогда придется при каждом изменении пересобирать заново и никакого толку от использования списков.. А можно и каждый полигон в свой список запихнуть, но тут никаких списков не напасешься.. :))
> саму приведенную вами процедуру ставлю в TMyClass.Render
Не, не надо ее в рендер ставить, добавь какой-нить метод типа BuildList (или ReBuildList), в нем будем строится список объекта (нажо стремиться делать это как можно реже, лучше вообще один раз:)) ). А в рендере надо просто вызвать этот список glCallList(номер списка) и фсио! :)
Creative (2006-11-28 17:53:00) [90]Можно немного посторонний вопрос задать (просто не хочется из-за такой ерунды целую ветку открывать, а вы наверняка знаете): у меня есть два примитива на одной сцене. Как мне каждый из них повернуть на свой угол? А то мне кажется, что glPotate действует аддитивно.
Creative (2006-11-28 17:51:00) [91]Следующий тупой вопрос: а как мне понять, какое количество списков мне нужно в данном конкретном случае со сферой?
И если я, например, саму приведенную вами процедуру ставлю в TMyClass.Render, то в конструкторе мне нужно написать FListID:= "собственно нужное мне число списков", так?
ancara (2006-11-28 17:46:00) [92]
> а не glNewList(FListID,
Не там у меня было именно свойство ListID, в принципе без разницы :))
> ListID как инициализировать?
ListID:=glGenLists(1); //1 - это количество списков,
ListID:= glGenLists(range: Integer) генерирует range идентификаторов диспл. списков, следующих подряд, при этом ListID принимает значение первого из них.
Т.е. если нам требуется 18 списков, мы делаем ListID:= glGenLists(18) и смотрим
чему равен ListID, если он, к примеру, равен 44, то это значит что OpenGL для нас зарезервировал диспл. списки с 44 по 61 включительно и мы их можем использовать. После того как они станут не нужны следует их удалить функцией glDeleteLists.
Чтобы пересобрать, скажем, 47 дисп. список, его не обязательно удалять и заново создавать, можно прям так и написать glNewList(47, GL_COMPILE) и т.д.
Creative (2006-11-28 17:27:00) [93]Вопрос наверное тупой: ListID как инициализировать?
Creative (2006-11-28 17:24:00) [94]а точно вот так glNewList(ListID, GL_COMPILE),
а не glNewList( FListID, GL_COMPILE);
Creative (2006-11-28 17:16:00) [95]aziStartR:= FAzimuthStart*pi/180;
из класса выдрал? :-)
ancara (2006-11-28 17:12:00) [96]Ой, самое главное вырезал!
После того как координаты обоих вершин посчитали делаем
glVertex3fv(@Vec2);
glVertex3fv(@Vec1);
> Результат интересен?
Отпишись:))
Будут вопросы - излагай :)
Creative (2006-11-28 17:11:00) [97]Так написано то вроде правильно?
ancara (2006-11-28 17:06:00) [98]Поправка: в начале кода написал
aziStartR:=FAzimuthStart*pi/180; //Тут переводим из радианов в градусы
aziStopR:=FAzimuthStop*pi/180; //значения углов
там наоборот конечно же, в радианы все гоним!
Creative (2006-11-28 17:06:00) [99]Душевное вам спасибо, и особливо за комменты, пойду пробовать :-)
Результат интересен?
ancara (2006-11-28 17:03:00) [100]можно самому сферу построить, точнее даже часть сферы в дипазонах по зениту и азимуту и вращать ее glRotate как обычный примитив.
вот код, там дисплейные списки используется, это не совсем "прогресивный" метод, но результат тот же
type
TVector3f = array [0..2]of single;
var
zen, azi: real; //счетчики углов по зениту и азимуту (радианы)
aziNext, zenNext: real; //счетчики углов по зен. и аз. для след. шага (радианы)
aziStartR, aziStopR: real; //диапазон по азимуту
zenStartR, zenStopR: real; //диапазон по зениту
stpZ, stpA: real; //шаги по зен. и азим.
Vec1, Vec2: TVector3f; //координаты вершин для опенгл
begin
aziStartR:=FAzimuthStart*pi/180; //Тут переводим из радианов в градусы
aziStopR:=FAzimuthStop*pi/180; //значения углов
zenStartR:=FZenithStart*pi/180;
zenStopR:=FZenithStop*pi/180;
glNewList(ListID, GL_COMPILE); //ListID - номер диспл. списка
stpZ:=pi/FSlices; //считаем шаг по зениту, FSlices - кол-во разбиений по меридиану
stpA:=pi*2/FLoops; //считаем шаг по азимуту, FLoops - колво разбиений по параллели
zen:=zenStartR; //счетчик зенита в нач. значение
while zen<=zenStopR do //будем увелич. его на шаг, пока не упремся в конечн. значение
begin
if zen=zenStopR then Break; //если start = stop выходим из while .. do
//тут хитро считаем следующий угол по зениту с учетом шага и стопа
zenNext:=-pi/2;
while zenNext<=zen do zenNext:=zenNext+stpZ;
if zenNext>zenStopR then zenNext:=zenStopR;
azi:=aziStartR; //счетчик азимута в начальное значение
glBegin(GL_QUAD_STRIP); //начинаем примитив "лента из четырехугольников"
while azi<=aziStopR do //будем увелич. азимут на шаг, пока не упремся в конечн. значение
begin
//тут считаем координаты первой и второй вершины
Vec1[0]:=Sin(azi)*Cos(zen)*FRadius; //FRadius - радиус сферы
Vec1[1]:=Sin(zen)*FRadius;
Vec1[2]:=Cos(azi)*Cos(zen)*FRadius;
Vec2[0]:=Sin(azi)*Cos(zenNext)*FRadius;
Vec2[1]:=Sin(zenNext)*FRadius;
Vec2[2]:=Cos(azi)*Cos(zenNext)*FRadius;
//почему выходим именно тут не помню давно это было :))
if azi=aziStopR then break;
//тут хитро считаем следующий угол по азимуту с учетом шага и стопа
aziNext:=0;
while aziNext<=azi do aziNext:=aziNext+stpA;
if aziNext>aziStopR then aziNext:=aziStopR;
azi:=aziNext; //наращиваем азимут
end;
glEnd;
zen:=zenNext; //наращиваем зенит
end;
glEndList;
end;
Ух, запарился каменты писать :)) Тут еще и топик прыгает по веткам :))
Насчет работоспособности именно ЭТОГО куска не уверен, не проверял, выдрал из компонента, может что и забыл убрать лишнее...