将CKER翻译的NeHe的VC 的OPENGL框架转成了Delphi版,
希望对现象我一样初学OPENGL的兄弟有所帮助,
不知为什么,我的Delphi环境下无法直接运行,但是在别的机器上好像没问题
我的机器只能编译后运行EXE文件。
感谢NeHe提供的这么好的框架,感谢CKER翻译的VC的资料 Program Project1;Uses
opengl,
windows,
Messages;Const
WND_TITLE = 'OPenGl 基本框架'; //标题
Var
//===========================================================================
// 每一个OpenGL都被连接到一个着色描述表上。着色描述表将所有的OpenGL调用命令连
// 接到Device Context(设备描述表)上,将OpenGL的着色描述表定义为hRC ,要让程序能
// 够绘制窗口的话,还需要创建一个设备描述表,Windows的设备描述表被定义为 hDC,
// DC将窗口连接到GDI(Graphics Device Interface图形设备接口)。而RC将OpenGL连接
// 到DC。
//===========================================================================
h_RC : HGLRC; // Rendering Context(着色描述表)。
h_DC : HDC; // Device Context(设备描述表)
h_Wnd : HWND; // 窗口句柄
h_Instance : HINST; // 程序Instance(实例)。
keys : Array[0..255] Of Boolean; // 用于键盘例程的数组
{$R *.res} //==============================================================================
//重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变(假定没有使用全屏模式)。
//甚至无法改变窗口的大小时(例如在全屏模式下),它至少仍将运行一次————————
//在程序开始时设置透视图。OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。
//==============================================================================Procedure glResizeWnd(Width, Height: Integer); // 重置并初始化GL窗口大小
Begin
If (Height = 0) Then // 防止高度为0,产生除0异常
Height := 1;
glViewport(0, 0, Width, Height); // 重置当前的视口(Viewport) //下面几行为透视图设置屏幕。意味着越远的东西看起来越小。这么做创建了一个现实
//外观的场景。此处透视按照基于窗口宽度和高度的45度视角来计算。0.1f,100.0f是
//我们在场景中所能绘制深度的起点和终点。
//glMatrixMode(GL_PROJECTION)指明接下来的两行代码将影响projection matrix(投影矩阵)。
//投影矩阵负责为我们的场景增加透视。
//glLoadIdentity()近似于重置。它将所选的矩阵状态恢复成其原始状态。
//调用 glLoadIdentity()之后我们为场景设置透视图。 glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵 gluPerspective(45.0, Width / Height, 0.1, 100.0); // 计算窗口的外观比例 //glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响 modelview matrix(模型观察矩阵)。
//模型观察矩阵中存放了我们的物体讯息。 glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵 //如果现在还不能理解这些术语的含义,请别着急。
//只要知道如果想获得一个精彩的透视场景的话,必须这么做。
End;//==============================================================================
// 对OpenGL进行所有的设置。将设置清除屏幕所用的颜色,打开深度缓存,
// 启用smooth shading(阴影平滑),等等。这个例程直到OpenGL窗口创建之后才会被调用。
// 此过程将有返回值。但此处的初始化没那么复杂,现在还用不着担心这个返回值。
//==============================================================================Procedure glInit();
Begin //设置清除屏幕时所用的颜色。如果对色彩的工作原理不清楚的话,快速解释一下。
//色彩值的范围从0.0f到1.0f。0.0f代表最黑的情况,1.0f就是最亮的情况。
//glClearColor 后的第一个参数是Red Intensity(红色分量),第二个是绿色,第三个是蓝色。
//最大值也是1.0f,代表特定颜色分量的最亮情况。最后一个参数是Alpha值。
//当它用来清除屏幕的时候,不用关心第四个数字。现在让它为0.0f。
//通过混合三种原色(红、绿、蓝),可以得到不同的色彩
//因此,使用glClearColor(0.0f,0.0f,1.0f,0.0f),您蓝色来清除屏幕。
//如果用 glClearColor(0.5f,0.0f,0.0f,0.0f)的话,将使用中红色来清除屏幕。
//不是最亮(1.0f),也不是最暗 (0.0f)。要得到白色背景,应该将所有的颜色设成最亮(1.0f)。
//要黑色背景的话,该将所有的颜色设为最暗(0.0f)。 glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景 //阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。 glShadeModel(GL_SMOOTH); // 启用阴影平滑 //接下来必须做的是关于depth buffer(深度缓存)的。将深度缓存设想为屏幕后面的层。
//深度缓存不断的对物体进入屏幕内部有多深进行跟踪。本程序其实没有真正使用深度缓存,
//但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。它的排序决定那个物体先画。
//这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分。 glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型 //接着告诉OpenGL我们希望进行最好的透视修正。
//这会十分轻微的影响性能。但使得透视图看起来好一点。 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正End;//==============================================================================
//所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。
//以后的每个程序会在此处增加新的代码。
//==============================================================================Procedure glDraw();
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
End;Function WndProc(hWnd: HWND; // 窗口的句柄
Msg: UINT; // 窗口的消息
wParam: WPARAM; // 附加的消息内容
lParam: LPARAM // 附加的消息内容
): LRESULT; stdcall;
Begin
Result := 0;
Case (Msg) Of // 检查Windows消息
WM_ACTIVATE: // 监视窗口激活消息
Begin
End;
WM_CREATE: // 创建
Begin
End;
WM_CLOSE: // 关闭
Begin
PostQuitMessage(0); // 发出退出消息
Result := 0
End;
WM_KEYDOWN: // 按键按下
Begin
keys[wParam] := True; // 如果是,设为TRUE
Result := 0;
End;
WM_KEYUP: // 按键松开
Begin
keys[wParam] := False; // 如果是,设为FALSE
Result := 0;
End;
WM_SIZE: //调整OpenGL窗口大小
Begin
glResizeWnd(LOWORD(lParam), HIWORD(lParam)); //LoWord=Width,HiWord=Height
Result := 0;
End;
WM_TIMER: //timers
Begin
End;
Else //其余的让Windows自行处理。
Result := DefWindowProc(hWnd, Msg, wParam, lParam); //向DefWindowProc传递所有未处理的消息。
End;
End;
希望对现象我一样初学OPENGL的兄弟有所帮助,
不知为什么,我的Delphi环境下无法直接运行,但是在别的机器上好像没问题
我的机器只能编译后运行EXE文件。
感谢NeHe提供的这么好的框架,感谢CKER翻译的VC的资料 Program Project1;Uses
opengl,
windows,
Messages;Const
WND_TITLE = 'OPenGl 基本框架'; //标题
Var
//===========================================================================
// 每一个OpenGL都被连接到一个着色描述表上。着色描述表将所有的OpenGL调用命令连
// 接到Device Context(设备描述表)上,将OpenGL的着色描述表定义为hRC ,要让程序能
// 够绘制窗口的话,还需要创建一个设备描述表,Windows的设备描述表被定义为 hDC,
// DC将窗口连接到GDI(Graphics Device Interface图形设备接口)。而RC将OpenGL连接
// 到DC。
//===========================================================================
h_RC : HGLRC; // Rendering Context(着色描述表)。
h_DC : HDC; // Device Context(设备描述表)
h_Wnd : HWND; // 窗口句柄
h_Instance : HINST; // 程序Instance(实例)。
keys : Array[0..255] Of Boolean; // 用于键盘例程的数组
{$R *.res} //==============================================================================
//重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变(假定没有使用全屏模式)。
//甚至无法改变窗口的大小时(例如在全屏模式下),它至少仍将运行一次————————
//在程序开始时设置透视图。OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。
//==============================================================================Procedure glResizeWnd(Width, Height: Integer); // 重置并初始化GL窗口大小
Begin
If (Height = 0) Then // 防止高度为0,产生除0异常
Height := 1;
glViewport(0, 0, Width, Height); // 重置当前的视口(Viewport) //下面几行为透视图设置屏幕。意味着越远的东西看起来越小。这么做创建了一个现实
//外观的场景。此处透视按照基于窗口宽度和高度的45度视角来计算。0.1f,100.0f是
//我们在场景中所能绘制深度的起点和终点。
//glMatrixMode(GL_PROJECTION)指明接下来的两行代码将影响projection matrix(投影矩阵)。
//投影矩阵负责为我们的场景增加透视。
//glLoadIdentity()近似于重置。它将所选的矩阵状态恢复成其原始状态。
//调用 glLoadIdentity()之后我们为场景设置透视图。 glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵 gluPerspective(45.0, Width / Height, 0.1, 100.0); // 计算窗口的外观比例 //glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响 modelview matrix(模型观察矩阵)。
//模型观察矩阵中存放了我们的物体讯息。 glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵 //如果现在还不能理解这些术语的含义,请别着急。
//只要知道如果想获得一个精彩的透视场景的话,必须这么做。
End;//==============================================================================
// 对OpenGL进行所有的设置。将设置清除屏幕所用的颜色,打开深度缓存,
// 启用smooth shading(阴影平滑),等等。这个例程直到OpenGL窗口创建之后才会被调用。
// 此过程将有返回值。但此处的初始化没那么复杂,现在还用不着担心这个返回值。
//==============================================================================Procedure glInit();
Begin //设置清除屏幕时所用的颜色。如果对色彩的工作原理不清楚的话,快速解释一下。
//色彩值的范围从0.0f到1.0f。0.0f代表最黑的情况,1.0f就是最亮的情况。
//glClearColor 后的第一个参数是Red Intensity(红色分量),第二个是绿色,第三个是蓝色。
//最大值也是1.0f,代表特定颜色分量的最亮情况。最后一个参数是Alpha值。
//当它用来清除屏幕的时候,不用关心第四个数字。现在让它为0.0f。
//通过混合三种原色(红、绿、蓝),可以得到不同的色彩
//因此,使用glClearColor(0.0f,0.0f,1.0f,0.0f),您蓝色来清除屏幕。
//如果用 glClearColor(0.5f,0.0f,0.0f,0.0f)的话,将使用中红色来清除屏幕。
//不是最亮(1.0f),也不是最暗 (0.0f)。要得到白色背景,应该将所有的颜色设成最亮(1.0f)。
//要黑色背景的话,该将所有的颜色设为最暗(0.0f)。 glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景 //阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。 glShadeModel(GL_SMOOTH); // 启用阴影平滑 //接下来必须做的是关于depth buffer(深度缓存)的。将深度缓存设想为屏幕后面的层。
//深度缓存不断的对物体进入屏幕内部有多深进行跟踪。本程序其实没有真正使用深度缓存,
//但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。它的排序决定那个物体先画。
//这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分。 glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型 //接着告诉OpenGL我们希望进行最好的透视修正。
//这会十分轻微的影响性能。但使得透视图看起来好一点。 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正End;//==============================================================================
//所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。
//以后的每个程序会在此处增加新的代码。
//==============================================================================Procedure glDraw();
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
End;Function WndProc(hWnd: HWND; // 窗口的句柄
Msg: UINT; // 窗口的消息
wParam: WPARAM; // 附加的消息内容
lParam: LPARAM // 附加的消息内容
): LRESULT; stdcall;
Begin
Result := 0;
Case (Msg) Of // 检查Windows消息
WM_ACTIVATE: // 监视窗口激活消息
Begin
End;
WM_CREATE: // 创建
Begin
End;
WM_CLOSE: // 关闭
Begin
PostQuitMessage(0); // 发出退出消息
Result := 0
End;
WM_KEYDOWN: // 按键按下
Begin
keys[wParam] := True; // 如果是,设为TRUE
Result := 0;
End;
WM_KEYUP: // 按键松开
Begin
keys[wParam] := False; // 如果是,设为FALSE
Result := 0;
End;
WM_SIZE: //调整OpenGL窗口大小
Begin
glResizeWnd(LOWORD(lParam), HIWORD(lParam)); //LoWord=Width,HiWord=Height
Result := 0;
End;
WM_TIMER: //timers
Begin
End;
Else //其余的让Windows自行处理。
Result := DefWindowProc(hWnd, Msg, wParam, lParam); //向DefWindowProc传递所有未处理的消息。
End;
End;
解决方案 »
- delphi调用dll函数问题
- 事件为参数线程怎么写
- 该过程中间设计到2个开发语言和数据库太麻烦求精简
- 让人愤怒,如果早有人重视,现在就不会死这么多人。
- 想结婚选日子吗?超难的“双八”问题,我没分了,有兴趣的进,很好玩!!!
- 准备将程序做成单机版和c/s版两种版本,是需要开发两次还是说只需要开发一次(c/s版)就可以了?不知道能不能把c/s版转化为单机版?
- 帮忙解决一个问题!!
- 关于 SetUp 文件的问题
- 收购成熟的流通企业进销存软件(家电)
- xp系统下delphi如何向打印端口LPT1按二进制循环输出0x36,0x39,0x3c;
- 做bde软件的安装程序,一定要用installshild express for delphi 吗?
- 哪里有fast report的Demo?
// 只在程序退出之前调用。作用是依次释放着色描述表,设备描述表和窗口句柄。
// 加入了许多错误检查。如果程序无法销毁窗口的任意部分,都会弹出带相应错误消息的
// 讯息窗口,
//==============================================================================Procedure glKillWnd(Fullscreen: Boolean);
Begin //在KillGLWindow()中所作的第一件事是检查是否处于全屏模式。
//如果是,要切换回桌面。本应在禁用全屏模式前先销毁窗口,
//但在某些显卡上这么做可能会使得桌面崩溃。所以还是先禁用全屏模式。
//这将防止桌面出现崩溃,并在Nvidia和3dfx显卡上都工作的很好! If Fullscreen Then // 处于全屏模式吗?
Begin
// 使用ChangeDisplaySettings(NULL,0)回到原始桌面。
// 将NULL作为第一个参数,
// 0作为第二个参数传递强制Windows使用当前存放在注册表中的值
// (缺省的分辨率、色彩深度、刷新频率,等等)来有效的恢复我原始桌面。
// 换回桌面后,还要使得鼠标指针重新可见。 ChangeDisplaySettings(devmode(Nil^), 0); // 是的话,切换回桌面
ShowCursor(True); //显示鼠标
End; //是否拥有着色描述表(hRC)。
If h_RC > 0 Then
//看我们能否释放它(将 hRC从hDC分开)。
If (Not wglMakeCurrent(h_DC, 0)) Then
MessageBox(0, 'DC和RC无法被释放!', '错误', MB_OK Or
MB_ICONERROR); // 能否删除着色描述表
If (Not wglDeleteContext(h_RC)) Then
Begin
MessageBox(0, '删除着色描述表失败!', '错误', MB_OK Or
MB_ICONERROR);
h_RC := 0;
End; //是否存在设备描述表,如果有尝试释放它。
If ((h_DC > 0) And (ReleaseDC(h_Wnd, h_DC) = 0)) Then
Begin
MessageBox(0, '释放设备描述表失败!', '错误', MB_OK Or
MB_ICONERROR);
h_DC := 0;
End; //是否存在窗口句柄,调用 DestroyWindow( hWnd )来尝试销毁窗口
If ((h_Wnd <> 0) And (Not DestroyWindow(h_Wnd))) Then
Begin
MessageBox(0, '无法销毁窗体!', '错误', MB_OK Or
MB_ICONERROR);
h_Wnd := 0;
End; // 注销窗口类
//这允许我们正常销毁窗口,接着在打开其他窗口时,
//不会收到诸如"Windows Class already registered"(窗口类已注册)的错误消息。
If (Not UnRegisterClass('OpenGL', hInstance)) Then
Begin
MessageBox(0, '无法注销窗口类!', '错误', MB_OK Or
MB_ICONERROR);
hInstance := 0;
End;
End;
//==============================================================================
// 创建OpenGL窗口,
// 带有5个参数:窗口的标题栏,窗口的宽度,窗口的高度,色彩位数(16/24/32),
// 全屏标志(TRUE --全屏模式, FALSE--窗口模式 )。
// 返回的布尔值 窗口是否成功创建。
//==============================================================================Function glCreateWnd(Width, Height: Integer; Fullscreen: Boolean; PixelDepth:
Integer): Boolean;
Var
wndClass : TWndClass; // 窗口类
dwStyle : DWORD; // 窗口风格
dwExStyle : DWORD; // 扩展窗口风格
PixelFormat : GLuint; // 象素格式
h_Instance : HINST; // 当前实例
dmScreenSettings : DEVMODE; // 设备模式
pfd : TPIXELFORMATDESCRIPTOR; //格式描述符Begin
h_Instance := GetModuleHandle(Nil); // 取得窗口的实例
ZeroMemory(@wndClass, SizeOf(wndClass)); // 初始化内存
With wndClass Do // 设置窗口类
Begin
style := CS_HREDRAW Or // 如果长度变化,
CS_VREDRAW Or // 如果高度变化,就是只要变化就强制重画
CS_OWNDC; //CS_OWNDC为窗口创建一个私有的DC。这意味着DC不能在程序间共享。
lpfnWndProc := @WndProc; // WndProc处理消息
// cbClsExtra := 0; // 无额外窗口数据
// cbWndExtra := 0; // 无额外窗口数据
hInstance := h_Instance; // 设置实例
//hIcon := LoadIcon(0, IDI_WINLOGO); // 装入缺省图标
hCursor := LoadCursor(0, IDC_ARROW); //载入鼠标指针
//hbrBackground := 0; // GL不需要背景
//lpszMenuName := ''; // 不需要菜单
lpszClassName := 'OpenGL'; //设定类名
End;
If (RegisterClass(wndClass) = 0) Then // 注册窗体类
Begin
MessageBox(0, '注册窗体类失败!', '错误', MB_OK Or
MB_ICONERROR);
Result := False;
Exit
End; // 如果需要全屏的话
If Fullscreen Then
Begin
ZeroMemory(@dmScreenSettings, SizeOf(dmScreenSettings)); // 确保内存分配
With dmScreenSettings Do
Begin // 设置屏幕设置的参数
dmSize := SizeOf(dmScreenSettings); // Devmode 结构的大小
dmPelsWidth := Width; // 所选屏幕宽度
dmPelsHeight := Height; // 所选屏幕高度
dmBitsPerPel := PixelDepth; // 每象素所选的色彩深度
dmFields := DM_PELSWIDTH // 设置初始标志为dmPelsWidth
Or DM_PELSHEIGHT // dmPelsHeight 和
Or DM_BITSPERPEL; // dmBitsPerPel
End; // 转换为全屏模式 ,
//切换成与dmScreenSettings所匹配模式。
//CDS_FULLSCREEN 移去了状态条。
//并保证在来回切换时,没有移动或改变您在桌面上的窗口。
// 转换为全屏模式
If (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) =
DISP_CHANGE_FAILED) Then //转换失败
Begin
MessageBox(0, '不能转换为全屏模式!', '错误', MB_OK
Or MB_ICONERROR);
Fullscreen := False;
End;
End; If (Fullscreen) Then // 仍在全屏模式下
Begin
dwStyle := WS_POPUP Or // 没有边框
WS_CLIPCHILDREN // 要让OpenGL正常运行,这两个属性是必须的。
Or WS_CLIPSIBLINGS; //他们阻止别的窗体在我们的窗体内/上绘图。
dwExStyle := WS_EX_APPWINDOW; // 窗体可见时处于最前面
ShowCursor(False); // 不显示鼠标
End
Else //否则
Begin
dwStyle := WS_OVERLAPPEDWINDOW Or //带标题栏、可变大小的边框、菜单和最大/小化按钮
WS_CLIPCHILDREN Or // 要让OpenGL正常运行,这两个属性是必须的。
WS_CLIPSIBLINGS; //他们阻止别的窗体在我们的窗体内/上绘图。
dwExStyle := WS_EX_APPWINDOW Or // 增强窗体的3D感观
WS_EX_WINDOWEDGE; // 边框为凸起
ShowCursor(false); // 不显示鼠标
End;
h_Wnd := CreateWindowEx(dwExStyle, // 扩展窗体风格
'OpenGL', // 类名
WND_TITLE, // 标题
dwStyle, // 窗体属性
0, 0, // 窗体位置
Width, Height, // 窗体大小
0, // 没有父窗体
0, // 没有菜单
h_Instance, // 实例句柄
Nil); // 不向WM_CREATE传递任何东东 If h_Wnd = 0 Then // 创建失败,销毁窗体
Begin
glKillWnd(Fullscreen);
MessageBox(0, '不能创建窗体!', '错误', MB_OK Or
MB_ICONERROR);
Result := False;
Exit;
End; // 描述象素格式
//选择了通过RGBA(红、绿、蓝、alpha通道)支持OpenGL和双缓存的格式。
//试图找到匹配选定的色彩深度(16位、24位、32位)的象素格式。
//最后设置16位Z-缓存。
//其余的参数要么未使用要么不重要
//(stencil buffer模板缓存和accumulation buffer聚集缓存除外)。
With pfd Do
Begin
nSize := SizeOf(TPIXELFORMATDESCRIPTOR); // 格式描述符大小
nVersion := 1; // 版本号
dwFlags := PFD_DRAW_TO_WINDOW // 格式必须支持窗口
Or PFD_SUPPORT_OPENGL // 格式必须支持OpenGL
Or PFD_DOUBLEBUFFER; // 必须支持双缓冲
iPixelType := PFD_TYPE_RGBA; // 申请 RGBA 格式
cColorBits := PixelDepth; // 选定色彩深度
cRedBits := 0; // 忽略的色彩位
cRedShift := 0; // 忽略的色彩位
cGreenBits := 0; // 忽略的色彩位
cGreenShift := 0; // 忽略的色彩位
cBlueBits := 0; // 忽略的色彩位
cBlueShift := 0; // 忽略的色彩位
cAlphaBits := 0; // 无Alpha缓存
cAlphaShift := 0; // 忽略Shift Bit
cAccumBits := 0; // 无聚集缓存
cAccumRedBits := 0; // 忽略聚集位
cAccumGreenBits := 0; // 忽略聚集位
cAccumBlueBits := 0; // 忽略聚集位
cAccumAlphaBits := 0; // 忽略聚集位
cDepthBits := 16; // 16位 Z-缓存 (深度缓存)
cStencilBits := 0; // 无模板缓存
cAuxBuffers := 0; // 无辅助缓存
iLayerType := PFD_MAIN_PLANE; // 主绘图层
bReserved := 0; // 保留
dwLayerMask := 0; // 忽略层遮罩
dwVisibleMask := 0; // 忽略层遮罩
dwDamageMask := 0; // 忽略层遮罩
End;
//得到设备场景描述
h_DC := GetDC(h_Wnd);
If (h_DC = 0) Then
Begin
glKillWnd(Fullscreen); // 创建失败,销毁窗体
MessageBox(0, '不能得到设备场景!', '错误', MB_OK Or
MB_ICONERROR);
Result := False;
Exit;
End; //找到相应的象素格式
PixelFormat := ChoosePixelFormat(h_DC, @pfd);
If (PixelFormat = 0) Then
Begin
glKillWnd(Fullscreen);
MessageBox(0, '找不到合适的格式', '错误', MB_OK
Or MB_ICONERROR);
Result := False;
Exit;
End; //设置像素格式.
If (Not SetPixelFormat(h_DC, PixelFormat, @pfd)) Then
Begin
glKillWnd(Fullscreen);
MessageBox(0, '无法创建渲染格式', '错误', MB_OK Or
MB_ICONERROR);
Result := False;
Exit;
End; //取得着色描述表
h_RC := wglCreateContext(h_DC);
If (h_RC = 0) Then
Begin
glKillWnd(Fullscreen);
MessageBox(0, '无法创建OpenGL 绘制描述表', '错误',
MB_OK Or MB_ICONERROR);
Result := False;
Exit;
End; //已经取得了设备描述表和着色描述表。
//激活着色描述表
If (Not wglMakeCurrent(h_DC, h_RC)) Then
Begin
glKillWnd(Fullscreen);
MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error',
MB_OK Or MB_ICONERROR);
Result := False;
Exit;
End;
//OpenGL窗口已经创建完成 // 显示窗体,置于最前
ShowWindow(h_Wnd, SW_SHOW); // 显示窗口
SetForegroundWindow(h_Wnd); // 略略提高优先级
SetFocus(h_Wnd); // 设置键盘的焦点至此窗口 glResizeWnd(Width, Height); // 设置透视 GL 屏幕
glInit(); // 初始化新建的GL窗口 Result := True;
End;Function WinMain(hInstance: HINST; //实例
hPrevInstance: HINST; // 前一个实例
lpCmdLine: PChar; // 命令行参数
nCmdShow: Integer // 窗口显示状态
): Integer; stdcall;
Var
msg : TMsg; // Windowsx消息结构
finished : Boolean; // 用来退出循环的Bool 变量
Begin
finished := False; //应用程序初始化
//glCreateWnd,创建窗体为800*600
If Not glCreateWnd(800, 600, false, 32) Then
Begin
Result := 0;
Exit;
End; While Not finished Do
Begin
//检查一个线程消息队列,将所选的范围保存到消息纪录中
//BOOL PeekMessage(
// LPMSG lpMsg, // 消息记录的指针
// HWND hWnd, // 窗口句柄
// UINT wMsgFilterMin, // 第一个消息
// UINT wMsgFilterMax, // 最后一个消息
// UINT wRemoveMsg // 标志 Value Meaning
// ); PM_NOREMOVE 处理后保留在消息队列中
// PM_REMOVE 处理后从消息队列中清除
//要做的第一件事是检查是否有消息在等待。
//使用PeekMessage()可以在不锁住我们的程序的前提下对消息进行检查。
//许多程序使用GetMessage(),也可以很好的工作。
//但使用GetMessage(),程序在收到paint消息或其他别的什么窗口消息之前不会做任何事。
If (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) Then //检查是否有消息
// wMsgFilterMin,wMsgFilterMax 这两个参数都为0,返回所有可用的消息
Begin
If (msg.message = WM_QUIT) Then // 如果是退出消息
finished := True //改变循环条件,退出
Else
Begin // 否则处理消息
// 翻译消息,然后发送消息,使得WndProc() 或 Windows能够处理他们。
TranslateMessage(msg); //翻译消息
DispatchMessage(msg); //发送消息
End;
End
Else //如果没有消息,绘制我们的OpenGL场景。
Begin
glDraw(); // 重画屏幕
SwapBuffers(h_DC); // 交换缓存 (双缓存) If (keys[VK_ESCAPE]) Then // 如果按下了ESC键
finished := True
End;
End;
glKillWnd(FALSE); // 释放窗体
Result := msg.wParam; // 退出程序
End;Begin
WinMain(hInstance, hPrevInst, CmdLine, CmdShow);
End.
这段代码的功能是设置一个 OpenGL窗口。它可以只是一个窗口或是全屏幕的、可以任意 大小、任意色彩深度。此处的代码很稳定且很强大,您可以在您所有的OpenGL项目中使用。我会尽量在学习NeHe教程的同时将他翻译成Delphi版的。
//所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。
//以后的每个程序会在此处增加新的代码。
//==============================================================================Procedure glDraw();
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存 //当您调用glLoadIdentity()之后,您实际上讲当前点移到了屏幕中心,X坐标轴从左至右,
//Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。
// 中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。
// 移入屏幕深处是负值,移出屏幕则是正值。
glLoadIdentity(); // 重置当前的模型观察矩阵 //glTranslatef(x, y, z)沿着 X, Y 和 Z 轴移动。
//根据前面的次序,下面的代码沿着X轴左移1.5个单位,Y轴不动(0.0f),最后移入屏幕6.0f个单位。
//注意在glTranslatef(x, y, z)中当您移动的时候,您并不是相对屏幕中心移动,
//而是相对与当前所在的屏幕位置。
glTranslatef(-1.5, 0.0, -6.0); // 左移 1.5 单位,并移入屏幕 6.0 //现在我们已经移到了屏幕的左半部分,
//并且将视图推入屏幕背后足够的距离以便我们可以看见全部的场景-创建三角形。
//glBegin(GL_TRIANGLES)的意思是开始绘制三角形,glEnd() 告诉OpenGL三角形已经创建好了。
//通常您会需要画3个顶点,可以使用GL_TRIANGLES。
//在绝大多数的显卡上,绘制三角形是相当快速的。
//如果要画四个顶点,使用GL_QUADS的话会更方便。
//但据我所知,绝大多数的显卡都使用三角形来为对象着色。
//最后,如果您想要画更多的顶点时,可以使用GL_POLYGON。 //本节的简单示例中,我们只画一个三角形。
//如果要画第二个三角形的话,可以在这三点之后,再加三行代码(3点)。
//所有六点代码都应包含在glBegin(GL_TRIANGLES) 和 glEnd()之间。
//在他们之间再不会有多余的点出现,
//也就是说,(GL_TRIANGLES) 和 glEnd()之间的点都是以三点为一个集合的。
//这同样适用于四边形。如果您知道实在绘制四边形的话,
//您必须在第一个四点之后,再加上四点为一个集合的点组。
//另一方面,多边形可以由任意个顶点,
//(GL_POLYGON)不在乎glBegin(GL_TRIANGLES) 和 glEnd()之间有多少行代码。 // 几何图元类型和说明
// 类型 说明
// GL_POINTS 单个顶点集
// GL_LINES 多组双顶点线段
// GL_POLYGON 单个简单填充凸多边形
// GL_TRAINGLES 多组独立填充三角形
// GL_QUADS 多组独立填充四边形
// GL_LINE_STRIP 不闭合折线
// GL_LINE_LOOP 闭合折线
// GL_TRAINGLE_STRIP 线型连续填充三角形串
// GL_TRAINGLE_FAN 扇形连续填充三角形串
// GL_QUAD_STRIP 连续填充四边形串 //glBegin之后的第一行设置了多边形的第一个顶点,
//glVertex 的第一个参数是X坐标,然后依次是Y坐标和Z坐标。
//第一个点是上顶点,然后是左下顶点和右下顶点。
//glEnd()告诉OpenGL没有其他点了。
//这样将显示一个填充的三角形。 //译者:这里要注意的是存在两种不同的坐标变换方式,
//glTranslatef(x, y, z)中的x, y, z是相对与您当前所在点的位移,
//但glVertex(x,y,z)是相对于glTranslatef(x, y, z)移动后的新原点的位移。
//因而这里可以认为glTranslate移动的是坐标原点,glVertex中的点是相对最新的坐标原点的坐标值。 glBegin(GL_TRIANGLES); // 绘制三角形
glVertex3f(0.0, 1.0, 0.0); // 上顶点
glVertex3f(-1.0, -1.0, 0.0); // 左下
glVertex3f(1.0, -1.0, 0.0); // 右下
glEnd(); // 三角形绘制结束 //在屏幕的左半部分画完三角形后,我们要移到右半部分来画正方形。
//为此要再次使用glTranslate。
//这次右移,所以X坐标值为正值。
//因为前面左移了1.5个单位,
//这次要先向右移回屏幕中心(1.5个单位),再向右移动1.5个单位。
//总共要向右移3.0个单位。 glTranslatef(3.0, 0.0, 0.0); // 右移3单位 //现在使用GL_QUADS绘制正方形。
//与绘制三角形的代码相类似,画四边形也很简单。
//唯一的区别是用GL_QUADS来替换了GL_TRIANGLES。
//并增加了一个点。
//我们使用顺时针次序来画正方形-左上-右上-右下-左下。
//采用顺时针绘制的是对象的后表面。这就是说我们所看见的是正方形的背面。
//逆时针画出来的正方形才是正面朝着我们的。
//现在来说并不重要,但以后您必须知道。
glBegin(GL_QUADS); // 绘制正方形
glVertex3f(-1.0, 1.0, 0.0); // 左上
glVertex3f(1.0, 1.0, 0.0); // 右上
glVertex3f(1.0, -1.0, 0.0); // 左下
glVertex3f(-1.0, -1.0, 0.0); // 右下
glEnd(); // 正方形绘制结束 // Markus Knauer 注:
//在 ("OpenGL Programming Guide: The Official Guide to Learning OpenGL, Release 1",
//J. Neider, T. Davis, M. Woo, Addison-Wesley, 1993)
//《OpenGL编程指南:OpenGL学习的官方指南,第一版》
//一书中清楚的解释了NeHe所指的在OpenGL中移动的单位概念:
//"在OpenGL中真的有英寸和英里的区别吗?
//答案是一句话:没有。透视和其他的变换都是无单位的。
//如果您想要裁剪在1.0到20.0米,英寸、公里等等之间的平面,
//在OpenGL中您无法做到。唯一的法则是您必须使用一致的度量单位。"
End;
你可以运行一下看看效果
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵 glTranslatef(-1.5, 0.0, -6.0); // 左移 1.5 单位,并移入屏幕 6.0 glBegin(GL_TRIANGLES); // 绘制三角形 //glColor3f(r,g,b)。括号中的三个参数依次是红、绿、蓝三色分量。
//取值范围可以从0,0到1.0。类似于以前所讲的清除屏幕背景命令。 //我们将颜色设为红色(纯红色,无绿色,无蓝色)。
//接下来的一行代码设置三角形的第一个顶点(三角形的上顶点),
//并使用当前颜色(红色)来绘制。从现在开始所有的绘制的对象的颜色都是红色,
//直到我们将红色改变成别的什么颜色。 glColor3f(1.0, 0.0, 0.0); //设置当前色为红色
glVertex3f(0.0, 1.0, 0.0); // 上顶点 //第一个红色顶点已经设置完毕。
//接下来我们设置第二个绿色顶点。三角形的左下顶点被设为绿色。
glColor3f(0.0, 1.0, 0.0); //设置当前色为绿色
glVertex3f(-1.0, -1.0, 0.0); // 左下
//三角形的右下顶点。将颜色设为蓝色
//glEnd()出现后,三角形将被填充。
//但是因为每个顶点有不同的颜色,因此看起来颜色从每个角喷出,
//并刚好在三角形的中心汇合,三种颜色相互混合。这就是平滑着色。
glColor3f(0.0, 0.0, 1.0); //设置当前色为蓝色
glVertex3f(1.0, -1.0, 0.0); // 右下 glEnd(); // 三角形绘制结束
glTranslatef(3.0, 0.0, 0.0); // 右移3单位 //现在我们绘制一个单调着色-紫色的正方形。
//最重要的是要记住,设置当前色之后绘制的所有东东都是当前色的。
//以后您所创建的每个工程都要使用颜色。
//即便是在完全采用纹理贴图的时候,
//glColor3f仍旧可以用来调节纹理的色调。
//等等....,以后再说吧。
//(呵呵,原书是蓝色,但是我喜欢紫色) glBegin(GL_QUADS); // 绘制正方形
glColor3f(0.6, 0.2, 2.0); //设置当前色为紫色
glVertex3f(-1.0, 1.0, 0.0); // 左上
glVertex3f(1.0, 1.0, 0.0); // 右上
glVertex3f(1.0, -1.0, 0.0); // 左下
glVertex3f(-1.0, -1.0, 0.0); // 右下
glEnd(); // 正方形绘制结束
End;运行一下看看效果
不要拿鸡蛋砸我呀,我真的不懂!--------------------------------------
靠,还不结帖!
帮我up一下,我好回贴http://expert.csdn.net/Expert/topic/2072/2072933.xml?temp=.1717646------------------------------------------------------------------------什么叫虚伪?这就叫虚伪!哈哈..........
平时那么些问游戏编程需要什么的,opengl怎么入门的,现在都哪去了?
俺对opengl以前也是一窍不通的,现在俺给他们整理好了贴出来,咋就没人理呢?要是到了周一还没人的话,俺就结贴,何苦呢?
其实仔细看看代码会发现,撇开OPENGL不说,我们也能学到很多东西的
我喜欢~
:)偶正在玩OpenGL,遇到问题多多~
还请指教!
我按部就班的做了一遍,挺不错~
可是遇到一个大~~~~~问题!
就是我想在一个Form中做多个OpenGL的显示——搞不定!
我下载了一个控件TGLPanel——好像是从“品雪”那儿下的——它能做,可是“视角”又不很理想,向改称我自己的方法,可惜功力太浅没搞定!求教
呵呵,我现在连门都没入,何来求教?在form中显示OPENGL我还没做过
不知道是不是简单的连接在form的DC上,而不是象例子中的自己创建DC如果是的话,在窗体中创建多个DC不知行不行?呵呵,OPENGL这个玩艺我才搞了几天,很外行的,共同学习吧
有点意思,果然是我想的那样!!
不过现在只是连接到form的DC上,代码如下:Unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, opengl, ExtCtrls;
Type
TForm1 = Class(TForm)
Timer1: TTimer;
Procedure FormCreate(Sender: TObject);
Procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
End;
Var
Form1 : TForm1;
h_RC : HGLRC; // Rendering Context(着色描述表)。
h_DC : HDC; // Device Context(设备描述表)
pfd : TPIXELFORMATDESCRIPTOR; //格式描述符
PixelFormat : GLuint; // 象素格式
keys : Array[0..255] Of Boolean; // 用于键盘例程的数组
rtri : GLfloat; // 用于三角形的角度
rquad : GLfloat; // 用于四边形的角度
Implementation
{$R *.dfm}
Procedure glDraw();
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
glTranslatef(-1.5, 0.0, -6.0); // 左移 1.5 单位,并移入屏幕 6.0
glRotatef(rtri, 0.0, 1.0, 0.0); // 绕Y轴旋转三角形 ( 新增 )
glBegin(GL_TRIANGLES); // 绘制三角
glColor3f(1.0, 0.0, 0.0); //设置当前色为红色
glVertex3f(0.0, 1.0, 0.0); // 上顶点
glColor3f(0.0, 1.0, 0.0); //设置当前色为绿色
glVertex3f(-1.0, -1.0, 0.0); // 左下
glColor3f(0.0, 0.0, 1.0); //设置当前色为蓝色
glVertex3f(1.0, -1.0, 0.0); // 右下
glEnd(); // 三角形绘制结束
glLoadIdentity(); // 重置模型观察矩阵
glTranslatef(1.5, 0.0, -6.0); // 右移1.5单位,并移入屏幕 6.0
glRotatef(rquad, 1.0, 0.0, 0.0); // 绕X轴旋转四边形 ( 新增 )
glBegin(GL_QUADS); // 绘制正方形
glColor3f(0.6, 0.2, 2.0); //设置当前色为紫色
glVertex3f(-1.0, 1.0, 0.0); // 左上
glVertex3f(1.0, 1.0, 0.0); // 右上
glVertex3f(1.0, -1.0, 0.0); // 左下
glVertex3f(-1.0, -1.0, 0.0); // 右下
glEnd(); // 正方形绘制结束
rtri := rtri + 0.2; // 增加三角形的旋转变量(新增)
rquad := rquad - 0.15; // 减少四边形的旋转变量(新增)
End;
Procedure glResizeWnd(Width, Height: Integer); // 重置并初始化GL窗口大小
Begin
If (Height = 0) Then // 防止高度为0,产生除0异常
Height := 1;
glViewport(0, 0, Width, Height); // 重置当前的视口(Viewport)
glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵
gluPerspective(45.0, Width / Height, 0.1, 100.0); // 计算窗口的外观比例
glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
End;
Procedure glInit();
Begin
glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正
End;
Procedure TForm1.FormCreate(Sender: TObject);
Begin
With pfd Do
Begin
nSize := SizeOf(TPIXELFORMATDESCRIPTOR); // 格式描述符大小
nVersion := 1; // 版本号
dwFlags := PFD_DRAW_TO_WINDOW // 格式必须支持窗口
Or PFD_SUPPORT_OPENGL // 格式必须支持OpenGL
Or PFD_DOUBLEBUFFER; // 必须支持双缓冲
iPixelType := PFD_TYPE_RGBA; // 申请 RGBA 格式
//cColorBits := PixelDepth; // 选定色彩深度
cRedBits := 0; // 忽略的色彩位
cRedShift := 0; // 忽略的色彩位
cGreenBits := 0; // 忽略的色彩位
cGreenShift := 0; // 忽略的色彩位
cBlueBits := 0; // 忽略的色彩位
cBlueShift := 0; // 忽略的色彩位
cAlphaBits := 0; // 无Alpha缓存
cAlphaShift := 0; // 忽略Shift Bit
cAccumBits := 0; // 无聚集缓存
cAccumRedBits := 0; // 忽略聚集位
cAccumGreenBits := 0; // 忽略聚集位
cAccumBlueBits := 0; // 忽略聚集位
cAccumAlphaBits := 0; // 忽略聚集位
cDepthBits := 16; // 16位 Z-缓存 (深度缓存)
cStencilBits := 0; // 无模板缓存
cAuxBuffers := 0; // 无辅助缓存
iLayerType := PFD_MAIN_PLANE; // 主绘图层
bReserved := 0; // 保留
dwLayerMask := 0; // 忽略层遮罩
dwVisibleMask := 0; // 忽略层遮罩
dwDamageMask := 0; // 忽略层遮罩
End;
h_DC := GetDC(self.Handle);
PixelFormat := ChoosePixelFormat(h_DC, @pfd);
SetPixelFormat(h_DC, PixelFormat, @pfd);
h_RC := wglCreateContext(h_DC);
wglMakeCurrent(h_DC, h_RC);
glResizeWnd(Width, Height); // 设置透视 GL 屏幕
glInit(); // 初始化新建的GL窗口
End;Procedure startdraw;
Var
msg : TMsg; // Windowsx消息结构
finished : Boolean; // 用来退出循环的Bool 变量
Begin
finished := False;
While Not finished Do
If (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) Then //检查是否有消息
Begin
If (msg.message = WM_QUIT) Then // 如果是退出消息
finished := True //改变循环条件,退出
Else
Begin // 否则处理消息
TranslateMessage(msg); //翻译消息
DispatchMessage(msg); //发送消息
End;
End
Else //如果没有消息,绘制我们的OpenGL场景。
Begin
glDraw(); // 重画屏幕
SwapBuffers(h_DC); // 交换缓存 (双缓存)
If (keys[VK_ESCAPE]) Then // 如果按下了ESC键
finished := True
End;
Application.Terminate;
End;
Procedure TForm1.Timer1Timer(Sender: TObject);
Begin
startdraw;
Timer1.Enabled := false;
End;
End.
运行一下看看效果 :)这样就不用麻烦他们了,呵呵,下班了
谢谢~不过,我要的不是着效果的“多个”OpenGL显示
我要的是在一个窗口中,有两个或多个Panel做为显示“窗口”
h_DC := GetDC(self.Handle);
换成
h_DC := GetDC(Panel1.Handle);就搞定了!
——————————————————————
把这句
h_DC := GetDC(self.Handle);
换成
h_DC := GetDC(Panel1.Handle);
——————————————————————
不还是都在一个地方显示嘛~
我要的是在多个“Panel”里现实!
这是我找的一个控件,是“品雪”的看上去挺简单的,可是我拿咱们的方法往上套就是不行!
:(
gluPerspective(45.0, ClientWidth/ClientHeight,1,500);//能够定义一个以Z轴为中线的四棱台视景体.
glOrtho(-1, 1, -1, 1, -1, 50); //用投影矩阵操纵当前矩阵;虽然没有深入了解,可是看了些文档改了几个方法,搞定了!
可以使了!可是怎么做Zoom涅?!怎么做可以选择Zoom区域的?!
:)
就是用鼠标圈选区域放大!?
向正方向移动z轴就行了吧?
根据鼠标up和down的坐标,和当前屏幕斜角的顶点坐标,
比上现在z轴的距离,能求出移动的距离吧?
这个玩艺应该是立体几何的东东吧?
没做过,瞎说的磁效应:
呵呵。我的业余生活还比较闲,有东西写当然好了!
但是俺现在这个水平…… 哈,够呛呀,还是先好好学学吧,有什么想法QQ联系
{贴图可以极大的节省CPU时间。呵呵,但是这一节费了我比较多的时间 : (因为用到了opengl的辅助库,现在这个库的函数已经很少有人用了,但是我还是找到了,感谢zdcnow(磁效应),他给我提供的这个辅助库的delphi版本。在学习本节之前,请大家到网上下载glaux.dll、Glaux.pas文件,并加到项目中。好了,让我们继续OPENGL之路.首先我们需要加进SysUtils单元,因为我们这节要用到文件操作,我们还要将Glaux单元加进来。然后我们在第一课的基础上加上几个变量,xrot , yrot 和 zrot 。这些变量用来使立方体绕X、Y、Z轴旋转。texture[] 为一个纹理分配存储空间。如果您需要不止一个的纹理,应该将数字1改成您所需要的数字。}VAR h_RC : HGLRC; // Rendering Context(着色描述表)。
h_DC : HDC; // Device Context(设备描述表)
h_Wnd : HWND; // 窗口句柄
h_Instance : HINST; // 程序Instance(实例)。
keys : Array[0..255] Of Boolean; // 用于键盘例程的数组 xrot, // X 旋转量 ( 新增 )
yrot, // Y 旋转量 ( 新增 )
zrot : GLfloat; // Z 旋转量 ( 新增 ) Texture : Array[0..1] Of GLuint; // 存储一个纹理 ( 新增 ){然后引载入opengl32.dll中的两个过程,我们要用到他们}
Procedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
opengl32;
Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
opengl32;{接下来我们需要增加一个新的函数,用来再入图像,该函数的返回类型在Glaux.pas中定义如下:TAUX_RGBImageRec= record
sizeX, sizeY: GLint;
data: pointer;
end;
PTAUX_RGBImageRec= ^TAUX_RGBImageRec;具体含义会在后面介绍}Function LoadBmp(filename: pchar): PTAUX_RGBImageRec;
Var
BitmapFile : Thandle; // 文件句柄
Begin
//接下来检查文件名是否已提供
If Filename = '' Then // 确保文件名已提供。
result := Nil; // 如果没提供,返回 NULL
//接着检查文件是否存在。
BitmapFile := FileOpen(Filename, fmOpenWrite); //尝试打开文件
//如果我们能打开文件的话,很显然文件是存在的。 If BitmapFile > 0 Then // 文件存在么?
Begin
//关闭文件。
FileClose(BitmapFile); // 关闭句柄
//auxDIBImageLoad(Filename) 读取图象数据并将其返回。
result := auxDIBImageLoadA(filename); //载入位图并返回指针
End
Else
//如果我们不能打开文件,我们将返回NiL。
result := Nil; // 如果载入失败,返回NiL。
End;
// Status 缺省设为 FALSE (表示没有载入或创建任何东东)。
//TextureImage变量PTAUX_RGBImageRec类型 存储位图的图像记录。
//次记录包含位图的宽度、高度和数据。Var
Status : boolean;
TextureImage : Array[0..1] Of PTAUX_RGBImageRec;
Begin
Status := false;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // 将指针设为 NULL
TextureImage[0] := LoadBMP('Texture.bmp');
If TextureImage[0] <> Nil Then
Begin
Status := TRUE; // 将 Status 设为 TRUE
//现在使用中 TextureImage[0] 的数据创建纹理。
//glGenTextures(1, texture[0]) 告诉OpenGL我们想生成一个纹理名字
//(如果您想载入多个纹理,加大数字)。
//glBindTexture(GL_TEXTURE_2D, texture[0]) 告诉OpenGL将纹理名字 texture[0] 绑定到纹理目标上。
//2D纹理只有高度(在 Y 轴上)和宽度(在 X 轴上)。
//主函数将纹理名字指派给纹理数据。
//本例中我们告知OpenGL, &texture[0] 处的内存已经可用。
//我们创建的纹理将存储在 &texture[0] 的 指向的内存区域。
glGenTextures(1, texture[0]); // 创建纹理
glBindTexture(GL_TEXTURE_2D, texture[0]); // 使用来自位图数据生成 的典型纹理
//下来我们创建真正的纹理。
//下面一行告诉OpenGL此纹理是一个2D纹理 ( GL_TEXTURE_2D )。
//数字零代表图像的详细程度,通常就由它为零去了。
//数字三是数据的成分数。因为图像是由红色数据,绿色数据,蓝色数据三种组分组成。
//TextureImage[0].sizeX 是纹理的宽度。
//如果您知道宽度,您可以在这里填入,但计算机可以很容易的为您指出此值。
// TextureImage[0].sizey 是纹理的高度。
//数字零是边框的值,一般就是零。
// GL_RGB 告诉OpenGL图像数据由红、绿、蓝三色数据组成。
//GL_UNSIGNED_BYTE 意味着组成图像的数据是无符号字节类型的。
//最后... TextureImage[0].data 告诉OpenGL纹理数据的来源。
//此例中指向存放在 TextureImage[0] 记录中的数据。 // 生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data); //下面的两行告诉OpenGL在显示图像时,
//当它比放大得原始的纹理大(GL_TEXTURE_MAG_FILTER)
//或缩小得比原始得纹理小(GL_TEXTURE_MIN_FILTER)时OpenGL采用的滤波方式。
//通常这两种情况下我都采用 GL_LINEAR。这使得纹理从很远处到离屏幕很近时都平滑显示。
//使用 GL_LINEAR需要CPU和显卡做更多的运算。
//如果您的机器很慢,您也许应该采用 GL_NEAREST 。
//过滤的纹理在放大的时候,看起来斑驳的很(马赛克啦)。
//您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 线形滤波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 线形滤波
End;
//现在我们释放前面用来存放位图数据的内存。
//我们先查看位图数据是否存放在处。
//如果是的话,再查看数据是否已经存储。
//如果已经存储的话,删了它。
//接着再释放 TextureImage[0] 图像结构以保证所有的内存都能释放。
If assigned(TextureImage[0]) Then // 纹理是否存在
If assigned(TextureImage[0].data) Then // 纹理图像是否存在
TextureImage[0].data := Nil; // 释放纹理图像占用的内存
TextureImage[0] := Nil; // 释放图像结构
// 最后返回状态变量。如果一切OK,变量 Status 的值为 TRUE 。否则为 FALSE
result := Status; // 返回 Status
End;
//然后在 glInit 中增加很少的几行代码Procedure glInit();
Begin
If (Not LoadTexture) Then // 调用纹理载入子例程( 新增 )
exit; // 如果未能载入,退出( 新增 )
glEnable(GL_TEXTURE_2D); // 启用纹理映射( 新增 )
glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正End;
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
glTranslatef(0.0, 0.0, -6.0); // 移入屏幕6个单位 //下面三行使立方体绕X、Y、Z轴旋转。
//旋转多少依赖于变量 xrot , yrot 和 zrot 的值。
glRotatef(xrot, 1.0, 0.0, 0.0); // 绕X轴旋转
glRotatef(yrot, 0.0, 1.0, 0.0); // 绕Y轴旋转
glRotatef(zrot, 0.0, 0.0, 1.0); // 绕Z轴旋转 //下一行代码选择我们使用的纹理。
//如果在场景中使用多个纹理,应该使用
//glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 来选择要绑定的纹理。
//当想改变纹理时,应该绑定新的纹理。
//有一点值得指出的是,
//不能在 glBegin() 和 glEnd() 之间绑定纹理,
//必须在 glBegin() 之前或 glEnd() 之后绑定。
//注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。 glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理 //为了将纹理正确的映射到四边形上,
//必须将纹理的右上角映射到四边形的右上角,
//纹理的左上角映射到四边形的左上角,
//纹理的右下角映射到四边形的右下角,
//纹理的左下角映射到四边形的左下角。
//如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。 //glTexCoord2f 的第一个参数是X坐标。
// 0.0是纹理的左侧。 0.5是纹理的中点, 1.0是纹理的右侧。
//glTexCoord2f 的第二个参数是Y坐标。
//0.0是纹理的底部。 0.5是纹理的中点, 1.0是纹理的顶部。
//所以纹理的左上坐标是 X:0.0f,Y:1.0f ,
//四边形的左上顶点是 X: -1.0f,Y:1.0f 。
//其余三点依此类推。 //试着玩玩 glTexCoord2f 的X,Y坐标参数。
//把1.0改为0.5将只显示纹理的左半部分,
//把0.0改为0.5将只显示纹理的右半部分。
glBegin(GL_QUADS);
// 前面
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的左上
// 后面
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // 纹理和四边形的左下
// 顶面
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); // 纹理和四边形的右上
// 底面
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, -1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的右下
// 右面
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 纹理和四边形的左下
// 左面
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的左上
glEnd(); xrot := xrot + 0.3; // X 轴旋转
yrot := yrot + 0.2; // Y 轴旋转
zrot := zrot + 0.4; // Z 轴旋转
End;{最后,关于用作纹理的图像我想有几点十分重要,并且您必须明白。此图像的宽和高必须是2的n次方;宽度和高度最小必须是64象素;并且出于兼容性的原因,图像的宽度和高度不应超过256象素。如果您的原始素材的宽度和高度不是64,128,256象素的话,使用图像处理软件重新改变图像的大小。可以肯定有办法能绕过这些限制,但现在我们只需要用标准的纹理尺寸。}//OK!运行一下看看效果
http://www.csdn.net/Develop/read_article.asp?id=20029
http://www.csdn.net/Develop/read_article.asp?id=20031
http://www.csdn.net/Develop/read_article.asp?id=20039
http://www.csdn.net/Develop/read_article.asp?id=20109
http://www.csdn.net/Develop/read_article.asp?id=20165一共六课,还会继续贴的
可不可以把你上边发的好长的代码的程序给我一个啊`
我运行了~
可是什么效果没有啊~
555555555555~~~~~~~~~~~
我很想学习OPENGL啊~
[email protected]
var
pDC: HDC;
begin // It's simple, really:
pDC := GetDC(GLPanel1.Handle);
CgDC1 := TCGDeviceContext.Create(pDC);
CgDC1.InitGL;
glEnable(GL_DEPTH_TEST); // Note that each DC you create has its own OpenGL state variables!
pDC := GetDC(GLPanel2.Handle);
CgDC2 := TCGDeviceContext.Create(pDC);
CgDC2.InitGL;
glEnable(GL_DEPTH_TEST);end;procedure TPForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin CgDC1.Free;
CgDC2.Free;end;procedure TPForm.FormPaint(Sender: TObject);
begin // Just draw something...
CgDC1.MakeCurrent;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
glRotatef(a, 1, 2, 3);
glutWireTorus(0.2, 0.4, 16, 32);
CgDC1.PageFlip; // And to the second panel as well...
CgDC2.MakeCurrent;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
glRotatef(-a, 1, 2, 3);
glBegin(GL_TRIANGLES);
glColor3f(1, 0, 0); glVertex2f(-0.5, -0.5);
glColor3f(0, 1, 0); glVertex2f(0.5, -0.5);
glColor3f(0, 0, 1); glVertex2f(0, 0.5);
glEnd;
CgDC2.PageFlip;end;procedure TPForm.TimerTimer(Sender: TObject);
begin a := (a+1) mod 360;
Paint;end;procedure TPForm.SplitterMoved(Sender: TObject);
begin // Resize the viewports. Also called when the form resizes.
{ The splitter is set to rsUpdate, so it repaints whenever you drag it. This
causes a lot of flicker, so set it to rsPattern if you get a migraine. }
CgDC1.MakeCurrent;
glViewport(0, 0, GLPanel1.Width, GLPanel1.Height);
CgDC2.MakeCurrent;
glViewport(0, 0, GLPanel2.Width, GLPanel2.Height);end;procedure TPForm.SplitterCanResize(Sender: TObject; var NewSize: Integer;
var Accept: Boolean);
begin // Keep the splitter from snapping to the left edge of the form.
Accept := not (NewSize <= 31);end;