| 導購 | 订阅 | 在线投稿
分享
 
 
 

講解Delphi下的OpenGL開發入門

來源:互聯網  2008-05-19 00:44:11  評論

OpenGL最初是由Silicon圖形公司開發的底層圖形庫規範。你的系統中准確實現這個規範的部分,通常被稱爲OpenGL驅動,它允許你使用幾何集合(點,線,多邊形,圖像等等)來描述你希望表現的場景。讓肉眼觀察起來較爲舒適的中等規模場景,通常在毫秒級的速度上實現,這意味著該庫文件有足夠的能力來支持你創建一個生機勃勃的虛擬世界。

OpenGL驅動一般以二進制庫文件的形式提供。它能夠動態的連接到你的程序中。在Windows平台上,它將是成爲DLL的形式(在你的系統目錄下檢查opengl.dll)。自從Delphi能夠使用任何DLL開始,它對OpenGL 3D編程的能力就像其他任何語言一樣容易了。本文將幫助你獲得在Delphi中進行OpenGL開發的有效知識。

數學基礎

OpenGL擁有強大的數學基礎,因此對它功能的限制完全取決于你的想象能力(譯者注:沒有做不到,只有想不到)。對于理解那些公理和引理,更好的是讓我們立刻認識一個簡單的3D坐標系統,它是3D編程中慣用的坐標系統。如下:

王朝网络

你應該如何理解你的屏幕(藍色的方塊)在場景中的放置位置呢?發出四條射線並形成屏幕的那個點,是該想象空間中的視點(point of view)。OpenGL讓你調用兩個簡單的函數來定義這個場景

glMatrixMode(GL_PROJECTION);

glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);

在這個調用的過程中的-0.1,0.1,-0.1,0.1定義了這個可視屏幕的左上角和右下角坐標;0.3指定視愕狡聊壞木嗬?就好象「近剪貼板」(near clipping plane))同時25.0指定「遠剪貼板」(far clipping plane)。任何近剪貼板前面的物體以及遠剪貼板後面的物體都將不可見。當然,你能夠任意擺弄這些數字,以使他們適合你需要的場景。

從基本元素(primitive)到對象

現在開始最有意思的部分:對象。OpenGL僅僅支持以下幾種基本幾何圖形:點,線和多邊形。沒有表面或者更高級的圖形(比如球狀圖形)能被作爲基本圖形元素繪制。但是它們能夠用多邊形完美的模仿出來。隨意看看現代3D遊戲,你會發現它們完全由三角形建立。因此,我們不會被此限制所約束。

對象的繪制非常類似Pascal語言編程。每個塊都應該被begin-end包含著,更爲確切的說是glBegin()和glEnd()。如同下面的例子:

const S=1.0; D=5.0;

...

glBegin(GL_TRIANGLES);

glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D);

glEnd;

這是個簡單的三角形。它距離你的視點有5個單位,自身高1個單位,寬2個單位。

這是屏幕截圖:

王朝网络

即使它看起來不象3D圖形,但它是我們的初始塊。在下面你可以看到這個例子的源代碼。

在你開始鑽研代碼前,還有些話要說。每次OpenGL編程,都包含一些初始化輸出設備的OS設定(OS-specific)代碼。如果你使用Win32,你將需要設置像素格式以及建立顯示上下文環境脫離windows設備上下文環境。如果windows系統級編程你並不很在行,你可以把如下的代碼作爲模版使用。FormCreate中被調用函數的詳細信息可以參考幫助文檔。

FILE: Tri.pas

unit Tri;

interface

uses

OpenGL, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls, ComCtrls;

type

TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

procedure FormPaint(Sender: TObject);

private

procedure Draw; //Draws an OpenGL scene on request

public

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure setupPixelFormat(DC:HDC);

const

pfd:TPIXELFORMATDESCRIPTOR = (

nSize:sizeof(TPIXELFORMATDESCRIPTOR); // size

nVersion:1; // version

dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or

PFD_DOUBLEBUFFER; // support double-buffering

iPixelType:PFD_TYPE_RGBA; // color type

cColorBits:24; // preferred color depth

cRedBits:0; cRedShift:0; // color bits (ignored)

cGreenBits:0; cGreenShift:0;

cBlueBits:0; cBlueShift:0;

cAlphaBits:0; cAlphaShift:0; // no alpha buffer

cAccumBits: 0;

cAccumRedBits: 0; // no accumulation buffer,

cAccumGreenBits: 0; // accum bits (ignored)

cAccumBlueBits: 0;

cAccumAlphaBits: 0;

cDepthBits:16; // depth buffer

cStencilBits:0; // no stencil buffer

cAuxBuffers:0; // no auxiliary buffers

iLayerType:PFD_MAIN_PLANE; // main layer

bReserved: 0;

dwLayerMask: 0;

dwVisibleMask: 0;

dwDamageMask: 0; // no layer, visible, damage masks

);

var pixelFormat:integer;

begin

pixelFormat := ChoosePixelFormat(DC, @pfd);

if (pixelFormat = 0) then

exit;

if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then

exit;

end;

procedure GLInit;

begin

// set viewing projection

glMatrixMode(GL_PROJECTION);

glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);

// position viewer

glMatrixMode(GL_MODELVIEW);

glEnable(GL_DEPTH_TEST);

end;

procedure TForm1.FormCreate(Sender: TObject);

var DC:HDC;

RC:HGLRC;

i:integer;

begin

DC:=GetDC(Handle); //Actually, you can use any windowed control here

SetupPixelFormat(DC);

RC:=wglCreateContext(DC); //makes OpenGL window out of DC

wglMakeCurrent(DC, RC); //makes OpenGL window active

GLInit; //initialize OpenGL

end;

procedure TForm1.Draw;

const S=1.0; D=5.0;

begin

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity;

glTranslatef(0.0, 0.0, -12.0);

glBegin(GL_TRIANGLES);

glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D);

glEnd;

SwapBuffers(wglGetCurrentDC);

end;

procedure TForm1.FormPaint(Sender: TObject);

begin

Draw;

end;

end.

FILE: Tri.dfm

object Form1: TForm1

BorderStyle = bsDialog

Caption = \'BASIC OpenGL Program\'

ClientHeight = 318

ClientWidth = 373

OnCreate = FormCreate

OnPaint = FormPaint

end

3D曆險

好了,讓我們開始真正的3D吧。將先前的代碼作爲框架,我們增加一些畫線的代碼建立一個帶陰影面的四面體。應該如何用基本圖形元素來構建呢?我們使用四個三角形。一個在底部,另外三個作爲側面。這裏就是生成他們的代碼:

procedure TForm1.Draw;

const D=1.5;

H1=D/1.732;

H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)

HY=3.0;

const //vertexes

a1:TGLArrayf3=(-D, 0, -H1); //bootom left

a2:TGLArrayf3=( D, 0, -H1); //bootom right

a3:TGLArrayf3=( 0, 0, H2); //bootom back

a4:TGLArrayf3=( 0, HY, 0); //top

begin

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity;

glTranslatef(0.0, 0.0, -12.0);

glBegin(GL_TRIANGLES);

glVertex3fv(@a1); glVertex3fv(@a3); glVertex3fv(@a2);

glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);

glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);

glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);

glEnd;

SwapBuffers(wglGetCurrentDC);

end;

雖然看起來有點複雜,不過當你面對下面這張圖時,它就很容易理解了。

王朝网络

我們定義頂點a1 ? a4同時依據4個頂點位置建立指定的三角形。當你定義自己的三角形(或者其他的多邊形),請使用如下的規則:始終按照逆時針順序排列定點序號,就像你正在外部觀看側面一樣。通過這個規則,我們可以指定指定a1-a2-a4,a1-a3-a2(仰視),a2-a3-a4和a3-a1-a4。

現在就替換Tri.pas中TForm1.Darw()部分,程序運行的效果不會體現出過多的變化。它看起來仍然不象三維圖形。這是因爲我們還沒有設定任何光源。

LIGHTS! CAMERA! OPENGL!

在OpenGL中光源模式有兩部分:光源自身(顔色,強度等等)和對象材質。材質,依次包括顔色,一些物理參數(比如不透明性光澤性)以及紋理。深入其中,這會是一個巨大的世界,我們將一步步地接近。

定義一個光源相當容易。

procedure GLInit;

const

light0_positi

  OpenGL最初是由Silicon圖形公司開發的底層圖形庫規範。你的系統中准確實現這個規範的部分,通常被稱爲OpenGL驅動,它允許你使用幾何集合(點,線,多邊形,圖像等等)來描述你希望表現的場景。讓肉眼觀察起來較爲舒適的中等規模場景,通常在毫秒級的速度上實現,這意味著該庫文件有足夠的能力來支持你創建一個生機勃勃的虛擬世界。   OpenGL驅動一般以二進制庫文件的形式提供。它能夠動態的連接到你的程序中。在Windows平台上,它將是成爲DLL的形式(在你的系統目錄下檢查opengl.dll)。自從Delphi能夠使用任何DLL開始,它對OpenGL 3D編程的能力就像其他任何語言一樣容易了。本文將幫助你獲得在Delphi中進行OpenGL開發的有效知識。   數學基礎   OpenGL擁有強大的數學基礎,因此對它功能的限制完全取決于你的想象能力(譯者注:沒有做不到,只有想不到)。對于理解那些公理和引理,更好的是讓我們立刻認識一個簡單的3D坐標系統,它是3D編程中慣用的坐標系統。如下:      [url=/bbs/detail_1440293.html][img]http://images.wangchao.net.cn/images/upload/images/lsdn/1211129050727.jpg[/img][/url]   你應該如何理解你的屏幕(藍色的方塊)在場景中的放置位置呢?發出四條射線並形成屏幕的那個點,是該想象空間中的視點(point of view)。OpenGL讓你調用兩個簡單的函數來定義這個場景   glMatrixMode(GL_PROJECTION);   glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);   在這個調用的過程中的-0.1,0.1,-0.1,0.1定義了這個可視屏幕的左上角和右下角坐標;0.3指定視愕狡聊壞木嗬?就好象「近剪貼板」(near clipping plane))同時25.0指定「遠剪貼板」(far clipping plane)。任何近剪貼板前面的物體以及遠剪貼板後面的物體都將不可見。當然,你能夠任意擺弄這些數字,以使他們適合你需要的場景。   從基本元素(primitive)到對象   現在開始最有意思的部分:對象。OpenGL僅僅支持以下幾種基本幾何圖形:點,線和多邊形。沒有表面或者更高級的圖形(比如球狀圖形)能被作爲基本圖形元素繪制。但是它們能夠用多邊形完美的模仿出來。隨意看看現代3D遊戲,你會發現它們完全由三角形建立。因此,我們不會被此限制所約束。   對象的繪制非常類似Pascal語言編程。每個塊都應該被begin-end包含著,更爲確切的說是glBegin()和glEnd()。如同下面的例子:   const S=1.0; D=5.0;   ...   glBegin(GL_TRIANGLES);   glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D);   glEnd;   這是個簡單的三角形。它距離你的視點有5個單位,自身高1個單位,寬2個單位。   這是屏幕截圖:      [url=/bbs/detail_1440293.html][img]http://images.wangchao.net.cn/images/upload/images/lsdn/1211129050961.jpg[/img][/url]   即使它看起來不象3D圖形,但它是我們的初始塊。在下面你可以看到這個例子的源代碼。   在你開始鑽研代碼前,還有些話要說。每次OpenGL編程,都包含一些初始化輸出設備的OS設定(OS-specific)代碼。如果你使用Win32,你將需要設置像素格式以及建立顯示上下文環境脫離windows設備上下文環境。如果windows系統級編程你並不很在行,你可以把如下的代碼作爲模版使用。FormCreate中被調用函數的詳細信息可以參考幫助文檔。   FILE: Tri.pas   unit Tri;   interface   uses   OpenGL, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,   StdCtrls, ExtCtrls, ComCtrls;   type   TForm1 = class(TForm)   procedure FormCreate(Sender: TObject);   procedure FormPaint(Sender: TObject);   private   procedure Draw; //Draws an OpenGL scene on request   public   end;   var   Form1: TForm1;   implementation   {$R *.DFM}   procedure setupPixelFormat(DC:HDC);   const   pfd:TPIXELFORMATDESCRIPTOR = (   nSize:sizeof(TPIXELFORMATDESCRIPTOR); // size   nVersion:1; // version   dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or   PFD_DOUBLEBUFFER; // support double-buffering   iPixelType:PFD_TYPE_RGBA; // color type   cColorBits:24; // preferred color depth   cRedBits:0; cRedShift:0; // color bits (ignored)   cGreenBits:0; cGreenShift:0;   cBlueBits:0; cBlueShift:0;   cAlphaBits:0; cAlphaShift:0; // no alpha buffer   cAccumBits: 0;   cAccumRedBits: 0; // no accumulation buffer,   cAccumGreenBits: 0; // accum bits (ignored)   cAccumBlueBits: 0;   cAccumAlphaBits: 0;   cDepthBits:16; // depth buffer   cStencilBits:0; // no stencil buffer   cAuxBuffers:0; // no auxiliary buffers   iLayerType:PFD_MAIN_PLANE; // main layer   bReserved: 0;   dwLayerMask: 0;   dwVisibleMask: 0;   dwDamageMask: 0; // no layer, visible, damage masks   );   var pixelFormat:integer;   begin   pixelFormat := ChoosePixelFormat(DC, @pfd);   if (pixelFormat = 0) then   exit;   if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then   exit;   end;   procedure GLInit;   begin   // set viewing projection   glMatrixMode(GL_PROJECTION);   glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);   // position viewer   glMatrixMode(GL_MODELVIEW);   glEnable(GL_DEPTH_TEST);   end;   procedure TForm1.FormCreate(Sender: TObject);   var DC:HDC;   RC:HGLRC;   i:integer;   begin   DC:=GetDC(Handle); //Actually, you can use any windowed control here   SetupPixelFormat(DC);   RC:=wglCreateContext(DC); //makes OpenGL window out of DC   wglMakeCurrent(DC, RC); //makes OpenGL window active   GLInit; //initialize OpenGL   end;   procedure TForm1.Draw;   const S=1.0; D=5.0;   begin   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);   glLoadIdentity;   glTranslatef(0.0, 0.0, -12.0);   glBegin(GL_TRIANGLES);   glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D);   glEnd;   SwapBuffers(wglGetCurrentDC);   end;   procedure TForm1.FormPaint(Sender: TObject);   begin   Draw;   end;   end.   FILE: Tri.dfm   object Form1: TForm1   BorderStyle = bsDialog   Caption = \'BASIC OpenGL Program\'   ClientHeight = 318   ClientWidth = 373   OnCreate = FormCreate   OnPaint = FormPaint   end   3D曆險   好了,讓我們開始真正的3D吧。將先前的代碼作爲框架,我們增加一些畫線的代碼建立一個帶陰影面的四面體。應該如何用基本圖形元素來構建呢?我們使用四個三角形。一個在底部,另外三個作爲側面。這裏就是生成他們的代碼:   procedure TForm1.Draw;   const D=1.5;   H1=D/1.732;   H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3)   HY=3.0;   const //vertexes   a1:TGLArrayf3=(-D, 0, -H1); //bootom left   a2:TGLArrayf3=( D, 0, -H1); //bootom right   a3:TGLArrayf3=( 0, 0, H2); //bootom back   a4:TGLArrayf3=( 0, HY, 0); //top   begin   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);   glLoadIdentity;   glTranslatef(0.0, 0.0, -12.0);   glBegin(GL_TRIANGLES);   glVertex3fv(@a1); glVertex3fv(@a3); glVertex3fv(@a2);   glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);   glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);   glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);   glEnd;   SwapBuffers(wglGetCurrentDC);   end;   雖然看起來有點複雜,不過當你面對下面這張圖時,它就很容易理解了。      [url=/bbs/detail_1440293.html][img]http://images.wangchao.net.cn/images/upload/images/lsdn/1211129051164.jpg[/img][/url]   我們定義頂點a1 ? a4同時依據4個頂點位置建立指定的三角形。當你定義自己的三角形(或者其他的多邊形),請使用如下的規則:始終按照逆時針順序排列定點序號,就像你正在外部觀看側面一樣。通過這個規則,我們可以指定指定a1-a2-a4,a1-a3-a2(仰視),a2-a3-a4和a3-a1-a4。   現在就替換Tri.pas中TForm1.Darw()部分,程序運行的效果不會體現出過多的變化。它看起來仍然不象三維圖形。這是因爲我們還沒有設定任何光源。   LIGHTS! CAMERA! OPENGL!   在OpenGL中光源模式有兩部分:光源自身(顔色,強度等等)和對象材質。材質,依次包括顔色,一些物理參數(比如不透明性光澤性)以及紋理。深入其中,這會是一個巨大的世界,我們將一步步地接近。   定義一個光源相當容易。   procedure GLInit;   const   light0_positi
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有