Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.04.20;
Скачать: CL | DM;

Вниз

вектора нормалей   Найти похожие ветки 

 
basf   (2007-01-17 12:34) [0]

В одной книжонке по 3D-графике прочитал что по умолчанию за вектор нормали в OpenGL принимается вектор перпендикулярный к какой-либо плоскости (что, вроде бы, очевидно). Я рисую не самую сложную фигуру ("срезка" эллипсоида), при включении освещения объект пропадает, когда я нормали ставлю сам, то фигура видна, но так как я их ставлю с некоторой "погрешностью" получается не совсем то что надо. В общем, ставит OpenGL нормали сам или нет, может эту "опцию"  нужно как-то включить, подскажите, plz, как их правильно расставить.


 
@!!ex ©   (2007-01-17 13:28) [1]

Не ставит OpenGL нормали сам.
Проблема расчитать чтоли?


 
@!!ex ©   (2007-01-17 13:44) [2]

glut?
GLUT сам считает нормали, если ему указать, никогда им не пользовался...
Рисуй элипс сам? :)


 
Rial ©   (2007-01-17 16:25) [3]

Рассчет нормали (кое что наспех удалил, но работать должно):

function CalcNormal(Const V1X, V1Y, V1Z,
                                     V2X, V2Y, V2Z,
                                     V3X, V3Y, V3Z : GLFloat;
                               Const bNormalize : Boolean) : Array[0..2] of GLFloat;
Var VX1, VY1, VZ1,
    VX2, VY2, VZ2 : GLFloat;
   X, Y, Z : GLFloat;
   WrkI : GLFloat;
begin
VX1:=V1X - V2X;
VY1:=V1Y - V2Y;
VZ1:=V1Z - V2Z;
VX2:=V2X - V3X;
VY2:=V2Y - V3Y;
VZ2:=V2Z - V3Z;
//Вектор перпендикулярен центру треугольника
X:=VY1 * VZ2 - VZ1 * VY2;
Y:=VZ1 * VX2 - VX1 * VZ2;
Z:=VX1 * VY2 - VY1 * VX2;
If (bNormalize)then begin
 //Вычисляем длину
 WrkI:=Sqrt(X * X + Y * Y + Z * Z);
 If (WrkI = 0.0) then WrkI := 1.0; //Для предотвращения деления на ноль
 //Номализуем
 Result[0]:=X / WrkI;
 Result[1]:=Y / WrkI;
 Result[2]:=Z / WrkI;
end else begin
 Result[0]:=X;
 Result[1]:=Y;
 Result[2]:=Z;
end;
end;

procedure SetNormal(Const V1X, V1Y, V1Z,
                                     V2X, V2Y, V2Z,
                                     V3X, V3Y, V3Z : GLFloat);
Var GLNormal : Array[0..2] of GLFloat;
begin
GLNormal:=CalcNormal(V1X, V1Y, V1Z,
                     V2X, V2Y, V2Z,
                     V3X, V3Y, V3Z,
                     True);
glNormal3fv(@GLNormal);
end;


А вот как все делается без лишних библиотек.
Опять же, кое чего не хватает, но это прими как домашнее задание :)

procedure rglCalc_Disk(Const InnerRadius, OuterRadius, Height1, Height2 :  GLFloat);
Var Sn, Cs  :  Extended;
   iX, iY, oX, oY  :  GLFloat;
   biX, biY, boX, boY  :  GLFloat;
   I : Integer;
   iTexPosX, iTexPosY, oTexPosX, oTexPosY  :  GLFloat;
   biTexPosX, biTexPosY, boTexPosX, boTexPosY  :  GLFloat;
begin
 SinCos(TwoPi / DetailedX, Sn, Cs);
 biX :=InnerRadius;
 biY :=0.0;
 boX :=OuterRadius;
 boY :=0.0;

 boTexPosX :=1.0;
 boTexPosY :=0.5;
 biTexPosX :=0.5 + (InnerRadius / OuterRadius) / 2.0;
 biTexPosY :=0.5;

 SetDefaultNormal;

 glBegin(GL_Triangles);
  For I :=0 to DetailedX do begin
   iX :=biX;
   iY :=biY;
   oX :=boX;
   oY :=boY;

   iTexPosX :=biTexPosX;
   iTexPosY :=biTexPosY;
   oTexPosX :=boTexPosX;
   oTexPosY :=boTexPosY;

   PerformCoords(oX, oY, Cs, Sn, boX, boY);
   PerformCoords(iX, iY, Cs, Sn, biX, biY);

   boTexPosX :=oTexPosX + (boX - oX) / 2.0;
   boTexPosY :=oTexPosY + (boY - oY) / 2.0;

   biTexPosX :=iTexPosX + (biX - iX) / 2.0;
   biTexPosY :=iTexPosY + (biY - iY) / 2.0;

   //Первый треугольник
   glTexCoord2f(iTexPosX, iTexPosY);
   glVertex3f(iX, iY, Height1);

   glTexCoord2f(oTexPosX, oTexPosY);
   glVertex3f(oX, oY, Height2);

   glTexCoord2f(boTexPosX, boTexPosY);
   glVertex3f(boX, boY, Height2);

   //Второй треугольник
   glTexCoord2f(iTexPosX, iTexPosY);
   glVertex3f(iX, iY, Height1);

   glTexCoord2f(boTexPosX, boTexPosY);
   glVertex3f(boX, boY, Height2);

   glTexCoord2f(biTexPosX, biTexPosY);
   glVertex3f(biX, biY, Height1);

  end;
 glEnd;
end; //With rglEngine

procedure PerformCoords(Const X, Y, Cs, Sn  :  GLFloat; Var OutX, OutY  :  GLFloat);
begin
OutX :=X * Cs - Y * Sn;
OutY :=Y * Cs + X * Sn;
end;



 
@!!ex ©   (2007-01-17 16:32) [4]


> basf   (17.01.07 12:34)  

На будущее. (Я пока не чтал учиьтся даже и не знал).
Оказывается норамаль - это тупо векторное произведение двух векторов.
Возьми учебник ао Аналитической геометрии и посмотри тему: "векторное произведение". ИМХО это лучше чем тупо скопировать текст.


 
Думкин ©   (2007-01-17 18:42) [5]

> Оказывается норамаль - это тупо векторное произведение двух
> векторов.

Так то оно так, но оно не коммутативно, и при смене порядка - меняет направление. То есть определяет ориентацию. Это самая засада для многих.


 
Думкин ©   (2007-01-17 18:49) [6]

Кстати в glut была ошибка на подобную тему и в одном примере у Краснова, додекаэдр(кажется) при вращении терял одну сторону. :)


 
ors_archangel ©   (2007-01-17 19:36) [7]


//Вычисляем длину
WrkI:=Sqrt(X * X + Y * Y + Z * Z);
If (WrkI = 0.0) then WrkI := 1.0; //Для предотвращения деления на ноль
//Номализуем
Result[0]:=X / WrkI;
Result[1]:=Y / WrkI;
Result[2]:=Z / WrkI;

оптимизация деления:

//Вычисляем длину
WrkI:=Sqrt(X * X + Y * Y + Z * Z);
If WrkI <> 0.0 then begin //Для предотвращения деления на ноль
  WrkI := 1/WrkI;
  //Номализуем
  Result[0]:=X * WrkI;
  Result[1]:=Y * WrkI;
  Result[2]:=Z * WrkI;
end else begin
  Result[0]:=X;
  Result[1]:=Y;
  Result[2]:=Z;
end;


 
Rial ©   (2007-01-17 20:22) [8]

> [6] Думкин ©   (17.01.07 18:49)
> Кстати в glut была ошибка на подобную тему и в одном примере
> у Краснова, додекаэдр(кажется) при вращении терял одну сторону.
> :)

А glut вообще зло, имхо :)
Если glu можно еще использовать, чтобы не мучаться со своими
текстурными координатами и нормалями, то все, что делается
в glut лучше переписать заново.
Возможно, сейчас есть более новые версии, но в той, что испугала
меня, нашлись таки тоже какие то глюки, да и лишнего много там.

P.S.
Как я не изголялся с оптимизацией, а обогнать, например,
gluSphere по производительности хоть на сколько - нибудь
значимое число операций так и не смог,
даже переписав всю процедуру на ассемблере.


 
XProger ©   (2007-01-17 21:03) [9]

Нормаль в OpenGL это перпендикуляр к плоскости плоскости полигона?
СОЖГИТЕ ЭТУ КНИГУ!


 
Думкин ©   (2007-01-18 05:37) [10]


> XProger ©   (17.01.07 21:03) [9]

Ну если под нормалью понимать именно нормаль в математическом смысле в еквлидовом пространстве - то это так. А если конечно, в применении к ЖЛ - то таки нет.


 
Rial ©   (2007-01-18 09:32) [11]

>[7] ors_archangel ©   (17.01.07 19:36)
>оптимизация деления:
> WrkI:=Sqrt(X * X + Y * Y + Z * Z);
> If WrkI <> 0.0 then begin //Для предотвращения деления на ноль
>  WrkI := 1/WrkI;


Это, наверное, опечатка, да ? :)
Ибо во - первых нет
else WrkI:=1.0;
да и на самом деле количество тактов то не уменьшилось %)

Уж если придираешься к тиким глупостям, то уж
придирайся обоснованно.


 
MBo ©   (2007-01-18 10:11) [12]

>да и на самом деле количество тактов то не уменьшилось %)

Три деления обычно медленнее одного деления и трех умножений


 
@!!ex ©   (2007-01-18 10:15) [13]


> Думкин ©   (17.01.07 18:42) [5]

Не думаю что это так. ИМХО каждый должен знать, что нормальный треугольник - треугольник с вершинами заданными по часовой стрелке.
Если перемножать также по часовой - нормаль правильная получается.
Если я не ошибаюсь, конечно.


 
Думкин ©   (2007-01-18 10:36) [14]

> @!!ex ©   (18.01.07 10:15) [13]
>
> > Думкин ©   (17.01.07 18:42) [5]
>
> Не думаю что это так. ИМХО каждый должен знать, что нормальный
> треугольник - треугольник с вершинами заданными по часовой
> стрелке.

Либо треугольник нормальный, либо я ненормальный. Никогда подобные благоглупости не заучивал. И почему то, что ты описал должен знать каждый - в упор не понимаю.


 
MBo ©   (2007-01-18 10:55) [15]

>нормальный треугольник - треугольник с вершинами заданными по часовой стрелке

А в трехмерном пространстве как?


 
@!!ex ©   (2007-01-18 11:27) [16]

Я о трехмерном пространстве и говорю. :))
У треугольника есть лицевая сторона и задная.
Определяется по тому, в какой последовательности заданы вершины.
Соответственно если почасовой - то он повернут лицевой стороной к пользователю - если против, значит задней.
А знать...
Ну вообще как можно писать графику без знания этого? Ведь на этом очень многие алгоритмы построены... Тоже нахождение нормалей. :)))
Плюс для оптимизации обычно не рисуют треугольники повернутые задней стороной. и т.д.


 
Думкин ©   (2007-01-18 11:36) [17]

> @!!ex ©   (18.01.07 11:27) [16]

Это не знание, это предмет договора. Условность. Не инвариант.


 
@!!ex ©   (2007-01-18 12:57) [18]


> Думкин ©   (18.01.07 11:36) [17]

Это стандарт. Не знаю ни одного распространенного API, которое бы основывалось на другом стандарте.
Крестик закрывает окно. Это знание? Это стандарт.


 
Думкин ©   (2007-01-18 13:19) [19]

> @!!ex ©   (18.01.07 12:57) [18]

Да при чем тут АПИ и прочее? Я о высоком. :)
А еще есть правило правого буравчика и левого. :)


 
XProger ©   (2007-01-18 13:29) [20]

Maya, 3ds max хранят нужный порядок вершин. При применении модификаторов по типу Normal - соотсветствующе меняют этот порядок. Никаких проблем с экспортом и дальнейшим расчётом нормалей быть не может.


 
Ricks ©   (2007-01-18 13:35) [21]


> @!!ex ©


> MBo ©


В трехмерном пространстве нормаль к поверхности треугольника должна быть направлена так, чтобы с её конца поворот на минимальный угол от одной стороны к другой был ПРОТИВ часовой стрелке!

Для товарища basf предлагаю код (в принципе это уже было, но у меня немного по другому выглядит):

function PlaneNormal(Plane:array of TVector):TVector;
var v1, v2 : TVector;
begin
if Length(Plane) < 3
 then Result:=VectorOrth( CrossProduct(Plane[0], Plane[1]) )
 else begin
  v1:=SubVector( Plane[0], Plane[1] );
  v2:=SubVector( Plane[1], Plane[2] );
  Result:=VectorOrth( CrossProduct(v1, v2) );
 end;
end;

где:

TVector = record
 x : single;
 y : single;
 z : single;
end;

function SubVector(v1, v2 : TVector):TVector;
begin
Result:=Vector( v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.z );
end;

function CrossProduct(v1, v2 : TVector):TVector; // векторное произведение
begin
Result.X:=v1.Y * v2.Z - v1.Z * v2.Y;
Result.Y:=v1.Z * v2.X - v1.X * v2.Z;
Result.Z:=v1.X * v2.Y - v1.Y * v2.X;
end;

function VectorOrth(v:TVector):TVector;
var L : single;
begin
L:=VectorLength( v );
if IsZero(L)
 then Result:=NullVector
 else Result:=Vector( v.X / L, v.Y / L, v.Z / L );
end;

function VectorLength(v:TVector):single;
begin
Result:=Sqrt( Sqr(v.X) + Sqr(v.Y) + Sqr(v.Z) );
end;


пользуясь этим набором функций каждый сможет самостоятельно посчитать себе нормаль к треугольнику! :)


 
Думкин ©   (2007-01-18 14:08) [22]


> Ricks ©   (18.01.07 13:35) [21]
>
> В трехмерном пространстве нормаль к поверхности треугольника
> должна быть направлена так, чтобы с её конца поворот на
> минимальный угол от одной стороны к другой был ПРОТИВ часовой
> стрелке!


Кому должна? если уж пишите, то пишите - должна так согласно стандарту ....

Никто никому ничего изначально никогда в этом не должен.


 
Ricks ©   (2007-01-18 14:28) [23]


> Думкин ©


Ну просто должна она... должна и все! :)

Во всей аналитической геометрии и плюс еще в теоретической/аналитической механике нормаль выбирается именно так. Так уж принято...

А в OpenGL при неправильном выборе просто будет освещена другая сторона треугольника, исправить это можно домножением на (-1)


 
@!!ex ©   (2007-01-18 14:33) [24]


> Ricks ©   (18.01.07 13:35) [21]

А какую систему векторов образует векторное произведение? :)))


 
Думкин ©   (2007-01-18 14:33) [25]


> Ricks ©   (18.01.07 14:28) [23]

Про ЖЛ понимаю. Про аналитическую и далее - первый раз слышу. Если только в каких-нибудь конкретных учебниках.


 
Ricks ©   (2007-01-18 14:43) [26]


> @!!ex ©

Правую систему координат. А что?


> Думкин ©

Нет не только в конкрентых учебниках, это у нас на парах было (не думаю, что только в нашем институте указом ректора такую фигню ввели)! :)


 
Ricks ©   (2007-01-18 15:05) [27]

Кстати о делении на ноль итд итп (посты [3], [7])
если длинна вектора нулевая, то ни о какой дальнейшей нормализации не может быть и речи!


 
ors_archangel ©   (2007-01-18 16:09) [28]


> Ricks ©   (18.01.07 15:05) [27]

Ну, n = (0,0,0) не намного лучше в этом случае...
Тебе тоже нужно оптимизировать деление, и на ноль можно проверить перед Sqrt.
Извините, что придераюсь, люди, просто глаз режет, нормаль - это эе частая операция


 
Думкин ©   (2007-01-18 18:53) [29]

> Ricks ©   (18.01.07 14:43) [26]

Тут такой момент - имеет место быть произвольность выбора, которая в конечном счете на результат не влияет.
Я же говорю: наряду с правилом правого буравчика, есть и правило левого. И ни одно животное от этого не пострадало.

Вот возьмем электричество. Движущийся заряд создает магнитное поле, это магнитное поле действует на другой движущийся заряд.
Как будем работать для счета? Работаем с векторными произведениями. Главное в них четко зафиксировать один выбор - куда итоговый направлять и все и с соответствующим выбором выписать законы. А примите ли вы по часовой или против - в реале два заряда все одно провзаимодействуют точно также. Фиксировать выбор надо при одной работе и содним и тем же набором обектов. Зафиксировать ориентацию. При этом выбора изначально - ровно два. И чем предложенный вами выбор лучше другого - я не знаю. Главное знать об этом и при обсуждении выяснять - какую ориентацию выбрал собеседник. И все. Остальное от лукавого. И в книгах многих, просто сообщают вначале - каким буравчиком они будут врезать вектора. Это хорошие книги. Те же кто не сообщает этого надеясь на "общепринятое" - поступают не совсем верно, если конечно это будет важно. Потому что иногда эо не очень важно. Главное знать, что есть +1 и -1.


 
ors_archangel ©   (2007-01-18 20:45) [30]

В том же OpenGL отлично переключается :) glCullFace, если я не ошибаюсь, у меня друг один проект сначала писал CW (Clock-Wise, по часовой стрелке), а потом взял всё переделал на CCW (были причины, для взаимодействия с какой-то библиотекой), вобщем, выбор не принципиален, но тем не менее общепринятое решение здесь практически полезно


 
basf   (2007-01-23 17:48) [31]

Да уж, расчёт нормали с помощью векторного произв-я кажется вроде бы совсем несложным, а я то сначала через углы считал - кучу времени и нервов потратил, т.к. долго не получалось. Спасибо за ответы!


 
basf   (2007-01-23 17:58) [32]

Теперь задачка - наложить на это дело текстуру, но я с этим ещё мало разбирался и вопросов пока нет ...потом появятся ;-)



Страницы: 1 вся ветка

Текущий архив: 2008.04.20;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.024 c
15-1204740905
tesseract
2008-03-05 21:15
2008.04.20
Мдя студенты проснулись


15-1204656429
Fredy314
2008-03-04 21:47
2008.04.20
как можно создавая многотомный архив, создать только второй том?


2-1206196869
***mikle***
2008-03-22 17:41
2008.04.20
Ошибка несоответствия типов


3-1196237600
pavel_guzhanov
2007-11-28 11:13
2008.04.20
UDF для Firebird


3-1195800195
alexnmsk
2007-11-23 09:43
2008.04.20
Помогите составить запрос