亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

Delphi下的OpenGL開發

2019-11-18 18:19:28
字體:
來源:轉載
供稿:網友
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_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0);
ambient: TGLArrayf4=( 0.3, 0.3, 0.3, 0.3);
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);

// set lights
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, @light0_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient);
glEnable(GL_LIGHT0);
end;

代码内的两个常量是必须的。一个定义光源位置(位于视点的后面的左上角),另外一个定义环境光线。这将产生少量的散乱光线,使你能够看到完全位于阴影中的某些物体。

虽然你可以使用光照设定光源,可是物体仍然没有绘制阴影。这是因为OpenGL需要知道你指定的每个多边形的“normal”以便进行光线计算(Normal是一个与表面正交的向量) 。如果你没有自己的向量函数库,可以使用以下方法计算三角形中三个顶点的normal。这个函数是以定点逆时针排列为基础的,因为normal是一个向量的叉积,如果你不遵守该规则,会使向量指向四面体内部。

function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3;
var a,b:TGLArrayf3;
begin
//make two vectors
a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2];
b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2];
//calculate cross-product
result[0]:=a[1]*b[2]-a[2]*b[1];
result[1]:=a[2]*b[0]-a[0]*b[2];
result[2]:=a[0]*b[1]-a[1]*b[0];
end;

使用这个函数,就可以设定所有的计算光线必需的信息了:
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);
a2:TGLArrayf3=(D, 0, -H1);
a3:TGLArrayf3=(0, 0, H2);
a4:TGLArrayf3=(0, HY, 0);
var n1, n2, n3, n4: TGLArrayf3; //normals
begin
n1 := getNormal(a1,a3,a2);
n2 := getNormal(a1,a2,a4);
n3 := getNormal(a2,a3,a4);
n4 := getNormal(a3,a1,a4);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_NORMALIZE);
glShadeModel(GL_FLAT);
glCullFace(GL_BACK);
glLoadIdentity;
glTranslatef(0.0, 0.0, -12.0);
glBegin(GL_TRIANGLES);
glNormal3fv(@n1);
glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3);
glNormal3fv(@n2);
glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4);
glNormal3fv(@n3);
glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4);
glNormal3fv(@n4);
glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4);
glEnd;
SwapBuffers(wglGetCurrentDC);
end;

这便是以上代码的效果:

现在,使用一点Delphi VCL提供的的东西。在窗体上放一个Timer,指定一个类成员“angle:single”并在每次Timer触发时让他增加1:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
angle:=angle+1.0;
Draw;
end;

离一个充满生气的OpenGL仅差条线:

glRotatef(angle, 0.0, 1.0, 0.0);

把它放在glBegin()内三角开始绘制前的位置上,这样你的阴影部分就可以旋转了,至此,一切结束。

上一篇:用DELPHI通過寫注冊表來實現建立IIS的虛擬目錄

下一篇:在delphi中建立程序的快捷方式--并將快捷方式放在開始->程序->的啟動組中

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲免费视频在线观看| 久久久久国产精品免费网站| 青青草国产精品一区二区| 亚洲性生活视频| 亚洲欧美激情在线视频| 中文字幕无线精品亚洲乱码一区| 欧美日韩性视频在线| 97视频国产在线| 91精品国产自产在线| 两个人的视频www国产精品| 激情av一区二区| 中文字幕在线日韩| 日韩精品在线免费观看视频| 91国产中文字幕| 欧美激情视频网址| 18性欧美xxxⅹ性满足| 91精品久久久久久久久不口人| 尤物九九久久国产精品的特点| 91精品久久久久久久久久久| 亚洲女同精品视频| 亚洲精品美女久久久久| 欧美一区二区三区四区在线| 亚洲一级一级97网| 久久久免费高清电视剧观看| 最好看的2019年中文视频| 日韩欧美有码在线| 91精品久久久久久久久久久久久| 欧美综合在线观看| 久久伊人精品一区二区三区| 不卡av日日日| 欧美亚洲午夜视频在线观看| 精品国产精品三级精品av网址| 午夜精品免费视频| 国产成人在线精品| 亚洲无限乱码一二三四麻| 欧美日韩亚洲视频一区| 久久精品夜夜夜夜夜久久| 日韩在线资源网| 欧美成人免费播放| 亚洲男人的天堂在线播放| 91免费高清视频| 日韩精品在线播放| 欧美黄色小视频| 久久视频精品在线| 欧美日韩免费看| 91精品久久久久久久久青青| 91精品国产自产在线观看永久| 久久九九国产精品怡红院| 欧美—级a级欧美特级ar全黄| 亚洲成人精品久久| 日韩欧美在线观看| 精品久久久久久久大神国产| 亚洲人成亚洲人成在线观看| 久久av红桃一区二区小说| 亚洲国产99精品国自产| 日韩在线视频导航| 国产精国产精品| 亚洲精品一区二区三区婷婷月| 欧美日韩中文在线观看| 国产亚洲精品一区二555| 黄色91在线观看| 欧美极品在线视频| 国产精国产精品| 日韩精品中文字幕有码专区| 91精品在线看| 欧美成人免费播放| 久久精品亚洲热| 九色精品美女在线| 亚洲精品日韩久久久| 国产精品日韩在线播放| 欧美日韩中国免费专区在线看| 在线观看国产成人av片| 国产亚洲精品美女久久久久| 日韩日本欧美亚洲| 日韩av中文在线| 欧美一区二区三区艳史| 欧美丝袜一区二区| 欧美中文字幕在线| 欧美性xxxxx极品娇小| 中文日韩在线观看| 欧美福利视频在线| 久久精品视频播放| 日韩中文字幕在线视频| 亚洲欧美一区二区精品久久久| 91精品国产成人www| 中文字幕不卡在线视频极品| 欧美大片第1页| 久久精品成人欧美大片| 久久成人亚洲精品| 高清欧美一区二区三区| 最近2019中文字幕大全第二页| 亚洲色图25p| 久久久久久网址| 国外成人性视频| 日韩一区av在线| 久久亚洲一区二区三区四区五区高| 亚洲精品网站在线播放gif| 九九视频这里只有精品| 91香蕉国产在线观看| 91国产中文字幕| 欧美日韩福利在线观看| 亚洲精品国产精品国产自| 8090成年在线看片午夜| 日韩av一区在线观看| 日本成人精品在线| 日韩av网址在线| 日本老师69xxx| 久久激情五月丁香伊人| 欧美成人剧情片在线观看| 亚洲一区二区三区在线免费观看| 精品国产欧美成人夜夜嗨| 国产精品久久久久久av下载红粉| 青青草国产精品一区二区| 亚洲精品一区中文| 欧美色欧美亚洲高清在线视频| 国产精品免费电影| 久久激情五月丁香伊人| 日韩中文字幕第一页| 一本色道久久综合狠狠躁篇的优点| 成人免费观看49www在线观看| 亚洲精品国产品国语在线| 精品福利免费观看| 在线观看91久久久久久| 亚洲精品日韩丝袜精品| 国产最新精品视频| 97久久精品视频| 亚洲国产成人在线视频| 亚洲欧美日韩精品| 美日韩精品视频免费看| 国产精品免费看久久久香蕉| 日韩精品视频中文在线观看| 激情成人中文字幕| 国模精品视频一区二区三区| 精品日本美女福利在线观看| 国产精品va在线播放我和闺蜜| 亚洲精品456在线播放狼人| 久久99精品久久久久久青青91| 欧美性xxxxxxxxx| 亚洲网站视频福利| 91高清免费在线观看| 成人亚洲激情网| 日韩在线观看高清| 亚洲天天在线日亚洲洲精| 国产日韩视频在线观看| 欧美第一页在线| 成人午夜在线影院| 日韩免费av在线| 日韩在线观看网站| 中文字幕精品在线| 亚洲美女精品久久| 日韩视频在线观看免费| 中文字幕久热精品视频在线| 亚洲欧美国产一本综合首页| 日韩免费中文字幕| 欧美午夜精品久久久久久久| 午夜精品蜜臀一区二区三区免费| 孩xxxx性bbbb欧美| 91系列在线播放| 久久精品亚洲热| 亚洲国产日韩欧美在线99| 免费91麻豆精品国产自产在线观看| 中文字幕亚洲欧美| 日韩成人在线视频网站| 疯狂欧美牲乱大交777|