![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблемы при освоении OpenGL. Подскажите решение. [Delphi, Windows]
MegaVolt © (2007-06-04 10:48:00)Занялся освоением OpenGL. Встретился с некоторыми трудностями красивых решений которых я не вижу. Подскажите как их обычно решают?
1. Разбиение невыпуклого полигона на треугольники. Можно ли это сделать автоматически? Полигон задан координатами вершин, лежит целиком в одной плоскости. Для примера можно взять букву "Ш".
Как разбить ручками я понимаю но очень хотелось бы разбивать автоматически. К алгоритму особых скоросных требований нет. Полгоны несложные поряка 10-16 вершин.
2. Вращение объекта мышкой. Есть объект например куб изначально ориентированный по осям. На экране он так и выглядит. Двигаем по экрану мышь и преобразовываем это движение в поворот по двум осям. Теперь куб повёрнут на некоторые углы и соответственно так отрисован. Теперь нужно преобразовать следующее движение мыши в углы поворота. Вот тут и возникает сложность.
так как в идеале дожно быть так:
glRotate(Углы для 2-го поворота)
glRotate(Углы для 1-го поворота)
рисуем куб.
Т.е. в матричном виде:
Rn*...*(R2*(R1*x))
Соответственно чтобы правильно осуществлять поворот нужно у себя в программе вычислять
Rn*...(R3*(R2*R1))
Есть ли другой способ осуществить задуманное? Можно ли вычитать матрицу из OpenGL? Загружать можно, домножать на мою можно а обратно извлеч можно?
Sapersky (2007-06-05 17:28:00) [21]Само слово "полигон" (поли == много!!!!) явно означает "многоугольник". Хотя, действительно, в 3D-графике "полигонами" часто называют треугольники. Но это скорее профессиональный жаргон, а вовсе не истина в последней инстанции :)
homm (2007-06-05 17:11:00) [22]> [7] Yashin © (04.06.07 20:47)
> Никогда не выводил полигоны, а зачем, если треугольники
> намного удобней
[9] MegaVolt © (05.06.07 11:50)
> Тем более что у меня полигоны плоские и как они будут разбиты
> на треугольники совершенно без разницы.
Полигон == треугольник!!!!
Теперь ты, Yashin, никогда впредь и не выводи полигоны, а ты, MegaVolt, так и продолжай «разбивать» их на треугольники! Вот смеху то будет :)
Rial (2007-06-05 17:02:00) [23]> [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)
Присоединяюсь, просто хотелось полнее раскрыть суть вопроса. :)
@!!ex_ (2007-06-05 12:31:00) [24]> Одно маленькое дополнение. Не 2 вызова а три. Потому что
> появляется составляющая принадлежащая третьей оси.
LOL. Зачем ТРИ вращения??? Вроде как бы любой поворот достигается двумя вращениями.
> Я наоборот хочу упростить :)
> Я хочу через OpenGL считать конечную матрицу повторота.
> Т.е. загрузил начальную матрицу применил к ней первый поворот.
> Выгрузил запомнил. Когда появились новые повороты загрузил
> обратно повернул выгрузил :) В результате всё считает карточка
> :) И обратное разложение на углы даже и не понадобится так
> как уже будет готовая матрица поворота.
Как то странно упрощаешь... Через попу.
glLoadIdeti
glPushMatrix
glPopMatrix
> Если есть треугольники то удобней выводить их. А если есть
> масив точек задающий полигон то выводить проще полигон.
> А уж разбиением на точки пусть занимается карточка. Тем
> более что у меня полигоны плоские и как они будут разбиты
> на треугольники совершенно без разницы.
glu и glut работают на ЦПУ. И никакого отношения к карточке не имеют.
Я могу еще раз повторить банальность:
ВСЕ что делает карточка - получает вершину, преобразует, получает треугольник, преобразует и выводит.
Ну еще может в роли хранилища данных выступать, для текстурок, например. ВСЕ. Запомните! Карточка не будет вам НИЧЕГО разбивать.
@!!ex_ (2007-06-05 12:31:00) [25]Чорт.
glLoadIdentity
MegaVolt (2007-06-05 11:50:00) [26]Rial
>Про (3) нечего сказать, извини уж, что так вышло. ;)
Ничего. Подождём может кто подскажет. За совет по делу огромное спасибо. Это то что я искал.
>Еще углы - еще поворот. Таким образом этот вектор у тебя
>будет "образцом" поворота.
>Перед отрисовкой получай из вектора всего 2 угла поворота
>по осям и делай только 2 вызова glRotate.
Одно маленькое дополнение. Не 2 вызова а три. Потому что появляется составляющая принадлежащая третьей оси.
>Матрицы... вот тут то как раз ты зря пытаешься усложнить себе жизнь.
Я наоборот хочу упростить :)
Я хочу через OpenGL считать конечную матрицу повторота. Т.е. загрузил начальную матрицу применил к ней первый поворот. Выгрузил запомнил. Когда появились новые повороты загрузил обратно повернул выгрузил :) В результате всё считает карточка :) И обратное разложение на углы даже и не понадобится так как уже будет готовая матрица поворота.
Yashin
>Никогда не выводил полигоны, а зачем, если треугольники намного удобней
Если есть треугольники то удобней выводить их. А если есть масив точек задающий полигон то выводить проще полигон. А уж разбиением на точки пусть занимается карточка. Тем более что у меня полигоны плоские и как они будут разбиты на треугольники совершенно без разницы.
Итак остался только третий вопрос. Кто может помочь выручайте.
@!!ex_ (2007-06-05 10:01:00) [27]> [7] Yashin © (04.06.07 20:47)
Хм. Это у художников полигон - квад, а у порграммеров, полигон - простейший элемент геометрии, то бишь треугольник. :)
Во всяком случае в том обществе, где я кручусь.
Yashin (2007-06-04 20:47:00) [28]Никогда не выводил полигоны, а зачем, если треугольники намного удобней
Rial (2007-06-04 19:05:00) [29]Про (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;
MegaVolt (2007-06-04 18:09:00) [30]>Ну, это же скучно. :) Зачем искать легкие пути ?..
Как раз и открыл тему по поиску лёгких путей.
По другим вопросам есть что сказать?
Rial (2007-06-04 17:47:00) [31]> [2] Sapersky (04.06.07 15:00)
> Есть же вроде стандартные средства тесселяции, gluTess<...>
Ну, это же скучно. :) Зачем искать легкие пути ?..
MegaVolt (2007-06-04 15:36:00) [32]>Есть же вроде стандартные средства тесселяции, gluTess<...>
Есть но я их не заметил. Спасибо то что доктор прописал.
Вопрос 2 остаётся открытым. и ещё добавляется новый:
3. При триангуляции полигона в местах соприкосновения граней треугольников получаются небольшие просветы. Что то похожее на прозрачную паутинку. Как от этого можно избавиться?
Sapersky (2007-06-04 15:00:00) [33]Есть же вроде стандартные средства тесселяции, gluTess<...>
Rial (2007-06-04 14:56:00) [34]По первому вопросу могу предложить свой способ с использованием текстуры.
Как грузить текстуры, как их потом использовать - это все из другой басни.
Я предлагаю лишь несложный алгоритм, отвечающий твоим требованиям
с соблюдением определенной степени точности (если размер грани
будет не меньше 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;