-
Занялся освоением OpenGL. Встретился с некоторыми трудностями красивых решений которых я не вижу. Подскажите как их обычно решают?
1. Разбиение невыпуклого полигона на треугольники. Можно ли это сделать автоматически? Полигон задан координатами вершин, лежит целиком в одной плоскости. Для примера можно взять букву "Ш". Как разбить ручками я понимаю но очень хотелось бы разбивать автоматически. К алгоритму особых скоросных требований нет. Полгоны несложные поряка 10-16 вершин.
2. Вращение объекта мышкой. Есть объект например куб изначально ориентированный по осям. На экране он так и выглядит. Двигаем по экрану мышь и преобразовываем это движение в поворот по двум осям. Теперь куб повёрнут на некоторые углы и соответственно так отрисован. Теперь нужно преобразовать следующее движение мыши в углы поворота. Вот тут и возникает сложность.
так как в идеале дожно быть так:
glRotate(Углы для 2-го поворота) glRotate(Углы для 1-го поворота) рисуем куб.
Т.е. в матричном виде: Rn*...*(R2*(R1*x))
Соответственно чтобы правильно осуществлять поворот нужно у себя в программе вычислять Rn*...(R3*(R2*R1))
Есть ли другой способ осуществить задуманное? Можно ли вычитать матрицу из OpenGL? Загружать можно, домножать на мою можно а обратно извлеч можно?
-
По первому вопросу могу предложить свой способ с использованием текстуры. Как грузить текстуры, как их потом использовать - это все из другой басни. Я предлагаю лишь несложный алгоритм, отвечающий твоим требованиям с соблюдением определенной степени точности (если размер грани будет не меньше 2х пикселей относительно размера текстуры). Для построения используется любой замкнутый набор из точек в области единичного прямоугольника: допустимы самопересечения и т.п. Вобщем, если будет желание, алгоритм можно выдрать без проблем. :)
Type //точка в 2д пространстве TPos2f = record //соответствующие координаты X : GLFloat; Y : GLFloat; end;
//массив из точек TPos2fArray = Array[0 .. 0] of TPos2f;
Var pPoints : PPos2fArray;
function CoordToAngle(Const X, Y : Single) : Single; begin If (X = 0.0) then begin If (Y >= 0.0) then Result := HalfPi else Result := - HalfPi; Exit; end; Result :=ArcTan2(Y, X); end;
procedure FindFreePoint(Const X1, Y1, X2, Y2, X3, Y3, fStep : Single; Var X, Y : Single); Var A1, A2, A, AK : Single; Sn, Cs : Extended; begin A1 :=CoordToAngle(X1 - X2, Y1 - Y2); A2 :=CoordToAngle(X3 - X2, Y3 - Y2); A :=(A2 + A1) / 2.0; If(A2 - A1 > Pi) or (A1 - A2 > Pi) then A := A + Pi; AK :=Abs(A2 - A1); AK :=Min(AK, Abs(TwoPi - AK)); AK :=Max(AK, 0.01); AK :=Min(fStep / Sin(AK), (Hypot(X1 - X2, Y1 - Y2) + Hypot(X3 - X2, Y3 - Y2))); SinCos(A, Sn, Cs); X := X2 + Cs * AK; Y := Y2 + Sn * AK; end;
function Inhalt(Const AX1, AY1, AX2, AY2, BX1, BY1, BX2, BY2 : Single; Const bFl : Boolean) : Boolean;
function GetK(Const X, Y : Single) : Single; begin If (X = 0.0) then Result:=1.0e+4 else Result:=Y / X; end;
Var X, Y : Single;
function Insect(Const X1, X2, Y1, Y2 : Single) : Boolean; begin Result :=((X >= X1) and (X <= X2)) or ((X <= X1) and (X >= X2)) and ((Y >= Y1) and (Y <= Y2)) or ((Y <= Y1) and (Y >= Y2)); end;
Var AK, BK : Single; begin AK :=GetK(AX2 - AX1, AY2 - AY1); BK :=GetK(BX2 - BX1, BY2 - BY1); X :=GetK(AK - BK, BY1 - AY1); If(AY1 > AY2) then Y :=AY2 + BK * X else Y :=AY1 + AK * X; Result :=(Insect(AX1, AX2, AY1, AY2)) and (Insect(BX1, BX2, BY1, BY2)); end;
function TMainForm.Reinspect(Const X1, Y1, X2, Y2 : Single; Const Index : Integer; Const bFl : Boolean) : Boolean; Var I : Integer; begin Result :=True; For I:=0 to FCount - 2 do If (I <> Index)and (Inhalt(X1, Y1, X2, Y2, pPoints^[I].X, pPoints^[I].Y, pPoints^[I + 1].X, pPoints^[I + 1].Y, bFl)) then Exit; Result:=False; end;
procedure TMainForm.BuildTex; Const nSize = 512; AlphaOptions : TAlphaOptions = ( Enabled : True; R : 0.56; G : 0.33; B : 0.11; AMulti : -5.0; TexVisible : $20 ); Var I : Integer; Bitmap : TExBitmap; nC : Integer; bX, bY : Single; begin If(Not FFilled) then Exit; Bitmap:=TExBitmap.Create; Try With Bitmap do begin Width :=nSize; Height :=nSize; Canvas.Brush.Color :=clBlack; Canvas.Rectangle(0, 0, nSize, nSize); Canvas.Pen.Width :=1; Canvas.Pen.Color :=clWhite; //рисуем линии nC :=nSize div 2; For I:=0 to FCount - 2 do begin Canvas.MoveTo(Round(nC * (1.0 + pPoints^[I].X)), Round(nC * (1.0 - pPoints^[I].Y))); Canvas.LineTo(Round(nC * (1.0 + pPoints^[I + 1].X)), Round(nC * (1.0 - pPoints^[I + 1].Y))); end; Canvas.Brush.Color :=clWhite; For I:=0 to FCount - 3 do If(I = 0) or (Reinspect(pPoints^[I].X, pPoints^[I].Y, pPoints^[I + 1].X, pPoints^[I + 1].Y, I, False))then begin FindFreePoint(pPoints^[I].X, pPoints^[I].Y, pPoints^[I + 1].X, pPoints^[I + 1].Y, pPoints^[I + 2].X, pPoints^[I + 2].Y, 2.0 / nC, bX, bY); Canvas.FloodFill(Round(nC * (1.0 + bX)), Round(nC * (1.0 - bY)), clWhite, fsBorder); end; // bitmap.SaveToFile('Tmp.bmp'); If(Tex <> Nil) then RTex.Delete(Tex); Tex := RTex.CreateTexture(Bitmap, False, @AlphaOptions); end;//With Bitmap Finally Bitmap.Free; end; end;
-
Есть же вроде стандартные средства тесселяции, gluTess<...>
-
>Есть же вроде стандартные средства тесселяции, gluTess<...>
Есть но я их не заметил. Спасибо то что доктор прописал.
Вопрос 2 остаётся открытым. и ещё добавляется новый:
3. При триангуляции полигона в местах соприкосновения граней треугольников получаются небольшие просветы. Что то похожее на прозрачную паутинку. Как от этого можно избавиться?
-
> [2] Sapersky (04.06.07 15:00) > Есть же вроде стандартные средства тесселяции, gluTess<...>
Ну, это же скучно. :) Зачем искать легкие пути ?..
-
>Ну, это же скучно. :) Зачем искать легкие пути ?..
Как раз и открыл тему по поиску лёгких путей. По другим вопросам есть что сказать?
-
Про (3) нечего сказать, извини уж, что так вышло. ;)
получит матрицы: With PMatrixes^ do begin glGetFloatv(GL_Projection_Matrix, @Proj); glGetFloatv(GL_ModelView_Matrix, @Model); glGetFloatv(GL_Texture_Matrix, @Tex); end;//With);
установить матрицы: 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);
Type TGLMatrix = Array [0 .. 3, 0 .. 3] of GLFloat; TGLMatrixes = record Model : TGLMatrix; Proj : TGLMatrix; Tex : TGLMatrix; end; PGLMatrixes = ^ TGLMatrixes;
Только это немного неверное решение. Задай сналача единичный вектор (1, 0, 0). Получаешь первые два угла по каким то осям - поверни его с помощью формул поворота на эти углы. Еще углы - еще поворот. Таким образом этот вектор у тебя будет "образцом" поворота. Перед отрисовкой получай из вектора всего 2 угла поворота по осям и делай только 2 вызова glRotate. Эта два угла можно получить с помощью одного преобразования, обратного повороту. Матрицы... вот тут то как раз ты зря пытаешься усложнить себе жизнь.
Поворот делать просто: procedure chCoords(Const X, Y, Cs, Sn : GLFloat; Var OutX, OutY : GLFloat); begin OutX:=X * Cs - Y * Sn; OutY:=Y * Cs + X * Sn; end;
-
Никогда не выводил полигоны, а зачем, если треугольники намного удобней
-
> [7] Yashin © (04.06.07 20:47)
Хм. Это у художников полигон - квад, а у порграммеров, полигон - простейший элемент геометрии, то бишь треугольник. :) Во всяком случае в том обществе, где я кручусь.
-
Rial >Про (3) нечего сказать, извини уж, что так вышло. ;)
Ничего. Подождём может кто подскажет. За совет по делу огромное спасибо. Это то что я искал.
>Еще углы - еще поворот. Таким образом этот вектор у тебя >будет "образцом" поворота. >Перед отрисовкой получай из вектора всего 2 угла поворота >по осям и делай только 2 вызова glRotate.
Одно маленькое дополнение. Не 2 вызова а три. Потому что появляется составляющая принадлежащая третьей оси.
>Матрицы... вот тут то как раз ты зря пытаешься усложнить себе жизнь.
Я наоборот хочу упростить :) Я хочу через OpenGL считать конечную матрицу повторота. Т.е. загрузил начальную матрицу применил к ней первый поворот. Выгрузил запомнил. Когда появились новые повороты загрузил обратно повернул выгрузил :) В результате всё считает карточка :) И обратное разложение на углы даже и не понадобится так как уже будет готовая матрица поворота.
Yashin >Никогда не выводил полигоны, а зачем, если треугольники намного удобней
Если есть треугольники то удобней выводить их. А если есть масив точек задающий полигон то выводить проще полигон. А уж разбиением на точки пусть занимается карточка. Тем более что у меня полигоны плоские и как они будут разбиты на треугольники совершенно без разницы.
Итак остался только третий вопрос. Кто может помочь выручайте.
-
> Одно маленькое дополнение. Не 2 вызова а три. Потому что > появляется составляющая принадлежащая третьей оси.
LOL. Зачем ТРИ вращения??? Вроде как бы любой поворот достигается двумя вращениями.
> Я наоборот хочу упростить :) > Я хочу через OpenGL считать конечную матрицу повторота. > Т.е. загрузил начальную матрицу применил к ней первый поворот. > Выгрузил запомнил. Когда появились новые повороты загрузил > обратно повернул выгрузил :) В результате всё считает карточка > :) И обратное разложение на углы даже и не понадобится так > как уже будет готовая матрица поворота.
Как то странно упрощаешь... Через попу. glLoadIdeti glPushMatrix glPopMatrix
> Если есть треугольники то удобней выводить их. А если есть > масив точек задающий полигон то выводить проще полигон. > А уж разбиением на точки пусть занимается карточка. Тем > более что у меня полигоны плоские и как они будут разбиты > на треугольники совершенно без разницы.
glu и glut работают на ЦПУ. И никакого отношения к карточке не имеют. Я могу еще раз повторить банальность: ВСЕ что делает карточка - получает вершину, преобразует, получает треугольник, преобразует и выводит. Ну еще может в роли хранилища данных выступать, для текстурок, например. ВСЕ. Запомните! Карточка не будет вам НИЧЕГО разбивать.
-
Чорт. glLoadIdentity
-
> [9] MegaVolt © (05.06.07 11:50) > Одно маленькое дополнение. Не 2 вызова а три. Потому что > появляется составляющая принадлежащая третьей оси.
Дополнение неверно. Например, поворот по осям Z и Y вектора (X, Y, Z):
fTmp :=X * Cos(aZ) - Y * Sin(aZ); X' := fTmp * Cos(aY) - Z * Sin(aY); Y' := Y * Cos(aZ) + X * Sin(aZ); Z' := Z * Cos (aY) + fTmp * Sin(aY);
Очевидно, перебирая все возможные aZ, aY для заданных X, Y, Z, покрываем все возможные значения X', Y', Z'.
> Я наоборот хочу упростить :) > Я хочу через OpenGL считать конечную матрицу повторота. > Т.е. загрузил начальную матрицу применил к ней первый поворот. > Выгрузил запомнил. Когда появились новые повороты загрузил > обратно повернул выгрузил :) В результате всё считает карточка > :) И обратное разложение на углы даже и не понадобится так > как уже будет готовая матрица поворота.
Глупости. А если нужно будет сделать поворот относительный ? Ведь у тебя будут сохранены только повороты единичной матрицы. Иногда свой велосипед изобретать полезно, но в данным случае ты получишь частное решение, неприменимое в общем случае.
> Если есть треугольники то удобней выводить их. А если есть > масив точек задающий полигон то выводить проще полигон. > А уж разбиением на точки пусть занимается карточка. Тем > более что у меня полигоны плоские и как они будут разбиты > на треугольники совершенно без разницы.
"Плоские полигоны" - хм ?.. А вообще рекомендую карточке "подсовывать" исключетильно треугольники, таким образом ты получишь наилучшее быстродействие.
> [10] @!!ex_ (05.06.07 12:31)
Присоединяюсь, просто хотелось полнее раскрыть суть вопроса. :)
-
> [7] Yashin © (04.06.07 20:47) > Никогда не выводил полигоны, а зачем, если треугольники > намного удобней
[9] MegaVolt © (05.06.07 11:50) > Тем более что у меня полигоны плоские и как они будут разбиты > на треугольники совершенно без разницы.
Полигон == треугольник!!!! Теперь ты, Yashin, никогда впредь и не выводи полигоны, а ты, MegaVolt, так и продолжай «разбивать» их на треугольники! Вот смеху то будет :)
-
Само слово "полигон" (поли == много!!!!) явно означает "многоугольник". Хотя, действительно, в 3D-графике "полигонами" часто называют треугольники. Но это скорее профессиональный жаргон, а вовсе не истина в последней инстанции :)
-
@!!ex_ >LOL. Зачем ТРИ вращения??? Вроде как бы любой поворот достигается двумя вращениями.
Возможно. Пока для меня это неочевидно :( Буду думать.
>Как то странно упрощаешь... Через попу. >glLoadIdentity >glPushMatrix >glPopMatrix
А как умножить ту матрицу что у меня есть текущая на ту которую вернёт Pop?
Т.е. порядок действий такой: glLoadIdentity glRotate и теперь то что получилось нужно домножить на то что сохранено.
>ВСЕ что делает карточка - получает вершину, преобразует, получает треугольник, преобразует и выводит.
Я не правильно выразился. Когда я говорит карточка я имел в виду OpenGL. То что карточка не в состоянии бить полигоны я подозревал :)
Rial >Иногда свой велосипед изобретать полезно, но в данным случае >ты получишь частное решение, неприменимое в общем случае.
Подскажи как правильно?
>А вообще рекомендую карточке "подсовывать" исключетильно треугольники, >таким образом ты получишь наилучшее быстродействие.
На текущий момент быстродействие меня не волнует. У меня во всей сцене не более 100 вершин из которых мой полигон занимает 10-16 вершин причём с одноцветной закраской даже без освещения остальное линии сетки :) Так что проблем с производительностью не предвидится :)
homm >Полигон == треугольник!!!!
C какого это перепугу? Я говорю про элемент рисуемый glBegin(GL_POLYGON);
Т.е. некий объект заданный своими вершинами. Само собой если вершины 3 то это треугольник.
Если в терминологии спецов принято называть треугольник полигоном то как они называют то что я называю полигоном?
-
> Возможно. Пока для меня это неочевидно :( Буду думать.
Эм.. А как же высшее образование?(последний раз цепляюсь по поводу вышки. Больше не буду. чессслово.)
> А как умножить ту матрицу что у меня есть текущая на ту > которую вернёт Pop?
Хел тебе поможет, это раз. Зачем че-то на че-то умножать я не догоняю. В своих проектах ниче никогда не умножал(я имею ввиду касательно ОГЛ, так то понятно, часто приходится матрицы множить) и камера прекрасно вертится.
ЛОгика такая: Каждый кадр выставляешь единичную матрицу, функцию ты знаешь. Каждый кадр выставляешь ту систему координат, которая нужна.
> Я не правильно выразился. Когда я говорит карточка я имел > в виду OpenGL. То что карточка не в состоянии бить полигоны > я подозревал :)
Я может удивлю... Но glu и glut не имеют никакого отношения к OpenGL. :)) Это просто библиотект реализующий некий функционал используя OpenGL.(Больше не буду придиратся.. Чессслово. :)))
> На текущий момент быстродействие меня не волнует. У меня > во всей сцене не более 100 вершин из которых мой полигон > занимает 10-16 вершин причём с одноцветной закраской даже > без освещения остальное линии сетки :) Так что проблем с > производительностью не предвидится :)
"Это покааа. Это покааа." (С) Мужской сезон: Бархатная революция.
> C какого это перепугу? > Я говорю про элемент рисуемый > glBegin(GL_POLYGON); > > Т.е. некий объект заданный своими вершинами. Само собой > если вершины 3 то это треугольник. > > Если в терминологии спецов принято называть треугольник > полигоном то как они называют то что я называю полигоном?
Многоугольник. :)) У моделлеров обычно полигон - квад. У программеров - треугольник.
-
> Если в терминологии спецов принято называть треугольник > полигоном то как они называют то что я называю полигоном?
Polygon! Чувствуешь разницу? :))
-
> [15] MegaVolt © (05.06.07 19:50) > Подскажи как правильно?
Ну вот такую процедурку я обычно вызываю при изменении размеров окна:
glViewPort(..); glMatrixMode(GL_Projection); glLoadIdentity; If(bRendererMode)then gluPickMatrix(...); ... gluPerspective(...); glMatrixMode(GL_ModelView); If (Not bRendererMode)then begin glLoadIdentity; glTranslatef(...); end; glScissor(...);
Т.е. по сути у тебя постоянно установлена единичная матрица. А далее при каждой отрисовке: Var fRotateZ : GLFloat; fRotateY : GLFloat; .. glPushMatrix; glRotateF(fRotateZ, 0.0, 0.0, 1.0); glRotateF(fRotateY, 0.0, 1.0, 0.0); //рисуем здесь :) glPopMatrix;
Хранить достаточно 2 угла поворота. Их, естественно, нужно еще вычислять. Но это наиболее разумный подход.
-
@!!ex_ >Эм.. А как же высшее образование?(последний раз цепляюсь по поводу вышки. Больше не буду. чессслово.)
Rial >Хранить достаточно 2 угла поворота.
Господа моё высшее образование не позволяет верить выводам которые опровергаются простейшими примерами.
Итак рисуем кубик его грани паралельны осям. Система координат стандартная x,y в плоскости координат z уходит в экран
На передней грани нарисована стрелочка вверх. Как с помощью двух поворотов вокруг осей X и Y получить кубик у которого средлочка на передней грани повёрнута влево или вправо.
Я например не смог подобрать такие углы. Обязательно нужен третий поворот.
@!!ex_ >Зачем че-то на че-то умножать я не догоняю.
glRotate это умножение той матрицы что у нас была на матрицу поворота. Вот оно и умножение. Соответственно если я сам где то храню матрицу поворота то я её должен умножить с помощью glMultMatrix
>Я может удивлю... Но glu и glut не имеют никакого отношения к OpenGL. :)) >Это просто библиотект реализующий некий функционал используя OpenGL. >(Больше не буду придиратся.. Чессслово. :)))
Я даже спорить не буду :) Но от себя добавлю что и OpenGL и GLU реализованы одинаково програмно. Только одна обращается к карточке на прямую а вторая через OpenGL. Так что разница чисто условна.
Про полигон который многоугольник понял :))
|