Конференция "Игры" » Проблемы при освоении OpenGL. Подскажите решение. [Delphi, Windows]
 
  • MegaVolt © (04.06.07 10:48) [0]
    Занялся освоением OpenGL. Встретился с некоторыми трудностями красивых решений которых я не вижу. Подскажите как их обычно решают?

    1. Разбиение невыпуклого полигона на треугольники. Можно ли это сделать автоматически? Полигон задан координатами вершин, лежит целиком в одной плоскости. Для примера можно взять букву "Ш".
    Как разбить ручками я понимаю но очень хотелось бы разбивать автоматически. К алгоритму особых скоросных требований нет. Полгоны несложные поряка 10-16 вершин.

    2. Вращение объекта мышкой. Есть объект например куб изначально ориентированный по осям. На экране он так и выглядит. Двигаем по экрану мышь и преобразовываем это движение в поворот по двум осям. Теперь куб повёрнут на некоторые углы и соответственно так отрисован. Теперь нужно преобразовать следующее движение мыши в углы поворота. Вот тут и возникает сложность.

    так как в идеале дожно быть так:

    glRotate(Углы для 2-го поворота)
    glRotate(Углы для 1-го поворота)
    рисуем куб.

    Т.е. в матричном виде:
    Rn*...*(R2*(R1*x))

    Соответственно чтобы правильно осуществлять поворот нужно у себя в программе вычислять
    Rn*...(R3*(R2*R1))

    Есть ли другой способ осуществить задуманное? Можно ли вычитать матрицу из OpenGL? Загружать можно, домножать на мою можно а обратно извлеч можно?
  • Rial © (04.06.07 14:56) [1]
    По первому вопросу могу предложить свой способ с использованием текстуры.
    Как грузить текстуры, как их потом использовать - это все из другой басни.
    Я предлагаю лишь несложный алгоритм, отвечающий твоим требованиям
    с соблюдением определенной степени точности (если размер грани
    будет не меньше 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;
  • Sapersky (04.06.07 15:00) [2]
    Есть же вроде стандартные средства тесселяции, gluTess<...>
  • MegaVolt © (04.06.07 15:36) [3]
    >Есть же вроде стандартные средства тесселяции, gluTess<...>

    Есть но я их не заметил. Спасибо то что доктор прописал.

    Вопрос 2 остаётся открытым. и ещё добавляется новый:

    3. При триангуляции полигона в местах соприкосновения граней треугольников получаются небольшие просветы. Что то похожее на прозрачную паутинку. Как от этого можно избавиться?
  • Rial © (04.06.07 17:47) [4]
    > [2] Sapersky   (04.06.07 15:00)
    > Есть же вроде стандартные средства тесселяции, gluTess<...>

    Ну, это же скучно. :) Зачем искать легкие пути ?..
  • MegaVolt © (04.06.07 18:09) [5]
    >Ну, это же скучно. :) Зачем искать легкие пути ?..

    Как раз и открыл тему по поиску лёгких путей.
    По другим вопросам есть что сказать?
  • Rial © (04.06.07 19:05) [6]
    Про (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;
  • Yashin © (04.06.07 20:47) [7]
    Никогда не выводил полигоны, а зачем, если треугольники намного удобней
  • @!!ex_ (05.06.07 10:01) [8]
    > [7] Yashin ©   (04.06.07 20:47)

    Хм. Это у художников полигон - квад, а у порграммеров, полигон - простейший элемент геометрии, то бишь треугольник. :)
    Во всяком случае в том обществе, где я кручусь.
  • MegaVolt © (05.06.07 11:50) [9]
    Rial
    >Про (3) нечего сказать, извини уж, что так вышло. ;)

    Ничего. Подождём может кто подскажет. За совет по делу огромное спасибо. Это то что я искал.

    >Еще углы - еще поворот. Таким образом этот вектор у тебя
    >будет "образцом" поворота.
    >Перед отрисовкой получай из вектора всего 2 угла поворота
    >по осям и делай только 2 вызова glRotate.

    Одно маленькое дополнение. Не 2 вызова а три. Потому что появляется составляющая принадлежащая третьей оси.

    >Матрицы... вот тут то как раз ты зря пытаешься усложнить себе жизнь.

    Я наоборот хочу упростить :)
    Я хочу через OpenGL считать конечную матрицу повторота. Т.е. загрузил начальную матрицу применил к ней первый поворот. Выгрузил запомнил. Когда появились новые повороты загрузил обратно повернул выгрузил :) В результате всё считает карточка :) И обратное разложение на углы даже и не понадобится так как уже будет готовая матрица поворота.

    Yashin
    >Никогда не выводил полигоны, а зачем, если треугольники намного удобней

    Если есть треугольники то удобней выводить их. А если есть масив точек задающий полигон то выводить проще полигон. А уж разбиением на точки пусть занимается карточка. Тем более что у меня полигоны плоские и как они будут разбиты на треугольники совершенно без разницы.

    Итак остался только третий вопрос. Кто может помочь выручайте.
  • @!!ex_ (05.06.07 12:31) [10]
    > Одно маленькое дополнение. Не 2 вызова а три. Потому что
    > появляется составляющая принадлежащая третьей оси.

    LOL. Зачем ТРИ вращения??? Вроде как бы любой поворот достигается двумя вращениями.


    > Я наоборот хочу упростить :)
    > Я хочу через OpenGL считать конечную матрицу повторота.
    > Т.е. загрузил начальную матрицу применил к ней первый поворот.
    > Выгрузил запомнил. Когда появились новые повороты загрузил
    > обратно повернул выгрузил :) В результате всё считает карточка
    > :) И обратное разложение на углы даже и не понадобится так
    > как уже будет готовая матрица поворота.

    Как то странно упрощаешь... Через попу.
    glLoadIdeti
    glPushMatrix
    glPopMatrix


    > Если есть треугольники то удобней выводить их. А если есть
    > масив точек задающий полигон то выводить проще полигон.
    > А уж разбиением на точки пусть занимается карточка. Тем
    > более что у меня полигоны плоские и как они будут разбиты
    > на треугольники совершенно без разницы.

    glu и glut работают на ЦПУ. И никакого отношения к карточке не имеют.
    Я могу еще раз повторить банальность:
    ВСЕ что делает карточка - получает вершину, преобразует, получает  треугольник, преобразует и выводит.
    Ну еще может в роли хранилища данных выступать, для текстурок, например. ВСЕ. Запомните! Карточка не будет вам НИЧЕГО разбивать.
  • @!!ex_ (05.06.07 12:31) [11]
    Чорт.
    glLoadIdentity
  • Rial © (05.06.07 17:02) [12]
    > [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)

    Присоединяюсь, просто хотелось полнее раскрыть суть вопроса. :)
  • homm © (05.06.07 17:11) [13]
    > [7] Yashin ©   (04.06.07 20:47)
    > Никогда не выводил полигоны, а зачем, если треугольники
    > намного удобней

    [9] MegaVolt © (05.06.07 11:50)
    > Тем более что у меня полигоны плоские и как они будут разбиты
    > на треугольники совершенно без разницы.

    Полигон == треугольник!!!!
    Теперь ты, Yashin, никогда впредь и не выводи полигоны, а ты, MegaVolt, так и продолжай «разбивать» их на треугольники! Вот смеху то будет :)
  • Sapersky (05.06.07 17:28) [14]
    Само слово "полигон" (поли == много!!!!) явно означает "многоугольник". Хотя, действительно, в 3D-графике "полигонами" часто называют треугольники. Но это скорее профессиональный жаргон, а вовсе не истина в последней инстанции :)
  • MegaVolt © (05.06.07 19:50) [15]
    @!!ex_
    >LOL. Зачем ТРИ вращения??? Вроде как бы любой поворот достигается двумя вращениями.

    Возможно. Пока для меня это неочевидно :( Буду думать.

    >Как то странно упрощаешь... Через попу.
    >glLoadIdentity
    >glPushMatrix
    >glPopMatrix

    А как умножить ту матрицу что у меня есть текущая на ту которую вернёт Pop?

    Т.е. порядок действий такой:
    glLoadIdentity
    glRotate
    и теперь то что получилось нужно домножить на то что сохранено.

    >ВСЕ что делает карточка - получает вершину, преобразует, получает  треугольник, преобразует и выводит.

    Я не правильно выразился. Когда я говорит карточка я имел в виду OpenGL. То что карточка не в состоянии бить полигоны я подозревал :)

    Rial
    >Иногда свой велосипед изобретать полезно, но в данным случае
    >ты получишь частное решение, неприменимое в общем случае.

    Подскажи как правильно?

    >А вообще рекомендую карточке "подсовывать" исключетильно треугольники,
    >таким образом ты получишь наилучшее быстродействие.

    На текущий момент быстродействие меня не волнует. У меня во всей сцене не более 100 вершин из которых мой полигон занимает 10-16 вершин причём с одноцветной закраской даже без освещения остальное линии сетки :) Так что проблем с производительностью не предвидится :)

    homm
    >Полигон == треугольник!!!!

    C какого это перепугу?
    Я говорю про элемент рисуемый
    glBegin(GL_POLYGON);

    Т.е. некий объект заданный своими вершинами. Само собой если вершины 3 то это треугольник.

    Если в терминологии спецов принято называть треугольник полигоном то как они называют то что я называю полигоном?
  • @!!ex_ (05.06.07 20:30) [16]
    > Возможно. Пока для меня это неочевидно :( Буду думать.

    Эм.. А как же высшее образование?(последний раз цепляюсь по поводу вышки. Больше не буду. чессслово.)


    > А как умножить ту матрицу что у меня есть текущая на ту
    > которую вернёт Pop?

    Хел тебе поможет, это раз.
    Зачем че-то на че-то умножать я не догоняю. В своих проектах ниче никогда не умножал(я имею ввиду касательно ОГЛ, так то понятно, часто приходится матрицы множить) и камера прекрасно вертится.

    ЛОгика такая:
    Каждый кадр выставляешь единичную матрицу, функцию ты знаешь.
    Каждый кадр выставляешь ту систему координат, которая нужна.


    > Я не правильно выразился. Когда я говорит карточка я имел
    > в виду OpenGL. То что карточка не в состоянии бить полигоны
    > я подозревал :)

    Я может удивлю... Но glu и glut не имеют никакого отношения к OpenGL. :)) Это просто библиотект реализующий некий функционал используя OpenGL.(Больше не буду придиратся.. Чессслово. :)))


    > На текущий момент быстродействие меня не волнует. У меня
    > во всей сцене не более 100 вершин из которых мой полигон
    > занимает 10-16 вершин причём с одноцветной закраской даже
    > без освещения остальное линии сетки :) Так что проблем с
    > производительностью не предвидится :)


    "Это покааа. Это покааа." (С) Мужской сезон: Бархатная революция.


    > C какого это перепугу?
    > Я говорю про элемент рисуемый
    > glBegin(GL_POLYGON);
    >
    > Т.е. некий объект заданный своими вершинами. Само собой
    > если вершины 3 то это треугольник.
    >
    > Если в терминологии спецов принято называть треугольник
    > полигоном то как они называют то что я называю полигоном?

    Многоугольник. :))
    У моделлеров обычно полигон - квад.
    У программеров - треугольник.
  • homm © (05.06.07 20:38) [17]
    > Если в терминологии спецов принято называть треугольник
    > полигоном то как они называют то что я называю полигоном?

    Polygon! Чувствуешь разницу? :))
  • Rial © (05.06.07 23:13) [18]
    > [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 угла поворота. Их, естественно,
    нужно еще вычислять. Но это наиболее разумный подход.
  • MegaVolt © (06.06.07 13:39) [19]
    @!!ex_
    >Эм.. А как же высшее образование?(последний раз цепляюсь по поводу вышки. Больше не буду. чессслово.)

    Rial
    >Хранить достаточно 2 угла поворота.

    Господа моё высшее образование не позволяет верить выводам которые опровергаются простейшими примерами.

    Итак рисуем кубик его грани паралельны осям.
    Система координат стандартная x,y в плоскости координат z уходит в экран

    На передней грани нарисована стрелочка вверх.
    Как с помощью двух поворотов вокруг осей X и Y получить кубик у которого средлочка на передней грани повёрнута влево или вправо.

    Я например не смог подобрать такие углы. Обязательно нужен третий поворот.

    @!!ex_
    >Зачем че-то на че-то умножать я не догоняю.

    glRotate это умножение той матрицы что у нас была на матрицу поворота. Вот оно и умножение. Соответственно если я сам где то храню матрицу поворота то я её должен умножить с помощью glMultMatrix

    >Я может удивлю... Но glu и glut не имеют никакого отношения к OpenGL. :))
    >Это просто библиотект реализующий некий функционал используя OpenGL.
    >(Больше не буду придиратся.. Чессслово. :)))

    Я даже спорить не буду :) Но от себя добавлю что и OpenGL и GLU реализованы одинаково програмно. Только одна обращается к карточке на прямую а вторая через OpenGL. Так что разница чисто условна.

    Про полигон который многоугольник понял :))
 
Конференция "Игры" » Проблемы при освоении OpenGL. Подскажите решение. [Delphi, Windows]
Есть новые Нет новых   [119229   +50][b:0][p:0.001]