Opengl 最初是由 실리콘 图形公司开发的底层图形库规范。你的系统中准确实现这个规范的部分 图形公司开发的底层图形库规范。你的系统中准确实现这个规范的部分, 通常被称为 Opengl 驱动 驱动, 它允许你使用几何集合 (点 点, 线, 多边形, 图像等等) 来 来描述你希望表现的场景。让肉眼观察起来较为舒适的中等规模场景 描述你希望表现的场景。让肉眼观察起来较为舒适的中等规模场景, 通常在毫秒级的速度上实现, 这意味着该库文件有足够的能力来支持你创建一个生机勃勃的虚拟世界。
Opengl 驱动一般以二进制库文件的形式提供。它能够动态的连接到你的程序中。在 Windows 驱动一般以二进制库文件的形式提供。它能够动态的连接到你的程序中。在 驱动一般以二进制库文件的形式提供。它能够动态的连接到你的程序中。在 驱动一般以二进制库文件的形式提供。它能够动态的连接到你的程序中。在, 它将是成为 dll 的形式 ay (在你的系统目录下检查 OpenGl.dll) 。自从 delphi 能够使用任何 dll 开始 开始, 它对 Opengl 3d 编程的能力就像其他任何语言一样容易了。本文将帮助你获得在 delphi 中进行 Opengl 开发的有效知识。
数学基础
OpenGl 拥有强大的数学基础 拥有强大的数学基础, 拥有强大的数学基础 (译者注 : 没有做不到 : 没有做不到) 。对于理解那些公理和引理 。对于理解那些公理和引理, 更好的是让我们立刻认识一个简单的 3d 坐标系统 坐标系统, 它是 3d 编程中惯用的坐标系统。如下 :
你应该如何理解你的屏幕 (在场景中的放置位置呢?发出四条射线并形成屏幕的那个点) 蓝色的方块 蓝色的方块, 是该想象空间中的视点 (관점) 。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 指定视点到屏幕的距离 (就好象“近剪贴板”(클리핑 평면 근처 )) 同时 25.0 指定“远剪贴板”(먼 클리핑 평면) 。任何近剪贴板前面的物体以及远剪贴板后面的物体都将不可见。当然 。任何近剪贴板前面的物体以及远剪贴板后面的物体都将不可见。当然, 你能够任意摆弄这些数字, 以使他们适合你需要的场景。
从基本元素 (원시) prim
现在开始最有意思的部分 : 对象。 -opengl 仅仅支持以下几种基本几何图形 : 点 点, 线和多边形。没有表面或者更高级的图形 (比如球状图形 比如球状图形) 能被作为基本图形元素绘制。但是它们能够用多边形完美的模仿出来。随意看看现代 3d 游戏 游戏, 你会发现它们完全由三角形建立。因此, 我们不会被此限制所约束。
对象的绘制非常类似 Pascal al wart-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);
글렌드;
这是个简单的三角形。它距离你的视点有 5 , ,, 自身高 1 个单位 个单位, 宽 2 个单位。
这是屏幕截图 :
即使它看起来不象 3d 图形 图形, 但它是我们的初始块。在下面你可以看到这个例子的源代码。
在你开始钻研代码前, 还有些话要说。每次 OpenGl 编程 编程, 都包含一些初始化输出设备的 OS 设定 (OS- 특이 적) 代码。如果你使用 win32, 你将需要设置像素格式以及建立显示上下文环境脱离 Windows 系统级编程你并不很在行 Windows 设备上下文环境。如果 设备上下文环境。如果, 你可以把如下的代码作为模版使用。 formcreate 中被调用函数的详细信息可以参考帮助文档。
파일 : tri.pas
단위 트라이;
인터페이스
용도
OpenGl, Windows, 메시지, sysutils, 클래스, 그래픽, 컨트롤, 양식, 대화,
stdctrls, extctrls, comctrls;
유형
tform1 = 클래스 (tform)
프로 시저 Formcreate (sender : tobject);
절차 formpaint (발신자 : Tobject);
사적인
절차 추첨; // 요청시 OpenGL 장면을 그립니다
공공의
끝;
var
form1 : tform1;
구현
{$ r *.dfm}
절차 setuppixelformat (dc : hdc);
Const
pfd : tpixelformatdescriptor = (
nsize : sizeof (tpixelformatdescriptor); // 크기
nversion : 1; // 버전
dwflags : pfd_support_opengl 또는 pfd_draw_to_window 또는
pfd_doublebuffer; // 이중 소란을 지원합니다
iPixelType : PFD_TYPE_RGBA; // 색상 유형
ccolorbits : 24; // 선호하는 색 깊이
크레디트 : 0; Credshift : 0; // 색상 비트 (무시)
cgreenbits : 0; cgreenshift : 0;
cbluebits : 0; cblueshift : 0;
calphabits : 0; Calphashift : 0; // 알파 버퍼가 없습니다
caccumbits : 0;
caccumredbits : 0; // 축적 버퍼가 없음
caccumgreenbits : 0; // accum 비트 (무시)
caccumbluebits : 0;
caccumalphabits : 0;
CDEPTHBITS : 16; // 깊이 버퍼
cstencilbits : 0; // 스텐실 버퍼가 없습니다
cauxbuffers : 0; // 보조 버퍼가 없습니다
ilayertype : pfd_main_plane; // 메인 레이어
breserved : 0;
dwlayermask : 0;
dwvisiblemask : 0;
dwdamagemask : 0; // 레이어, 가시, 손상 마스크가 없습니다
);
var pixelformat : 정수;
시작하다
pixelforMat : = ChoosepixelforMat (dc, @pfd);
if (pixelformat = 0) 그러면
출구;
if (setpixelformat (dc, pixelformat, @pfd) <> true)
출구;
끝;
절차 Glinit;
시작하다
// 시청 투영을 설정합니다
glmatrixmode (gl_projection);
glfrustum (-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
// 위치 뷰어
glmatrixmode (gl_modelview);
glenable (gl_depth_test);
끝;
절차 tform1. formcreate (sender : tobject);
VAR DC : HDC;
RC : HGLRC;
I : 정수;
시작하다
DC : = getdc (핸들); // 실제로 여기에서 모든 창 컨트롤을 사용할 수 있습니다
setuppixelformat (dc);
RC : = wglcreateContext (DC); // DC에서 OpenGl 창을 만듭니다
WGLMAKECURRENT (DC, RC); // OpenGL 창을 활성화시킵니다
글리 니트; // OpenGL을 초기화합니다
끝;
절차 tform1.Draw;
const s = 1.0; d = 5.0;
시작하다
glclear (gl_color_buffer_bit 또는 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);
글렌드;
Swapbuffers (WGLGETCURRENTDC);
끝;
절차 tform1.formPaint (Sender : Tobject);
시작하다
그리다;
끝;
끝.
파일 : tri.dfm
객체 form1 : tform1
Borderstyle = bsdialog
캡션 = '기본 OpenGL 프로그램'
ClientHeight = 318
clientWidth = 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 // vertexes
A1 : tglarrayf3 = (-d, 0, -h1); // Bootom이 남았습니다
a2 : tglarrayf3 = (d, 0, -h1); // 부트 오른쪽
A3 : tglarrayf3 = (0, 0, H2); // bootom back
a4 : tglarrayf3 = (0, hy, 0); //맨 위
시작하다
glclear (gl_color_buffer_bit 또는 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);
글렌드;
Swapbuffers (WGLGETCURRENTDC);
끝;
虽然看起来有点复杂 虽然看起来有点复杂, 不过当你面对下面这张图时, 它就很容易理解了。
我们定义顶点 a1 - a4 同时依据 4 个顶点位置建立指定的三角形。当你定义自己的三角形 (或者其他的多边形), 请使用如下的规则 : 始终按照逆时针顺序排列定点序号, 就像你正在外部짐
现在就替换 tri.pas 中 tform1.darw () 部分, 程序运行的效果不会体现出过多的变化。它看起来仍然不象三维图形。这是因为我们还没有设定任何光源。
허파! 카메라! 오픈 gl!
在 Opengl 中光源模式有两部分 : 光源自身 光源自身 ■ 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 光源自身 和对象材质。材质 和对象材质。材质 和对象材质。材质 和对象材质。材质, 依次包括颜色, 一些物理参数 (比如不透明性光泽性 比如不透明性光泽性) 以及纹理。深入其中, 这会是一个巨大的 这会是一个巨大的世界, 我们将一步步地接近。
定义一个光源相当容易。
절차 Glinit;
Const
light0_position : tglarrayf4 = (-8.0, 8.0, -16.0, 0.0);
주변 : tglarrayf4 = (0.3, 0.3, 0.3, 0.3);
시작하다
// 시청 투영을 설정합니다
glmatrixmode (gl_projection);
glfrustum (-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
// 위치 뷰어 */
glmatrixmode (gl_modelview);
glenable (gl_depth_test);
// 조명을 설정합니다
glenable (gl_lighting);
gllightfv (gl_light0, gl_position, @light0_position);
gllightfv (gl_light0, gl_ambient, @ambient);
glenable (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 // 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; // 정상
시작하다
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);
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);
글렌드;
Swapbuffers (WGLGETCURRENTDC);
끝;
这便是以上代码的效果 :
现在 现在, 使用一点 Delphi VCL 提供的的东西。在窗体上放一个 타이머, 指定一个类成员“각도 : 단일”并在每次 타이머 触发时让他增加 1 :
절차 tform1.Timer1Timer (Sender : Tobject);
시작하다
각도 : = 각도+1.0;
그리다;
끝;
离一个充满生气的 OpenGL 仅差条线 :
glrotatef (각도, 0.0, 1.0, 0.0);
把它放在 glbegin () 内三角开始绘制前的位置上 内三角开始绘制前的位置上, 这样你的阴影部分就可以旋转了, 至此, 一切结束。 一切结束。