
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.231.217.107] |
![]() |
|
Сообщ.
#1
,
|
|
|
Доброго времени суток!
Начал изучать OpenGL... Вопрос к приемеру есть сетка: ![]() ![]() void _DrawGrid(float cx, float cy, float step) { float _cx = cx / 2; float _cy = cy / 2; for(float x = -_cx; x <= _cx; x += step) { glBegin(GL_LINES); glVertex3f(x, _cy, 0.0); glVertex3f(x, -_cy, 0.0); glEnd(); } for(float y = -_cy; y <= _cy; y += step) { glBegin(GL_LINES); glVertex3f(_cx, y, 0.0); glVertex3f(-_cx, y, 0.0); glEnd(); } } Или что-то в этом роде центр сетки 0,0,0 далее рисуется куб: ![]() ![]() void _DrawCube(GLfloat size) { glBegin(GL_QUADS); // левая грань glVertex3f( -size / 2, -size / 2, -size / 2); glVertex3f( -size / 2, size / 2, -size / 2); glVertex3f( -size / 2, size / 2, size / 2); glVertex3f( -size / 2, -size / 2, size / 2); // правая грань glVertex3f( size / 2, -size / 2, -size / 2); glVertex3f( size / 2, -size / 2, size / 2); glVertex3f( size / 2, size / 2, size / 2); glVertex3f( size / 2, size / 2, -size / 2); // нижняя грань glVertex3f( -size / 2, -size / 2, -size / 2); glVertex3f( -size / 2, -size / 2, size / 2); glVertex3f( size / 2, -size / 2, size / 2); glVertex3f( size / 2, -size / 2, -size / 2); // верхняя грань glVertex3f( -size / 2, size / 2, -size / 2); glVertex3f( -size / 2, size / 2, size / 2); glVertex3f( size / 2, size / 2, size / 2); glVertex3f( size / 2, size / 2, -size / 2); // задняя грань glVertex3f( -size / 2, -size / 2, -size / 2); glVertex3f( size / 2, -size / 2, -size / 2); glVertex3f( size / 2, size / 2, -size / 2); glVertex3f( -size / 2, size / 2, -size / 2); // передняя грань glVertex3f( -size / 2, -size / 2, size / 2); glVertex3f( size / 2, -size / 2, size / 2); glVertex3f( size / 2, size / 2, size / 2); glVertex3f( -size / 2, size / 2, size / 2); glEnd(); } центр куба тоже 0,0,0 все это дело отрисовывается в методе: ![]() ![]() // .... glPushMatrix(); // далее позиция и поворот меняются мышью... glTranslated(0.0, 0.0, m_RenderParams.Position.z); glRotatef(m_RenderParams.Rotation.x, 1, 0, 0); glRotatef(m_RenderParams.Rotation.y, 0, 1, 0); glRotatef(m_RenderParams.Rotation.z, 0, 0, 1); _DrawGrid(50.0, 50.0, 0.0); _DrawCube(10.0); glPopMatrix(); glFlush(); // .... Собственно вопрос... выводится все правильно и сетка в центре и куб, но только при вращении сцены - куб сам по себе, секта - сама, короче говоря как выводить объекты (в данном случае куб) с привязкой к сетке т.е. если шаг сетки равен, к примеру, 10, то при отрисовке куба с гранью 20, в центре он должен занять ровно 4-ре ячейки и при вращении/маштабировании вершины куба должны быть привязаны к координатной сетке т.е. как в любом 3D редакторе (3DS Max) и т.д. |
![]() |
Сообщ.
#2
,
|
|
Не понял, в чем вопрос? Как сделать чтобы сетк вращалась отдельно? Если так, то сделай примерно так:
![]() ![]() glTranslated(0.0, 0.0, m_RenderParams.Position.z); glPushMatrix(); glRotatef(gridRotation.x, 1, 0, 0); glRotatef(gridRotation.y, 0, 1, 0); glRotatef(gridRotation.z, 0, 0, 1); _DrawGrid(50.0, 50.0, 0.0); glPopMatrix(); glPushMatrix(); glRotatef(cubeRotation.x, 1, 0, 0); glRotatef(cubeRotation.y, 0, 1, 0); glRotatef(cubeRotation.z, 0, 0, 1); _DrawCube(50.0); glPopMatrix(); |
Сообщ.
#3
,
|
|
|
To OpenGL, нет, наоборот так чтобы сетка и куб вращались вместе т.е. куб должен быть в координатах сетки (вершины куба), а сей час..., хотя сетка и куб рисуются с координатами центра 0,0,0 но при вращении куб ведет себя как бы отдельно...
На рисунке видно, что (1) вид сбоку - нормально, (2) вид сверху - нормально, но при вращении (3) - как будто он (куб) выше сетки (а он должен быть на половину выше (т.к. центры у них совпадают), на (4) - как будто он на краю сетки, хотя он должен быть в центре... Т.е. куб при вращении ползает по сетке, а должен быть в заданной позиции (в данном случае в центре).[attach=#0][/attach] |
![]() |
Сообщ.
#4
,
|
|
Картинку не увидел, но по описанию похоже что ты не включил depth test. Попробуй:
![]() ![]() //при инициализации glEnable(GL_DEPTH_TEST); //при рисовании glClear(GL_DEPTH_BUFFER_BIT); |
Сообщ.
#5
,
|
|
|
Во... даже .rar не прикрепляется (c .exe). Попробую объяснить на пальцах... короче говоря куб при вращении сцены как будто ползает по сетке, а должен быть как монолит, т.е. жестко привязан к координатам сетки...
Как это реализовать или где посмотреть исходник самого простого 3D редактора? Добавлено glEnable(GL_DEPTH_TEST) - есть такое дело... дело не в этом... такое впечатление, что куб должен маштабироваться отдельно... |
![]() |
Сообщ.
#6
,
|
|
M Может тогда весь код покажешь? Цитата Sergey Bogoyavlenskiy @ такое впечатление, что куб должен маштабироваться отдельно... При чем здесь масштабирование, мы же вроде о вращении говорили... Цитата Sergey Bogoyavlenskiy @ где посмотреть исходник самого простого 3D редактора? Дома был, вечером возможно выложу. |
Сообщ.
#7
,
|
|
|
Про Прикрепление файла... все равно не могу... не крепит и всё тут... ни .jpeg ни .rar файл выбирается, но как его крепить?
Если после выбора делать предпросмотр, то файла нет, если нажать на [attach] то в сообщении появляетя [attach=#0][/attach]... а файла нет. А так я бы и код выложил и .exe в .rar и картинки... на счет кода то он разбит по классам, но принцип такой при обработке перемещения мыши изменяются m_RenderParams.Position (три float x, y, z), а также аналогично m_RenderParams.Rotation (x, y, z) далее, до начала отрисовки: ![]() ![]() // .... glPushMatrix(); // далее позиция и поворот меняются мышью... glTranslated(0.0, 0.0, m_RenderParams.Position.z); // колесо мыши ближе/дальше glRotatef(m_RenderParams.Rotation.x, 1, 0, 0); glRotatef(m_RenderParams.Rotation.y, 0, 1, 0); glRotatef(m_RenderParams.Rotation.z, 0, 0, 1); _DrawGrid(50.0, 50.0, 5.0); _DrawCube(10.0); glPopMatrix(); glFlush(); // .... код отрисовки куба и сетки выше... рисуются они с центром в 0,0,0. Но я так думал, что glTranslated() и glRotatef() должны действовать на все одинаково, т.е. и на сетку и на куб, отрисовываются они действительно в центре, но при вращении сцены создается впечатление что куб "гуляет" сетке... т.е. они не выглядят как сцена в том же 3DS Max, вроде они вращаются, маштабируются но как бы это сказать... каждый по свойму... нет ощущения единой сцены... |
![]() |
Сообщ.
#8
,
|
|
Все-таки что-то мне подсказывает что дело в depth test
![]() |
Сообщ.
#9
,
|
|
|
поменял, но все один к одному... возможно если двигать камеру то все было бы в порядке, но многие пишут, что разницы между (изменением положения камеры относительно сцены и изменением положения сцены относительно камеры) принципиальной нет. Вот просто представьте себе куб на плоскости (в центре) когда мы смотрим сверху то все нормально, но мы начинаем вращать пусть даже по одной оси, к примеру, от себя (пока сетка(плоскость) не станет одной линией) куб как бы должен сдвигаться назад к центру сетки(плоскости), а он рисуется, хотя и тоже вращается вместе с сеткой, в центре экрана, а не в центре сетки... Извините, но лучше объяснить у меня не получается.
|
![]() |
Сообщ.
#10
,
|
|
То есть, куб всегда у тебя рисуется выше/впереди сетки? |
![]() |
Сообщ.
#11
,
|
|
Цитата Sergey Bogoyavlenskiy @ Про Прикрепление файла... все равно не могу... не крепит и всё тут... ни .jpeg ни .rar файл выбирается, но как его крепить? Если после выбора делать предпросмотр, то файла нет, если нажать на [attach] то в сообщении появляетя [attach=#0][/attach]... а файла нет. Тег attach выполняет несколько другую функцию, он позволяет указать, в каком месте поста его выводить, а так же позволяет задать свое пояснение Что бы прикрепить файл, его достаточно просто выбрать, и нажать "Отправить" |
Сообщ.
#12
,
|
|
|
Пробую прикрепить файл...
Прикреплённый файл ![]() Добавлено Прикрепил! ![]() |
![]() |
Сообщ.
#13
,
|
|
Может лучше исходники выложишь? Здесь у меня MSVCR80.dll не установлена
![]() |
Сообщ.
#14
,
|
|
|
Вот что-то в этом роде, за качество кода извините, но суть думаю будет понятна...
Прикреплённый файл ![]() Добавлено Ну, с этим ладно, в принципе работает да и ладно, но возник еще один вопрос, изначально выводится сетка, затем куб, когда оно серое то особо не заметно, но когда установил различные цвета (для сетки и для куба) то происходит мерцание сетки на кубе при вращении как с этим бороться или это уже зависит от видеокарты? |
![]() |
Сообщ.
#15
,
|
|
Мерцание сетки вызвано тем, что она идет точь-в-точь по грани и в тех местах из-за погрешностей получается больше то одна величина, то другая. А с первой проблемой не понял - у меня все рисуется как надо.
|
Сообщ.
#16
,
|
|
|
Проблема была не с OpenGL а с видеокартой, (на работе встроеная) дома - все OK. Но про мерцание сетки не понял... У меня это выглядит так, как будто куб - частично прозрачный т.е. в зависимости от поворота через него видно сетку или ее часть.
|
![]() |
Сообщ.
#17
,
|
|
Видна именно та часть сетки, которая должна быть внутри куба, или лежащая на его гранях? Если второе, то так и должно быть.
|
Сообщ.
#18
,
|
|
|
Вот картинка...
Прикреплённая картинка
![]() Добавлено Исходники те же, только разные цвета для сетки и куба. Добавлено Причем, это не только с кубом, даже если поверх сетки выводить плоскость ![]() ![]() void _DrawPlane(POINT3D pos, float cx, float cy) { glBegin(GL_POLYGON); glVertex3f(pos.x - cx / 2, pos.y + cy / 2, pos.z); glVertex3f(pos.x + cx / 2, pos.y + cy / 2, pos.z); glVertex3f(pos.x + cx / 2, pos.y - cy / 2, pos.z); glVertex3f(pos.x - cx / 2, pos.y - cy / 2, pos.z); glEnd(); } плоскость лежит сверху на приличной высоте над сеткой, но при вращении эффект тот же, части сетки (линии) мерцают при вращении т.е. отрисовываются поверх плоскости. |
![]() |
Сообщ.
#19
,
|
|
Скриншот выглядит довольно загадочно
![]() Сейчас на работе, смогу запустить код только дома. |
Сообщ.
#20
,
|
|
|
Пробавл на 3-х, правда, на всех Windows 7. Но скорее всего причина в другом...
|
Сообщ.
#21
,
|
|
|
Вот еще рисунок на 1-м красная плоскость намного выше зеленной, но ее часть закрашивается зеленым (мерцает при повороте).
На втором красная плоскость (квадрат) находится за зеленной! Но она также мерцает т.е. прокрашивается... при поворотах. Прикреплённая картинка
![]() Добавлено что то с depth test т.к. если вызвать glDisable(GL_DEPTH_TEST); между отрисовками плоскостей то мерцание исчезает, правда рисуется нормально только на первый взглад... до поворота на 180... |
![]() |
Сообщ.
#22
,
|
|
У тебя во многих местах вызывается hDC=GetDC(...); Скорей всего, проблема в этом - у меня сначала вылезали непонятные баги, но после удаления этих строк все стало нормально. На всякий случай прикладываю архив того, что у меня получилось.
Архив, только исходники ![]() |
Сообщ.
#23
,
|
|
|
Спасибо, но возник еще вопрос, задумал я отрисовать в левом нижнем углу вектора направления осей (X, Y, Z) вот (в одном из примеров "нарыл"):
![]() ![]() void CRender::DrawAxis(HWND hWnd) { RECT rcClient; ::GetClientRect(hWnd, &rcClient); float aspect = (float)(rcClient.right - rcClient.left) / (float)(rcClient.bottom - rcClient.top); int nSize = 50; SIZE szViewPort; if (aspect > 1) // width > height { szViewPort.cx = nSize * aspect; szViewPort.cy = nSize; } else { szViewPort.cx = nSize; szViewPort.cy = nSize / aspect; } glViewport(0, 0, szViewPort.cx, szViewPort.cy); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glLineWidth(1.0); //glOrtho(-1.0, 1.0, -1.0, 1.0, 0.5, 1); //---------------------------------------------- float fLength = 10.0; POINT3D pt(0.0, 0.0, 0.0); glBegin(GL_LINES); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x + fLength, pt.y, pt.z); glEnd(); glBegin(GL_LINES); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x, pt.y + fLength, pt.z); glEnd(); glBegin(GL_LINES); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x, pt.y, pt.z + fLength); glEnd(); //---------------------------------------------- glPopAttrib(); glViewport(0,0, rcClient.right, rcClient.bottom); } Вот пока так примитивно, но возник вопрос следующего плана, при установке нового glViewport() его размеры должны быть с таким же соотношением сторон, как и у окна, иначе они (вектора осей) рисуются неверно, но в таком случае этот новый вьюпорт постоянно ползает (меняет размеры) в соответствии с размерами окна и графика в нем (в данном случае это три отрезка) маштабируются. Вопрос возможно ли сделать эту зону статической и квадратной к примеру 50х50 у.е. и уже в ней рисовать вектора осей или... P.S. Этот метод можно запихнуть в исходники выше, только надо пердать HWND окна. |
![]() |
Сообщ.
#24
,
|
|
У меня не рисуются оси твоей функцией
![]() ![]() ![]() void CRender::DrawAxis(HWND hWnd) { RECT rcClient; ::GetClientRect(hWnd, &rcClient); int nSize = 50; SIZE szViewPort; szViewPort.cx = nSize; szViewPort.cy = nSize; glViewport(0, 0, szViewPort.cx, szViewPort.cy); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glLineWidth(1.0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1); //---------------------------------------------- float fLength = 1.0; POINT3D pt(0.0, 0.0, 0.0); glColor3f(0,0,1); glBegin(GL_LINES); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x + fLength, pt.y, pt.z); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x, pt.y + fLength, pt.z); glVertex3f(pt.x, pt.y, pt.z); glVertex3f(pt.x, pt.y, pt.z + fLength); glEnd(); //---------------------------------------------- glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopAttrib(); glViewport(0,0, rcClient.right, rcClient.bottom); } |
Сообщ.
#25
,
|
|
|
Вот спасибо! Ну и еще, последний вопрос, дальше буду сам разбираться...
Видел много реализаций 3d объектов (реализаций на C++), но все расчитаны под 3ds max и т.д. А мне бы для начало что-нибудь попроще (что бы вникнуть), как правильно хранить вершины, ребра, плоскости. Так что бы в дальнейшем можно было осуществять их выбор и редактирование, пусть хотя бы только редактирование вершин... Где такое можно подсмотреть? |
![]() |
Сообщ.
#26
,
|
|
Цитата Sergey Bogoyavlenskiy @ Видел много реализаций 3d объектов (реализаций на C++), но все расчитаны под 3ds max При чем здесь 3d max? Библиотеки содержат инструменты, необходимые для загрузки, отображения и пр. дествий с 3D объектами. Самое простое (и довольно универсальное решение) сделать так: объект - массив граней + информация о его повороте и положении, грань - массив вершин, вершина - координаты, цвет и нормаль. |
Сообщ.
#27
,
|
|
|
Вот, вот!!! Нет, 3ds max здесь действительно не к месту, согласен, это я так для примера, а вот за массив граней и т.д. спасибо! Буду копать в этом направлении.
|
Сообщ.
#28
,
|
|
|
Вот и еще вопрос... ковырялся, googlil, но... Кроче говоря объектную модель сделал, все рисуется, все замечательно вершины упоковал в вектор и т.д. т.е. могу ходить по вершинам, по граням, по объектам, но теперь возник вопрос о выборе вершины мышью... нашел такой код:
![]() ![]() class CVector3 { public: float x,y,z; }; void calc_select_line(int mouse_x, int mouse_y, CVector3& p1, CVector3& p2) { // mouse_x, mouse_y - оконные координаты курсора мыши. // p1, p2 - возвращаемые параметры - концы селектирующего отрезка, // лежащие соответственно на ближней и дальней плоскостях // отсечения. GLint viewport[4]; // параметры viewport-a. GLdouble projection[16]; // матрица проекции. GLdouble modelview[16]; // видовая матрица. GLdouble vx,vy,vz; // координаты курсора мыши в системе координат viewport-a. GLdouble wx,wy,wz; // возвращаемые мировые координаты. glGetIntegerv(GL_VIEWPORT,viewport); // узнаём параметры viewport-a. glGetDoublev(GL_PROJECTION_MATRIX,projection); // узнаём матрицу проекции. glGetDoublev(GL_MODELVIEW_MATRIX,modelview); // узнаём видовую матрицу. // переводим оконные координаты курсора в систему координат viewport-a. vx = mouse_x; vy = height - mouse_y - 1; // где height - текущая высота окна. // вычисляем ближний конец селектирующего отрезка. vz = -1; gluUnProject(vx, vy, vz, modelview, projection, viewport, &wx, &wy, &wz); p1 = CVector3(wx,wy,wz); // вычисляем дальний конец селектирующего отрезка. vz = 1; gluUnProject(vx, vy, vz, modelview, projection, viewport, &wx, &wy, &wz); p2 = CVector3(wx,wy,wz); } Но решил проверить что же все таки получиться... и начал его отрисовывать (полученный отрезок)... или я чего-то не понимаю... или луч рисуется от края экрана в центр сцены, т.к. при любом положении курсора p1 - по всем координатам около нуля, да и орезок как то не связан с координатами курсора (x, y). Так вот собственно и вопрос как правильно выбирать (тест поподания) при данной реализации кода (см. выше)? |
![]() |
Сообщ.
#29
,
|
|
Третий параметр gluUnProject - значение z - буфера (ну или глубина сцены). И она должна идти от 0 до 1. Вообще, ИМХО, для выбора лучше использовать gluProject - вычисляешь оконные координаты каждой вершины и смотришь расстояние до координат мыши.
|
Сообщ.
#30
,
|
|
|
Так, хорошо вот набросал такую функцию:
![]() ![]() void _Transform(POINT3D ptObject, POINT3D& ptScreen) { int viewport[4]; // параметры viewport-a. GLdouble projection[16]; // матрица проекции. GLdouble modelview[16]; // видовая матрица. GLdouble vx, vy, vz; // координаты курсора мыши в системе координат viewport-a. GLdouble wx, wy, wz; // возвращаемые мировые координаты. glGetIntegerv(GL_VIEWPORT, viewport); // узнаём параметры viewport-a. glGetDoublev(GL_PROJECTION_MATRIX, projection); // узнаём матрицу проекции. glGetDoublev(GL_MODELVIEW_MATRIX, modelview); // узнаём видовую матрицу. gluProject(ptObject.x, ptObject.y, ptObject.z, modelview, projection, viewport, &ptScreen.x, &ptScreen.y, &ptScreen.z); } Есть объект (куб) который рисуется в центре сцены (основание = 0) с гранью = 10, если координаты вершины -5, -5, 10 то данный метод возвращает 839, 676 (размер окна 940х656), естественно вершина находится в другом месте, причем вроде как работает... координаты вершин - это получается чередование значений -5(5), -5(5), 10(0) так и на выходе череда значений 839(100), 676(-63) но как применить результат я пока не знаю. Так как когда мышь над вершинами (смотрим сбоку) то координаты 389,304 - 389,141(левая грань) и 551,304 - 551,141 (правая грань). Это раз. +Если развернуть сцену, то координаты возвращаются такие же. Короче говоря где можно посмотреть рабочий пример выбора вершин, или хотя бы подробные действия что и как делать, что бы мне разобраться раз и навсегда, да и возможно другим будет интересно. |
![]() |
Сообщ.
#31
,
|
|
Этот код должен работать правильно. А где ты вызываешь эту функцию? Если не внутри RenderScene и код не менял, то причина возможно в том, что transform у тебя вызывается после или до renderScene, в которой у тебя задается матрица вида, и в конце которой она возвращается назад (glPopMatrix). А насчет примера - на том же gamedev (где ты по-видимому и брал код
![]() |
Сообщ.
#32
,
|
|
|
То OpenGL так спасибо, огромное, буду разбираться, тут возникла еще задача, никоим образом не связанная с координатами, но решил новую тему не создавать, задача выводить в OpenGL шрифт, примеров достаточно, но все они рисуются либо контурами, либо полигонами, а надо один простой чертежный шрифт, т.е. к примеру буква A или О
это не набор 2-х контуров, а один, т.е. буква А должна выводится всего 3-мя линиями, буква О к примеру 8-ю (со скошенными углами) и т.д. ищу, но пока ничего не найду. Конечно можно высчитывать координаты в ручную, но это - время, а есть ли что нибудь готовое? |
![]() |
Сообщ.
#33
,
|
|
Таких примеров не видел. Могу посоветовать только попробовать подыскать подходящий шрифт.
|
Сообщ.
#34
,
|
|
|
Понял, спасибо, чувствую долго придется сидеть с миллиметровкой
![]() |
![]() |
Сообщ.
#35
,
|
|
Проще перед каждым рисованием "обнулять" матрицу вызовом glLoadIdentity, вместо Push/PopMatrix. Тогда после рисования все преобразования будут сохраняться.
|
Сообщ.
#36
,
|
|
|
День (вечер) добрый!
Возник еще вопрос, если необходимо выбрать вершину… допустим есть куб, прошли по его вершинам, проверили тест попадания – вершин которые прошли тест окажется 3 штуки принадлежащие разным граням… тогда получается, что при редактировании вершины куба необходимо передвинуть 3 vertex – а? Тогда, при редактировании вершины объекта любой сложности необходимо проходиться по всем граням, по всем vertex-ам и выбирать для редактирования прошедшие тест? И еще… Если перед каждым рисованием "обнулять" матрицу вызовом glLoadIdentity то тогда оси (векторы осей рисуются неправильно)… как сделать так чтобы и вершины можно было выбирать и оси рисовались правильно? А то получается что если делать Push/PopMatrix то оси рисутся правильно, но неправильно работает gluProject(), елси делать glLoadIdentity то gluProject() – работает, а оси не рисуются, вернее рисуются но неправильно… |
![]() |
Сообщ.
#37
,
|
|
По первому вопросу - ты не сможешь повернуть куб так, чтобы ты смог выбрать три точки
![]() |
Сообщ.
#38
,
|
|
|
To OpenGL:
Нет, Вы меня неправильно поняли, я имел виду, что точек с одинаковыми координатами образуется несколько. Т.е. если я правильно понял, предложенную Вами объектную модель то Объект это совокупность граней, грани - совокупность точек (вершин грани, но не куба). Тогда, допустим, куб, состоит из 4-х граней каждая из которых содержит по 4-е точки, следовательно в вершине куба сходятся 3 грани (которые видимы), но точек будет 3-и (для каждой грани образующих вершину, и которые будут иметь абсолютно одинаковые координаты). Так вот, пользователь хочет отредактировать одну вершину (вершину куба) -> проходим по всем граням -> у каждой грани проходим по ее точкам -> делаем тест попадания (можно с каким-либо небольшим отклонением) так вот точек которые пройдут тест окажется в результате 3-и, повторюсь, они будут принадлежать разным граням, т.е. эти 3-и точки будут находится в вершине куба… Или аналогично… Пользователь хочет изменить размер куба путем выбора грани (т.е. оттащить выбранную грань что бы получился параллелепипед) он тащит одну грань, но если я правильно все понял, то менять координаты надо не только тем 4-м точкам которые образуют грань, но и еще надо изменить размеры соседних 4-х граней т.е. по мимо 4-х точек передвигаемой грани нужно еще изменить позицию 8-ми точек принадлежащих соседним? Или это можно реализовать как-то по-другому? |
![]() |
Сообщ.
#39
,
|
|
Разумеется, лучше хранить не сами вершины, а ссылки на них - зачем дублировать лишние данные?
|
Сообщ.
#40
,
|
|
|
Не совсем понял с ссылками я пока реализовал так: Объект это вектор граней, грань это вектор точек т.е. вершин грани, в класс объект добавил метод вставки грани, а в класс грани метод вставки точки (x, y, z) т.е. вершины грани, но не объекта. Так у кого (какого класса) должны быть ссылки? Пока у меня получается действительно так, что точки при создании объекта (того же куба) дублируются…
Код примерно такой (пока так примитивно): ![]() ![]() CParallelepiped::CParallelepiped(POINT3D pos, float cx, float cy, float cz) { //.... float cx2 = cx/2; float cy2 = cy/2; float cz2 = cz/2; // создание вершин (точек) CVertex v0(pos.x - cx2, pos.y + cy2, pos.z + cz2); CVertex v1(pos.x - cx2, pos.y + cy2, pos.z - cz2); CVertex v2(pos.x - cx2, pos.y - cy2, pos.z - cz2); CVertex v3(pos.x - cx2, pos.y - cy2, pos.z + cz2); CVertex v4(pos.x + cx2, pos.y + cy2, pos.z + cz2); CVertex v5(pos.x + cx2, pos.y - cy2, pos.z + cz2); CVertex v6(pos.x + cx2, pos.y - cy2, pos.z - cz2); CVertex v7(pos.x + cx2, pos.y + cy2, pos.z - cz2); CVertex v8(pos.x - cx2, pos.y + cy2, pos.z + cz2); CVertex v9(pos.x + cx2, pos.y + cy2, pos.z + cz2); CVertex v10(pos.x + cx2, pos.y + cy2, pos.z - cz2); CVertex v11(pos.x - cx2, pos.y + cy2, pos.z - cz2); CVertex v12(pos.x - cx2, pos.y - cy2, pos.z + cz2); CVertex v13(pos.x - cx2, pos.y - cy2, pos.z - cz2); CVertex v14(pos.x + cx2, pos.y - cy2, pos.z - cz2); CVertex v15(pos.x + cx2, pos.y - cy2, pos.z + cz2); CVertex v16(pos.x - cx2, pos.y + cy2, pos.z + cz2); CVertex v17(pos.x - cx2, pos.y - cy2, pos.z + cz2); CVertex v18(pos.x + cx2, pos.y - cy2, pos.z + cz2); CVertex v19(pos.x + cx2, pos.y + cy2, pos.z + cz2); CVertex v20(pos.x - cx2, pos.y + cy2, pos.z - cz2); CVertex v21(pos.x + cx2, pos.y + cy2, pos.z - cz2); CVertex v22(pos.x + cx2, pos.y - cy2, pos.z - cz2); CVertex v23(pos.x - cx2, pos.y - cy2, pos.z - cz2); CFace f0, f1, f2, f3, f4, f5; // грани // вставляем вершины (3D точки) в грани (они живут в векторе грани) std::vector<CVertex> f0.InsertVertex(v0); f0.InsertVertex(v1); f0.InsertVertex(v2); f0.InsertVertex(v3); f1.InsertVertex(v4); f1.InsertVertex(v5); f1.InsertVertex(v6); f1.InsertVertex(v7); f2.InsertVertex(v8); f2.InsertVertex(v9); f2.InsertVertex(v10); f2.InsertVertex(v11); f3.InsertVertex(v12); f3.InsertVertex(v13); f3.InsertVertex(v14); f3.InsertVertex(v15); f4.InsertVertex(v16); f4.InsertVertex(v17); f4.InsertVertex(v18); f4.InsertVertex(v19); f5.InsertVertex(v20); f5.InsertVertex(v21); f5.InsertVertex(v22); f5.InsertVertex(v23); // вставляем грани в объект (они живут в векторе объекта) std::vector<CFace> InsertFace(f0); InsertFace(f1); InsertFace(f2); InsertFace(f3); InsertFace(f4); InsertFace(f5); //.... } |
![]() |
Сообщ.
#41
,
|
|
Пусть у тебя есть несколько точек. Тогда одна грань будет, например, из 1, 2, 3 точки, вторая - 1,3,4 и т.д.
|
Сообщ.
#42
,
|
|
|
Все дальше и дальше… Вот с проекцией вроде как разобрался все крутится, вертится, масштабируется. Но возник вопрос такого плана необходимо масштабировать при виде сверху в glOrtho()… Вот и приехали данный способ уже не работает…
Сделал что-то типа этого: ![]() ![]() //… glMatrixMode(GL_PROJECTION); glLoadIdentity(); float fSideAspect = abs(m_ViewParams.Position.z); // m_ViewParams.Position.z - изменяется при движении колеса мыши (масштаб) POINT ptVieport; // m_szView - размеры окна int nMinSide = min(m_szView.cx, m_szView.cy); int nMaxSide = max(m_szView.cx, m_szView.cy); if(m_szView.cy > m_szView.cx) { ptVieport.x = 0; ptVieport.y = m_szView.cy / 2 - m_szView.cx / 2; } else { ptVieport.x = m_szView.cx / 2 - m_szView.cy / 2; ptVieport.y = 0; } glViewport(ptVieport.x, ptVieport.y, nMinSide, nMinSide); float cx2 = fSideAspect / 2; float cy2 = fSideAspect / 2; glOrtho( -cx2, cx2, -cy2, cy2, - 1000, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //… Но получается что Vieport всегда квадратный со стороной равной меньшему размеру окна, и когда окно больше по Height то в центре окна отрисовка проходит в небольшом квадрате со стороной Width и наоборот, а возможно ли как-то масштабировать при режиме glOrtho() без изменения размеров Vieport – а (Вращать не надо т.к. используется только вид сверху или сбоку)? И как это сделать чтобы в режиме glOrtho сцена заполняла все окно, да же если оно ну очень непропорциональное? |
![]() |
Сообщ.
#43
,
|
|
Просто задавай размеры паралелепипеда в параметрах glOrtho пропорциональными размеру окна:
glOrtho( -m_szView.cx*fSideAspect, m_szView.cx*fSideAspect, -m_szView.cy*fSideAspect, m_szView.cy*fSideAspect, - 1000, 1000) Ну и еще нужно не забыть про glViewport(0,0,_szView.cx,_szView.cy) |
Сообщ.
#44
,
|
|
|
За glOrtho() - спасибо!
Вот еще возник вопрос… про буфер выбора на многих сайтах есть функция для работы с ним откуда и позаимствовал код… Делаю так: ![]() ![]() void CObjectContainer::Draw() { glInitNames(); // уничтожаем все OpenGL имена (ID) glPushName(0); // вставляем «нулевой» объект _it _First = m_Objs.begin(); _it _Last = m_Objs.end(); for(; _First != _Last; ++_First) { glLoadName((*_First)->GetID()); // устанавливаем имя (рисуется только один объект с ID = 101 (*_First)->Draw(); // выводим } } при нажатии кнопки мышки: ![]() ![]() DWORD CObjectSelector::FindObject(int x, int y) { int objectsFound = 0; // Общее количество кликнутых обьектов int viewportCoords[4] = {0}; // Массив для хранения экранных координат // Переменная для хранения ID обьектов, на которые мы кликнули. // Мы делаем массив в 32 элемента, т.к. OpenGL также сохраняет другую // информацию, которая нам сейчас не нужна. Для каждого обьекта нужно // 4 слота. unsigned int selectBuffer[32] = {0}; // glSelectBuffer регистрирует массив как буфер выбора обьектов. Первый параметр - размер // массива. Второй - сам массив для хранения информации. glSelectBuffer(32, selectBuffer); // Регистрируем буфер для хранения выбранных обьектов // Эта функция возвращает информацию о многих вещах в OpenGL. Мы передаём GL_VIEWPOR, // чтобы получить координаты экрана. Функция сохранит их в переданном вторым параметром массиве // в виде top,left,bottom,right. glGetIntegerv(GL_VIEWPORT, viewportCoords); // Получаем текущие координаты экрана // Теперь выходим из матрицы GL_MODELVIEW и переходим в матрицу GL_PROJECTION. // Это даёт возможность использовать X и Y координаты вместо 3D. glMatrixMode(GL_PROJECTION); // Переходим в матрицу проекции glPushMatrix(); // Переходим в новые экранные координаты // Эта функция делает так, что фреймбуфер не изменяется при рендере в него, вместо этого // происходит запись имён (ID) примитивов, которые были бы отрисованы при режиме // GL_RENDER. Информация помещается в selectBuffer. glRenderMode(GL_SELECT); // Позволяет рендерить обьекты без изменения фреймбуфера glLoadIdentity(); // Сбросим матрицу проекции // gluPickMatrix позволяет создавать матрицу проекции около нашего курсора. Проще говоря, // рендерится только область, которую мы укажем (вокруг курсора). Если обьект рендерится // в этой области, его ID сохраняется (Вот он, смысл всей функции). // Первые 2 параметра - X и Y координаты начала, следующие 2 - ширина и высота области // отрисовки. Последний параметр - экранные координаты. Заметьте, мы вычитаем 'y' из // НИЖНЕЙ экранной координаты. Мы сделали это, чтобы перевернуть Y координаты. // В 3д-пространстве нулевые y-координаты начинаются внизу, а в экранных координатах // 0 по y находится вверху. Также передаём регион 2 на 2 пиксела для поиска в нём обьекта. // Это может быть изменено как вам удобнее. gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords); // Далее просто вызываем нашу нормальную функцию gluPerspective, точно так же, как // делали при инициализации. m_pViewManager->RecoveryView(); glMatrixMode(GL_MODELVIEW); // Возвращаемся в матрицу GL_MODELVIEW m_pViewManager->Update(); //RenderScene(); // Если мы вернёмся в нормальный режим рендеринга из режима выбора, glRenderMode // возвратит число обьектов, найденных в указанном регионе (в gluPickMatrix()). objectsFound = glRenderMode(GL_RENDER); // Вернемся в режим отрисовки и получим число обьектов glMatrixMode(GL_PROJECTION); // Вернемся в привычную матрицу проекции glPopMatrix(); // Выходим из матрицы glMatrixMode(GL_MODELVIEW); // Вернемся в матрицу GL_MODELVIEW // УФФ! Это было немного сложно. Теперь нам нужно выяснить ID выбранных обьектов. // Если они есть - objectsFound должно быть как минимум 1. if (objectsFound > 0) { // Если мы нашли более 1 обьекта, нужно проверить значения глубины всех // выбоанных обьектов. Обьект с МЕНЬШИМ значением глубины - ближайший // к нам обьект, значит и щелкнули мы на него. В зависимости от того, что // мы программируем, нам могут понадобится и ВСЕ выбранные обьекты (если // некоторые были за ближайшим), но в этом уроке мы позаботимся только о // переднем обьекте. Итак, как нам получить значение глубины? Оно сохранено // в буфере выбора (selectionBuffer). Для каждого обьекта в нем 4 значения. // Первое - "число имен в массиве имен на момент события, далее минимум и // максимум значений глубины для всех вершин, которые были выбраны при прошлом // событии, далее по содержимое массива имен, нижнее имя - первое; // ("the number of names in the name stack at the time of the event, followed // by the minimum and maximum depth values of all vertices that hit since the // previous event, then followed by the name stack contents, bottom name first.") - MSDN. // Единстве, что нам нужно - минимальное значение глубины (второе значение) и // ID обьекта, переданного в glLoadName() (четвертое значение). // Итак, [0-3] - данные первого обьекта, [4-7] - второго, и т.д... // Будте осторожны, так как если вы отображаете на экране 2Д текст, он будет // всегда находится как ближайший обьект. Так что убедитесь, что отключили вывод // текста при рендеринге в режиме GL_SELECT. Я для этого использую флаг, передаваемый // в RenderScene(). Итак, получим обьект с минимальной глубиной! // При старте установим ближайшую глубину как глубину первого обьекта. // 1 - это минимальное Z-значение первого обьекта. unsigned int lowestDepth = selectBuffer[1]; // Установим выбранный обьект как первый при старте. // 3 - ID первого обьекта, переданный в glLoadName(). int selectedObject = selectBuffer[3]; // Проходим через все найденные обьекты, начиная со второго (значения первого // мы присвоили изначально). for(int i = 1; i < objectsFound; i++) { // Проверяем, не ниже ли значение глубины текущего обьекта, чем предидущего. // Заметьте, мы умножаем i на 4 (4 значения на каждый обьект) и прибавляем 1 для глубины. if(selectBuffer[(i * 4) + 1] < lowestDepth) { // Установим новое низшее значение lowestDepth = selectBuffer[(i * 4) + 1]; // Установим текущий ID обьекта selectedObject = selectBuffer[(i * 4) + 3]; } } // Вернем выбранный обьект return selectedObject; } // Если не щелкнули ни на 1 обьект, вернём 0 return 0; } |
Сообщ.
#45
,
|
|
|
Короче говоря код передернут
![]() Все вроде как работает, но везде написанно, что: Первое поле - количество объектов под курсором на момент нажатия. Второе поле - минимальная Z глубина объекта (экранная Z координата). Третье поле - максимальная Z глубина объекта (экранная Z координата). Четвертое поле - идентификатор объекта. Поэтому размер буфера задается так: (4 * КоличествоОбъектов). Хорошо… Но почему я получаю такие результаты как на картинке? [0] = 0 [1] = 4286679300 [2] = 4286928132 [3] = 1 [4] = 101238216 [5] = 4286845700 [6] = 101 // вот ID! [7] = 0 [8]…[31] = 0 И соответственно приведенные в примерах функции дают неправильный результат т.е. они возвращают [7] = 0. Если считать с [3] = 1 // Первое поле - количество объектов под курсором на момент нажатия. [4] = 101238216 // Второе поле - минимальная Z глубина объекта (экранная Z координата). [5] = 4286845700 // Третье поле - максимальная Z глубина объекта (экранная Z координата). [6] = 101 // Четвертое поле - идентификатор объекта То все правильно, но опять же что то уже не так… откуда берутся значения [0]…[2]? Или это происходит при glPushName(0); ? Прикреплённая картинка
![]() |
![]() |
Сообщ.
#46
,
|
|
Цитата Sergey Bogoyavlenskiy @ Все вроде как работает, но везде написанно, что: Первое поле - количество объектов под курсором на момент нажатия. Второе поле - минимальная Z глубина объекта (экранная Z координата). Третье поле - максимальная Z глубина объекта (экранная Z координата). Четвертое поле - идентификатор объекта. Не совсем так. Цитата www.opengl.org The hit record consists of the number of names in the name stack at the time of the event, followed by the minimum and maximum depth values of all vertices that hit since the previous event, followed by the name stack contents, bottom name first. То есть первое значение содержит количество имен в стеке на момент регистрации попадания, дальше z-depth а затем сам стек. Получается, в приведенном тобой примере все верно - сначала идет инфо о том, что 0 имен, затем z, а затем стек в количестве 0 записей ![]() |
Сообщ.
#47
,
|
|
|
Ну вот хоть убейте…
Не могу догнать… ![]() Всякий раз при нажатии левой кнопки мышки вызывается этот метод (FindObject(int x, int y)) который в свою очередь вызывает отрисовку сцены в буфер: ![]() ![]() void CObjectContainer::Draw() { glInitNames(); // уничтожаем все OpenGL имена (ID) glPushName(0); _it _First = m_Objs.begin(); _it _Last = m_Objs.end(); for(; _First != _Last; ++_First) { glLoadName((*_First)->GetID()); (*_First)->Draw(); } } И в котром производится очистка имен. И добавляется сначала нулевой, затем с именем 101 (в моем примере). Тогда как понять <количество имен в стеке на момент регистрации попадания>? Т.е. это первое значение = 0… т.е. если понимать дословно то количество имен в стеке = 0… ну не понимаю я… Это первый вопрос, а второй – не зависимо от того куда я щелкаю мышкой (или в мой куб с именем 101 или в пустоту) значения в этом стеке одни и те же кроме значений глубин. Зачем тогда устанавливать: gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords); Если щелкая в разные места сцены получаем 2 объекта? ![]() ![]() //... if (objectsFound > 0) // objectsFound Всегда равно 2! { //... } Т.е. даже если объект не попал в это окошко (нажали в произвольном месте, а не на куб с именем 101) то в буфере он все же присутствует! (значения [3]-[6]) меняются лишь его значения в плях [4][5]. Тогда в моем случае надо пропускать первые ([0][1][2]) значения? И работать со стальными? И именно по значению глубины делать выбор (находить имя объекта) тогда я не понимаю с чем сравнивать? Если у меня один объект с именем 101 с чем сравнивать его значения глубины? Или всетаки их сравнивать со значениями [1][2]? Если значения ([0][1][2]) пропускать (как информацию о предидущем попадании) тогда вообще – засада, куда ни щелкать – принимаеся решение, что щелкнули по кубу! Но ведь это не так! Если у других все работает – значит где-то ошибаюсь я, или просто не догоняю как работать с этим буфером… ![]() И еще такой вопрос, как правильнее производить выбор тех же самых вершин: Вариант 1: Переводить координаты мыши, а дальше проход по всем вершинам объектов и сравнивать их и принимать решение о выбранной, короче говоря – считать все математикой. Вариант 2: Вершинам каждого объекта присваивать имена (glLoadName())и производить выбор при помощи OpenGL – буфера выбора. (Но тогда, наверное, прийдется в каждой вершине рисовоть OpenGL точку.) Короче говоря, поставил перед собой задачу: необходимо реализовать выбор объетов, выбор грани объета, выбор ребер объекта, выбор вершин объекта. И хотелось бы какого то универсального способа применимого ко всему. Возможно ли такое? Или выбор объектов осуществлять, к примеру, буфером выбора, а вершины – по первому варианту (математикой)? |
![]() |
Сообщ.
#48
,
|
|
Цитата Sergey Bogoyavlenskiy @ т.е. если понимать дословно то количество имен в стеке = 0 Именно так. Можешь кстати трассировать по шагам само рисование, наблюдая при этом за буфером, чтобы узнать, когда в него записываются эти данные. Цитата Sergey Bogoyavlenskiy @ Тогда в моем случае надо пропускать первые ([0][1][2]) значения? Зачем? Я ведь сказал что они означают. Поэтому пока не кончились записи берешь количество объектов, пропускаешь z, идешь по объектам. Просто и универсально. Цитата Sergey Bogoyavlenskiy @ Если значения ([0][1][2]) пропускать (как информацию о предидущем попадании) тогда вообще – засада, куда ни щелкать – принимаеся решение, что щелкнули по кубу! Странно. В части кода из твоего прошлого сообщения вроде все верно, должно работать. Цитата Sergey Bogoyavlenskiy @ И еще такой вопрос, как правильнее производить выбор тех же самых вершин: Если нужен выбор вершин, то первый способ, т.к. количество имен ограничено. |