Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Вектора нормали в OpenGL


Автор: nght_elf 6.4.2008, 21:50
Народ помогите пожалуйста дописать програмку.
Её суть- просто построить некоторуя фигуру, которую я построил, но не смог разобраться с освещением..
Вот её код, да, к стати, что-то мне подсказывает, что реализация задачи выполнена через заднее место..
Если вы увидете способ, как такую фигуру построить подругому- напишите плиз..

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus,
  OpenGL;

type
  TfrmGL = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormResize(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    DC : HDC;
    hrc: HGLRC;
  end;

var
  frmGL: TfrmGL;
  Down:boolean=false;
  wrkX,wrkY:integer;

implementation

{$R *.DFM}

procedure TfrmGL.FormPaint(Sender: TObject);
const d=700;
var i:integer;
begin
 glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);    


  glBegin(GL_QUADS);
  for i:=0 to d do begin
    //glNormal3f(?(i),?(i),?(i));
    glVertex3f(sin(2*pi*i/d), 0, cos(2*pi*i/d));
    glVertex3f(sin(2*pi*(i+1)/d), 0, cos(2*pi*(i+1)/d));
    glVertex3f(sin(2*pi*(i+1)/d), -i/d, cos(2*pi*(i+1)/d));
    glVertex3f(sin(2*pi*i/d), -i/d, cos(2*pi*i/d));end;
  glEnd;

 SwapBuffers(DC);
end;

procedure SetDCPixelFormat (hdc : HDC);
var
 pfd : TPixelFormatDescriptor;
 nPixelFormat : Integer;
begin
 FillChar (pfd, SizeOf (pfd), 0);
 pfd.dwFlags  := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
 nPixelFormat := ChoosePixelFormat (hdc, @pfd);
 SetPixelFormat (hdc, nPixelFormat, @pfd);
end;


procedure TfrmGL.FormCreate(Sender: TObject);
begin
 DC := GetDC (Handle);
 SetDCPixelFormat(DC);
 hrc := wglCreateContext(DC);
 wglMakeCurrent(DC, hrc);
 glClearColor (0.5, 0.5, 0.75, 1.0); 
 glEnable (GL_LIGHTING);
 glEnable (GL_LIGHT0);
 glEnable (GL_DEPTH_TEST);
end;

procedure TfrmGL.FormDestroy(Sender: TObject);
begin
 wglMakeCurrent(0, 0);
 wglDeleteContext(hrc);
 ReleaseDC (Handle, DC);
 DeleteDC (DC);
end;

procedure TfrmGL.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 If Key = VK_ESCAPE then Close;
end;

procedure TfrmGL.FormResize(Sender: TObject);
begin
 glViewport(0, 0, ClientWidth, ClientHeight);
 glMatrixMode (GL_PROJECTION);
 glLoadIdentity;
 glFrustum (-1, 1, -1, 1, 4, 10);
 glMatrixMode (GL_MODELVIEW);
 glLoadIdentity;


 glTranslatef(0.0, 0.0, -8.0);  

 glRotatef(10.0, 1.0, 0.0, 0.0); 
 glRotatef(20.0, 0.0, 1.0, 0.0); 
 InvalidateRect(Handle, nil, False);
end;


procedure TfrmGL.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Down := True;
  wrkX := X;
  wrkY := Y;
end;

procedure TfrmGL.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
    Down := False;
end;

procedure TfrmGL.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
   If Down then begin
     glRotatef (X - wrkX, 0.0, 1.0, 0.0);
     glRotatef (Y - wrkY, 1.0, 0.0, 0.0);
     InvalidateRect(Handle, nil, False);
     wrkX := X;
     wrkY := Y;
  end;
end;

end.


фигура- часть цилиндра, построенного из множества(400 шт) прямоугольников.. я находил вектора номали по стандартному способу- но лажа в том, что прямоугольники в данном примере практически сводятся к отрезку, т.к. их ширина стремится к нулю.. К сожалению число 700 здесь необходимо, и предложения уменьшить число плоскостей не подходит, к поставленной мне задачи..

Автор: DragonFire 7.4.2008, 10:59
Когда-то давно, классе в 10 писал прожку...
Там надо было загрузить из 3Дмакса объект с нормальным освещением.

Я стоил нормали к каждой вершине по алгоритму:
Перебираются все вершины фигуры, для каждой из них:
1) Перебираются все грани (плоскости), содержащие вершину
2) Находится нормаль к этой плоскости (по 3 точкам)
3) Все вектора нормалей суммируются
4) Происходит нормировка полученного вектора
5) Все данные передаются в OpenGL

У меня есть код, но там все повязано на объектак и векторах, но мб поможет, вот процедура нормировки:
Код

procedure T3DObject.BuildNormals;
var i,j,k,p:integer;
    tmp:TVector3D;
    camera:TVector3D;
begin
  Camera.X:=0;
  Camera.Y:=0;
  Camera.Z:=-1*cos(3.14*Angle.z/180);
  for i:=1 to Count do begin
  for p:=0 to 2 do begin
      Vertexes[planes[i][p]].Normal.Free;
      for j:=1 to Count do for k:=0 to 2 do
      if (vertexes[planes[i][p]].x=vertexes[planes[j][k]].x) and (vertexes[planes[i][p]].y=vertexes[planes[j][k]].y) and (vertexes[planes[i][p]].z=vertexes[planes[j][k]].z) then begin
        tmp:=Normal3D(
          vertexes[planes[j][0]].x,vertexes[planes[j][0]].y,vertexes[planes[j][0]].z,
          vertexes[planes[j][1]].x,vertexes[planes[j][1]].y,vertexes[planes[j][1]].z,
          vertexes[planes[j][2]].x,vertexes[planes[j][2]].y,vertexes[planes[j][2]].z);
        Vertexes[planes[i][p]].Normal:=SumVectors(Vertexes[planes[i][p]].Normal,tmp);
      end;
      Vertexes[planes[i][p]].Normal.Normalize;
  end;
  end;
end;


Добавлено через 1 минуту и 47 секунд
Это вдогонку:
Код

type
  TArray3D=array[0..2] of Extended;
  TVertexNumber=byte;
  TPlane=array[0..2] of TVertexNumber;

  TVertexes=array[TVertexNumber] of TVertex;
  TPlanes=array[TVertexNumber] of TPlane;


type
  T3DObject=object
      Center:TVertex;
      Angle:TVertex;
      Scale:Single;
      Vertexes:TVertexes;
      Planes:TPlanes;
      Count:Integer;
      CountVertex:Integer;
      ViewNormals:Boolean;
      R:Single;
    private
    public
      procedure New;
      procedure LoadFromFile(FileName:String);
      procedure LoadFromASE(FileName:String);
      procedure View(Camera:TCamera);
      procedure BuildNormals;
  end;

Автор: nght_elf 8.4.2008, 20:10
Поясни алгоритм поподробнее пожалуйста.

Автор: Alexeis 8.4.2008, 21:00
nght_elf, векторное произведение 2х векторов дает вектор нормали, но его нужно нормировать на единицу, т.е. разделить каждую из координат на длину вектора нормали. В зависимость от того как задавать порядок вершин по часовой или против получается либо внутренняя нормаль либо наружная. 

Автор: DragonFire 8.4.2008, 22:20
Alexeis, Именно) линал азы...

А алгоритм... Строим нормали к каждой вершине. Сначало большой цикл по всем вершинам.
Вначале вектор нормали к вершине - нулевой.
1) Перебираются все грани (плоскости), содержащие вершину 
Тут цикл, который проходит по всем граням. Если текущая вершина принадлежит грани, то мы прибавляем к уже полученному вектору нормали вершины (на самом первом шаге - к нулевому вектору), нормаль к плоскости.
2) Находится нормаль к этой плоскости (по 3 точкам)
Тут берутся 3 вершины любые принадлежащие грани, по ним строится нормаль ( как это сделать где-то на форуме было, ищи по "нормаль к плоскости по трем точкам").
3) Происходит нормировка полученного вектора
Тут цикл по вершинам заканчивается. И ПОлученные вектора нормалей все делятся на свои длины.
4) Все данные передаются в OpenGL
Тут вроде все ясно - перед каждой glVertex вызываем glNormal

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)