OpenGl silicon图形公司开发的底层图形库规范。你的系统中准确实现这个规范的部分,通常被称为opengl驱动,它允许你使用几何集合(点,线,多边形,图像等等)来描述你希望表现的场景。让肉眼观察起来较为舒适的中等规模场景,通常在毫秒级的速度上实现,这意味着该库文件有足够的能力来支持你创建一个生机勃勃的虚拟世界。,这意味着该库文件有足够的能力来支持你创建一个生机勃勃的虚拟世界。
OpenGl windows平台上,它将是成为dll 的形式(在你的系统目录下检查 opengl.dll)。自从delphi能够使用任何dll开始
数学基础
opengl拥有强大的数学基础,因此对它功能的限制完全取决于你的想象能力:译者注:没有做不到,只有想不到),更好的是让我们立刻认识,更好的是让我们立刻认识一个简单的3d坐标系统,它是3d::
你应该如何理解你的屏幕(蓝色的方块)在场景中的放置位置呢?发出四条射线并形成屏幕的那个点,是该想象空间中的视点(观点)。opengl简单的函数来定义这个场景
glmatrixmode(gl_provoction);
glfrustum(-0.1,0.1,-0.1,0.1,0.3,25.0);
在这个调用的过程中的-0.1,0.1,-0.1,0.1 定义了这个可视屏幕的左上角和右下角坐标; 0.3指定视点到屏幕的距离(就好象“近剪贴板”(靠近剪裁平面)同时25.0指定“远剪贴板”(远剪平平面)。任何近剪贴板前面的物体以及远剪贴板后面的物体都将不可见。当然,你能够任意摆弄这些数字,以使他们适合你需要的场景。
从基本元素(原始)到对象
现在开始最有意思的部分:对象。opengl:点:线和多边形。没有表面或者更高级的图形,线和多边形。没有表面或者更高级的图形(比如球状图形)能被作为基本图形元素绘制。但是它们能够用多边形完美的模仿出来。随意看看现代3d游戏,你会发现它们完全由三角形建立。因此,我们不会被此限制所约束。,我们不会被此限制所约束。
对象的绘制非常类似pascal语言编程。每个块都应该被开始 - end
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)代码。如果你使用win32,你将需要设置像素格式以及建立显示上下文Windows设备上下文环境。如果Windows系统级编程你并不很在行,FormCreate中被调用函数的详细信息可以参考帮助文档。
文件:tri.pas
单位TRI;
界面
用途
OpenGL,Windows,Messages,Sysutils,类,图形,控件,表单,对话框,
stdctrls,extctrls,comctrls;
类型
tform1 = class(tform)
过程FormCreate(发送者:tobject);
过程FormPaint(发送者:tobject);
私人的
过程抽奖; //根据要求绘制OpenGL场景
民众
结尾;
var
form1:tform1;
执行
{$ r *.dfm}
过程setupixelformat(DC:HDC);
const
pfd:tpixelformatDescriptor =(
nsize:sizeof(tpixelformatDescriptor); // 尺寸
nversion:1; // 版本
dwflags:pfd_support_opengl或pfd_draw_to_to_window或
pfd_doublebuffer; //支持双重缓冲
ipixeltype:pfd_type_rgba; //颜色类型
Ccolorbits:24; //首选的颜色深度
CredBits:0;信用班:0; //颜色位(忽略)
cgreenbits:0; cgreenshift:0;
cbluebits:0; cblueshift:0;
calphabits:0; Calphashift:0; //没有α缓冲区
Caccumbits:0;
caccumredbits:0; //无积累缓冲,
caccumgreenbits:0; //累积位(忽略)
caccumbluebits:0;
Caccumalphabits:0;
cdepthbits:16; //深度缓冲区
cstencilbits:0; //没有模板缓冲区
Cauxbuffers:0; //没有辅助缓冲区
iLayerType:pfd_main_plane; //主层
大号:0;
dwlayermask:0;
dwvisiblembask:0;
dwdamagemask:0; //没有图层,可见,伤害口罩
);
var pixelformat:整数;
开始
pixelformat:= peacepixelformat(dc,@pfd);
如果(pixelformat = 0),则
出口;
if(setPixelforMat(DC,PixelforMat,@pfd)<> true)然后
出口;
结尾;
程序查看;
开始
//设置观看投影
glmatrixmode(gl_provoction);
glfrustum(-0.1,0.1,-0.1,0.1,0.3,25.0);
//位置查看器
glmatrixmode(gl_modelview);
glenable(gl_depth_test);
结尾;
过程tform1.formCreate(发件人:tobject);
VAR DC:HDC;
RC:HGLRC;
我:整数;
开始
DC:= getDC(handle); //实际上,您可以在此处使用任何窗口的控件
SetUppixelFormat(DC);
RC:= WGLCreateContext(DC); //使openGL窗口从DC中脱出
WGLMAKECURRENT(DC,RC); //使OpenGL窗口活动活动
光明; //初始化OpenGL
结尾;
过程tform1.draw;
const s = 1.0; d = 5.0;
开始
glclear(gl_color_buffer_bit或gl_depth_buffer_bit);
GLLODIDDICTITY;
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);
结尾;
过程tform1.formpaint(发件人:tobject);
开始
画;
结尾;
结尾。
文件:tri.dfm
对象形式1:tform1
borderstyle = bsdialog
字幕='Basic OpenGL程序'
客户端= 318
客户端= 373
onCreate = formCreate
OnPaint = FormPaint
结尾
3d历险
好了,让我们开始真正的,3d吧。将先前的代码作为框架,我们增加一些画线的代码建立一个带阴影面的四面体。应该如何用基本图形元素来构建呢?我们使用四个三角形。,我们增加一些画线的代码建立一个带阴影面的四面体。应该如何用基本图形元素来构建呢?我们使用四个三角形。一个在底部,另外三个作为侧面。这里就是生成他们的代码::
过程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 //顶点
a1:tglarrayf3 =(-d,0,-h1); //向左引导
a2:tglarrayf3 =(d,0,-h1); // bootom正确
a3:tglarrayf3 =(0,0,h2); // BOOTOM返回
a4:tglarrayf3 =(0,hy,0); //顶部
开始
glclear(gl_color_buffer_bit或gl_depth_buffer_bit);
GLLODIDDICTITY;
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);
结尾;
虽然看起来有点复杂,不过当你面对下面这张图时,它就很容易理解了。,它就很容易理解了。
我们定义顶点A1 - a4同时依据4个顶点位置建立指定的三角形。当你定义自己的三角形(或者其他的多边形),请使用如下的规则:始终按照逆时针顺序排列定点序号,就像你正在外部观看侧面一样。通过这个规则,A1-A2-A4,A1-A3-A2,A2-A3-A4和A3-A1-A1-A4。
现在就替换tri.pas中tform1.darw()部分,程序运行的效果不会体现出过多的变化。它看起来仍然不象三维图形。这是因为我们还没有设定任何光源。,程序运行的效果不会体现出过多的变化。它看起来仍然不象三维图形。这是因为我们还没有设定任何光源。
灯!相机! OpenGL!
在opengl:光源自身(颜色:光源自身(颜色,强度等等),依次包括颜色,依次包括颜色,一些物理参数(比如不透明性光泽性)以及纹理。深入其中世界,我们将一步步地接近。,我们将一步步地接近。
定义一个光源相当容易。
程序查看;
const
light0_position:tglarrayf4 =(-8.0,8.0,-16.0,0.0);
环境:tglarrayf4 =(0.3,0.3,0.3,0.3);
开始
//设置观看投影
glmatrixmode(gl_provoction);
glfrustum(-0.1,0.1,-0.1,0.1,0.3,25.0);
//位置查看器 */
glmatrixmode(gl_modelview);
glenable(gl_depth_test);
//设置灯
可亮(gl_lighting);
gllightfv(gl_light0,gl_position, @light0_position);
gllightfv(gl_light0,gl_ambient, @ambient);
可亮(gl_light0);
结尾;
代码内的两个常量是必须的。一个定义光源位置(位于视点的后面的左上角),另外一个定义环境光线。这将产生少量的散乱光线,使你能够看到完全位于阴影中的某些物体。
虽然你可以使用光照设定光源,可是物体仍然没有绘制阴影。这是因为opengl需要知道你指定的每个多边形的“正常”以便进行光线计算(正常是一个与表面正交的向量)。如果你没有自己的向量函数库,正常。这个函数是以定点逆时针排列为基础的,因为正常是一个向量的叉积,如果你不遵守该规则,会使,会使向量指向四面体内部。
函数getnormal(p1,p2,p3:tglarrayf3):tglarrayf3;
var a,b:tglarrayf3;
开始
//做两个向量
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];
//计算交叉产品
结果[0]:= A [1]*B [2] -a [2]*B [1];
结果[1]:= A [2]*B [0] -a [0]*B [2];
结果[2]:= A [0]*B [1] -a [1]*B [0];
结尾;
使用这个函数,就可以设定所有的计算光线必需的信息了::
过程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 //顶点
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; //正常
开始
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或gl_depth_buffer_bit);
可亮(gl_normize);
glshademodel(gl_flat);
glcullface(gl_back);
GLLODIDDICTITY;
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);
结尾;
这便是以上代码的效果:
现在,使用一点delphi vcl提供的的东西。在窗体上放一个计时器,指定一个类成员“角度:单”并在每次计时器触发时让他增加1:
过程tform1.timer1timer(发件人:tobject);
开始
角度:=角度+1.0;
画;
结尾;
离一个充满生气的opengl仅差条线:
glrotatef(角度为0.0,1.0,0.0);
把它放在glbegin()内三角开始绘制前的位置上,这样你的阴影部分就可以旋转了,至此,一切结束。,一切结束。