Форум: "Игры";
Текущий архив: 2008.01.13;
Скачать: [xml.tar.bz2];
ВнизПолусфера на поверхности сферы (OpenGL) Найти похожие ветки
← →
Creative (2006-11-28 14:34) [0]Есть Сфера и есть полусфера. Как сделать следующую вещь:
Нарисовать полусфера таким образом стобы ее можно было возить по сфере , останавливая в произвольной точке?
Была мысль использовать для рисования полусферы gluSphere + glClipPlane, но при тех параметрах, которые принимает в себя glClipPlane, не могу понять, как заставить ее произвольно вертеться.
Подскажите что-нибудь.
← →
ancara © (2006-11-28 17:03) [1]можно самому сферу построить, точнее даже часть сферы в дипазонах по зениту и азимуту и вращать ее 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;
Ух, запарился каменты писать :)) Тут еще и топик прыгает по веткам :))
Насчет работоспособности именно ЭТОГО куска не уверен, не проверял, выдрал из компонента, может что и забыл убрать лишнее...
← →
Creative (2006-11-28 17:06) [2]Душевное вам спасибо, и особливо за комменты, пойду пробовать :-)
Результат интересен?
← →
ancara © (2006-11-28 17:06) [3]Поправка: в начале кода написал
aziStartR:=FAzimuthStart*pi/180; //Тут переводим из радианов в градусы
aziStopR:=FAzimuthStop*pi/180; //значения углов
там наоборот конечно же, в радианы все гоним!
← →
Creative (2006-11-28 17:11) [4]Так написано то вроде правильно?
← →
ancara © (2006-11-28 17:12) [5]Ой, самое главное вырезал!
После того как координаты обоих вершин посчитали делаемglVertex3fv(@Vec2);
glVertex3fv(@Vec1);
> Результат интересен?
Отпишись:))
Будут вопросы - излагай :)
← →
Creative (2006-11-28 17:16) [6]aziStartR:=FAzimuthStart*pi/180;
из класса выдрал? :-)
← →
Creative (2006-11-28 17:24) [7]а точно вот так glNewList(ListID, GL_COMPILE),
а не glNewList(FListID, GL_COMPILE);
← →
Creative (2006-11-28 17:27) [8]Вопрос наверное тупой: ListID как инициализировать?
← →
ancara © (2006-11-28 17:46) [9]
> а не 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:51) [10]Следующий тупой вопрос: а как мне понять, какое количество списков мне нужно в данном конкретном случае со сферой?
И если я, например, саму приведенную вами процедуру ставлю в TMyClass.Render, то в конструкторе мне нужно написать FListID:= "собственно нужное мне число списков", так?
← →
Creative (2006-11-28 17:53) [11]Можно немного посторонний вопрос задать (просто не хочется из-за такой ерунды целую ветку открывать, а вы наверняка знаете): у меня есть два примитива на одной сцене. Как мне каждый из них повернуть на свой угол? А то мне кажется, что glPotate действует аддитивно.
← →
ancara © (2006-11-28 18:02) [12]
> какое количество списков мне нужно
ну это уже как удобней будет, если известно, что части какого-то объекта не будут перемащаться относит друг друга, то можно все это тела сделать одним списком. Ну если уж переместятся, то список можно пересобрать, но лучше этого избегать ибо ресурсоемко...
Как крайность, теоретически, можно конечно и всю сцену одним списком собрать, но тогда придется при каждом изменении пересобирать заново и никакого толку от использования списков.. А можно и каждый полигон в свой список запихнуть, но тут никаких списков не напасешься.. :))
> саму приведенную вами процедуру ставлю в TMyClass.Render
Не, не надо ее в рендер ставить, добавь какой-нить метод типа BuildList (или ReBuildList), в нем будем строится список объекта (нажо стремиться делать это как можно реже, лучше вообще один раз:)) ). А в рендере надо просто вызвать этот список glCallList(номер списка) и фсио! :)
← →
Creative (2006-11-28 18:06) [13]Кажется, эти списки для меня вообще предмет новый. Завтра будет много вопросов.
>
> Не, не надо ее в рендер ставить, добавь какой-нить метод
> типа BuildList (или ReBuildList), в нем будем строится список
> объекта (нажо стремиться делать это как можно реже, лучше
> вообще один раз:)) ). А в рендере надо просто вызвать этот
> список glCallList(номер списка) и фсио! :)
Так может просто в конструкторе его собирать?
← →
ancara © (2006-11-28 19:42) [14]
> а вы наверняка знаете
завязывай, давай на ты
> Так может просто в конструкторе его собирать?
Ну можно и в конструкторе, только сам код лучше разместить все таки в отдельном методе а из конструктора его вызывать, иначе как быть, если изменится радиус, например, или другие параметры геометрии? Его же опять надо будет вызвать...
> Кажется, эти списки для меня вообще предмет новый.
Ну знать их безусловно надо, но в будущем ориентируйся на 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-29 10:44) [15]
> В общем, чтобы не было аддитивности делаем так:
>glMatrixMode(GL_MODELVIEW);
>glPushMatrix;
>glRotate;
> - делаем рендеринг объекта в новой сист. коор.: glCallList,
> например;
Про рендеринг я впервые слышу, хотя что-то уже как-то рисую. Может это еще каким-то более известным способом делается?
> а можно glMultMatrix, если нам известна матрица
> преобразований,
> а можно вообще сразу glLoadMatrix, если нам известна
> результирующая матрица;
А как узнать то и другое?
← →
Creative (2006-11-29 11:09) [16]По поводу дисплейных списов. С первого раза, конечно ничего не заработало. Я правильно делаю:
1. procedure BuildList:
ListID:=1;
glNewList(ListID, GL_COMPILE);
......твой код рисования полусферы
glEndList;
2. procedure Render:
glPushMatrix();
glColor3f(255,255,255);
glCallList(1);
glPopMatrix();
Так?
← →
ancara © (2006-11-29 11:36) [17]
> А как узнать то и другое?
Да это вобщем-то и не обязательно знать, просто графич. движок может быть устроен таким образом, что у каждого объекта есть своя собственная матрица, однозначно определяющая его положение в пространстве, смещение относит. начала координат и его "вытянутость" по трем осям. В таком случае, перед рендерингом этого объекта, его не нужно будет последовательно крутить вокруг трех осей, затем смещать, затем масштабировать, а можно просто загрузить его собственную матрицу, сделать рендеринг и восстановить исходную, затем также со следующим... . Правда при передвижении или поворотах этого объекта, его матрицу придется перерасчитывать.
А насчет первого варианта, если известна матрица преобразований... ну я не знаю, но всякое в жизни бывает... Главное то, что есть такая возможность, матрицы перемножать! :))
Да, кстати я забыл перечислить, текущую матрицу можно прочитать ф-цией glGet с аргументом GL_MODELVIEW_MATRIX.
← →
ancara © (2006-11-29 11:42) [18]
> 1. procedure BuildList:
> ListID:=1;
не, ListID надо сначала получить: ListID:=glGenList(1);
потом мой код, там в нем уже есть glNewList
> 2. procedure Render:
вместо glCallList(1); надо glCallList(ListID);
ну в остальном вроде все верно, только в рендере сейчас PushMatrix и PopMatrix бессмыслены, ибо матрица и так остается неизменной, но если между ними будут преобразования сист. координат (glRotate или glTranslate или glScale) то тогда они будут иметь смысл.
← →
Creative (2006-11-29 11:54) [19]
> не, ListID надо сначала получить: ListID:=glGenList(1);
но компилятор пишет, что glGenList(1) - undeclared identifier
← →
ancara © (2006-11-29 12:01) [20]ошибся, glGenLists
← →
Creative (2006-11-29 12:10) [21]Самое противное заключается в том, что все равно ничего не происходит. Все компилится, все запускается, но ничего не рисуется. И вот теперь я уже не могу сказать, почему.
← →
Creative (2006-11-29 13:11) [22]Я могу код класса TSphere привести, если это поможет.
← →
ancara © (2006-11-29 14:58) [23]Я тут выложил свой рабочий примерчик, там полигон и текстура на нем. Рендеринг через вызов дисплейного списка. Там еще есть парочка "лишних" процедур для управления камерой при помощи мышки, ну думаю разберешься...
Начинается все с OnCreate формы : создается контекст OpenGL, некот. инициализация камеры и проч. и BuildList - создается список с этим полигоном и все. А дальше вызывается RenderScene, когда надо перерисовать форму (событие OnPaint).
← →
ancara © (2006-11-29 14:58) [24]Я тут выложил свой рабочий примерчик:
http://s28.quicksharing.com/v/8118153/OpenGL_texture.rar.html
, там полигон и текстура на нем. Рендеринг через вызов дисплейного списка. Там еще есть парочка "лишних" процедур для управления камерой при помощи мышки, ну думаю разберешься...
Начинается все с OnCreate формы : создается контекст OpenGL, некот. инициализация камеры и проч. и BuildList - создается список с этим полигоном и все. А дальше вызывается RenderScene, когда надо перерисовать форму (событие OnPaint).
← →
ancara © (2006-11-29 14:59) [25]хех, забыл сначала линк вставить :)
← →
Creative (2006-11-29 15:05) [26]Спасибо! Я постараюсь разобраться обязательно.
← →
Creative (2006-11-29 15:29) [27]Все бы ничего, только не качается он :-(
← →
Creative (2006-11-29 15:45) [28]Все в порядке, это у меня глюки
← →
Creative (2006-11-29 16:09) [29]Я дико извиняюсь, но по моему в твоем архиве чего-то не хватает. В частности файла Main_u.pas.
← →
ancara © (2006-11-29 16:24) [30]как так? а остальные есть? не может быть!
вобщем там было 4 (четыре) файла:
main_u.dfm
OpenGL_texture.dpr
1.jpg
main_u.pas
код main_u.pas положу сюда http://www.everfall.com/paste/id.php?icy518q11p56
← →
Creative (2006-11-29 16:28) [31]Мне архив сказал "неожиданный конец", и файла оказалось только три. Пас как раз и потерялся
← →
Creative (2006-11-29 16:31) [32]кстати, насчет независимого поволота объектов. Я вот как сделала:
glTranslatef (0.0, 0.0, -5.0);
glRotatef (30.0, 0.0, 0.0, 1.0);
glPushMatrix;
//нарисовала все, что хотела
glPopMatrix;
glLoadIdentity;
glTranslatef (0.0, 0.0, -5.0);
glRotatef (-30.0, 0.0, 0.0, 1.0);
glPushMatrix;
//нарисовала все, что хотела 2
glPopMatrix;
И получилось вроде правильно.
Это варварство?
← →
Creative (2006-11-29 16:41) [33]Битый архив не пошел на пользу проекту. Теперь он в усмерть не компилится.
← →
Creative (2006-11-29 16:52) [34]Все, нормально открылось. Буду смотреть
← →
ancara © (2006-11-29 17:15) [35]
> glTranslatef (0.0, 0.0, -5.0);
> glRotatef (30.0, 0.0, 0.0, 1.0);
> glPushMatrix;
> //нарисовала все, что хотела
> glPopMatrix;
>
Нет, это в корне не правильно :)
Еще раз: glPushMatrix позволяет сохранить матрицу, путем помещения ее копии в стек, а glPopMatrix ее из стека достает и таким образом восстанавлявает матрицу.
А операции glTranslatef и glRotatef изменяют матрицу.
Поэтому этот код выглядит так:
- изменяем матрицу не сохранив ее: glTranslatef (0.0, 0.0, -5.0);
- еще раз изменяем: glRotatef (30.0, 0.0, 0.0, 1.0);
- сохраняем уже измененную матрицу: glPushMatrix; (зачем ее сохранять то?)
- рисуем, но не изменяем матрицу: //нарисовала все, что хотела
- восстанавливаем матрицу: glPopMatrix;
А хотелось бы вот так:
- прежде всего сохранить исходную матрицу: glPushMatrix;
- сделать необходимые преобразования: glTranslatef (0.0, 0.0, -5.0);
- сделать необходимые преобразования: glRotatef (30.0, 0.0, 0.0, 1.0);
- нарисовать все, что хочу...
- восстанавить матрицу: glPopMatrix;
← →
Creative (2006-11-29 17:38) [36]
> Нет, это в корне не правильно :)
> А хотелось бы вот так:
Да, ты совершенно прав. Таким образом нам совершенно не нужна становится LoadIdentity. Спасибо.
Кстати, у меня тут еще один глупый вопрос есть: если я пишу glRotatef (30.0, 1.0, 0.0, 1.0) - я ведь получу поворот на 30 градусов по обеим указанным осям, так? А если я хочу повернуть объект по нескольким осям на разные углы, мне что, дважды или трижды писать glRotatef ?
Кстати, пример твой скомпилился, я поставила твой код и мне удалось нарисовать кусочек сферы :-). Осталось поработать над мелочами, подобрать точные параметры.
Такой вопрос: а тебе удобно писать на VCL?
← →
ancara © (2006-11-29 18:10) [37]
> я ведь получу поворот на 30 градусов по обеим указанным
> осям, так?
нет, это будет поворот вокруг вектора (1.0, 0.0, 1.0) на 30 градусов. Причем OpenGL этот вектор еще и нормализует...
> А если я хочу повернуть объект по нескольким осям на разные
> углы, мне что, дважды или трижды писать glRotatef ?
Да, дважды или трижды :)
> Такой вопрос: а тебе удобно писать на VCL?
Да не жалуюсь :))
Вот тут еще один вариант main_u.pas, там кусок сферы окрашенный в желтый цвет и точечный источник света.
В процедуре рендеринга вот этими функциямиglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, @diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, @diffuse);
устанавливаются соответсвующие свойства материала объекта.
← →
ancara © (2006-11-29 18:18) [38]вот чорт, опять линк забыл запостить, вот он:
http://www.everfall.com/paste/id.php?sloc9gq8fbfp
P.S. как-то там на эверфоле каменты странно выглядят, или мне так кажется?
← →
Creative (2006-11-30 10:39) [39]Да, очень страно смотрятся. Вчера как-то лечила, сегодня не могу вспомнить как.
А что делает процедура SwapRGB?
← →
ancara © (2006-11-30 11:59) [40]Дело в том, что порядок хранения цветов в bmp-файле и RGB-текстуре различается : в bmp BGR, а в текстуре RGB, вот она и меняет местами крайние байты..
Страницы: 1 2 3 вся ветка
Форум: "Игры";
Текущий архив: 2008.01.13;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.009 c