编写 OpenGL 程序的基本步骤 之 半透明效果(0分)

  • 主题发起人 小雨哥
  • 开始时间

小雨哥

Unregistered / Unconfirmed
GUEST, unregistred user!
{***************************************************************
* Name : Project6.dpr
* Purpose : 解释编写基本 OpenGL 程序的步骤及其程序的一般结构
* Author : 小雨哥 by 2003.1.12 DFW
* History : 绘制旋转的一个立体三角和一个立方体并着色并透明
***************************************************************}
program Project6;
uses
Windows, Messages, OpenGL;

{--------------------------------------------------------------}
{ 下面定义一些全局变量 }
{--------------------------------------------------------------}
const
WND_TITLE = 'OpenGL First Transparence Rotation 3D'; // 窗口标题
var
h_Wnd : HWND; // 本程序的窗口句柄
h_DC : HDC; // 设备描述表
h_RC : HGLRC; // 着色描述表
keys : Array[0..255] of Boolean; // 监控键盘动作的数组
active:Boolean; // 窗口活动标志
fullscreen:Boolean; // 全屏幕标志
rtri,rquad:GLfloat; // 控制三角形和四边型的旋转角度
TRIANGLES_Z, // 控制三角前后移动
QUADS_Z, // 控制立方前后移动
Axis_X:GLfloat; // 控制整体左右移动
Transparence:Boolean; // 控制是否打开透明选项

// {$R *.RES}

{--------------------------------------------------------------}
{ 下面代码的作用是当窗口大小变化时重新设置 OpenGL 场景的大小 }
{--------------------------------------------------------------}
procedure glResizeWnd(Width, Height : Integer);
begin
if (Height = 0) then // 防止在设置透视时被 0 除
Height := 1; // 将 Height 设为 1
glViewport(0, 0, Width, Height); // 重置当前的视口
glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵
gluPerspective(45.0, Width/Height, 1.0, 100.0); // 安排透视。按 45 度透视角记算,1.0
// 和 100.0 是场景中所能绘制深度的起点和终点
glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
end;

{--------------------------------------------------------------}
{ 窗口过程。响应和处理所有的窗口消息 }
{--------------------------------------------------------------}
function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result := 0;
case (Msg) of
WM_CREATE:
begin
// 窗口创建时需要执行的代码可以放在这里
end;
WM_ACTIVATE:
begin
if (LOWORD(wParam)=WA_INACTIVE) or (HIWORD(wParam)<>0) then // 窗口不是活动的或窗口是最小化的
active:=FALSE
else
active:=True;
end;
WM_CLOSE:
begin
PostQuitMessage(0);
Result := 0
end;
WM_KEYDOWN: // 当键盘按下时,以 WParam 值做下标,填写 keys 数组,标识按下了哪个键
begin
keys[wParam] := True;
Result := 0;
end;
WM_KEYUP: // 当键盘释放时,将 WParam 值为下标的 keys 数组单元复位
begin
keys[wParam] := False;
Result := 0;
end;
WM_SIZE: // 缩放窗口后需要对 OpenGL 进行一些初始化
begin
glResizeWnd(LOWORD(lParam),HIWORD(lParam));
Result := 0;
end;
else
Result := DefWindowProc(hWnd, Msg, wParam, lParam);
end;
end;

{--------------------------------------------------------------}
{ 下面的代码将对 OpenGL 进行所有的初始化处理 }
{--------------------------------------------------------------}
procedure glInit();
begin
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.5, 0.0, 0.0, 0.0); // 设置清除屏幕所用的颜色(红,绿,蓝,Alpha)
glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉 OpenGL 作精细的透视修正

glBlendFunc(GL_SRC_ALPHA,GL_ONE); // 基于源象素 Alpha 通道值的半透明混合函数
end;

{--------------------------------------------------------------}
{ OpenGL 所有的绘图处理,其实都在下面 }
{--------------------------------------------------------------}
procedure glDraw();
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵

glTranslatef(Axis_X-1.7,0.0,TRIANGLES_Z); // 左移 1.7 单位,并移入屏幕 -7.0 决定的值

// glRotatef(rtri,0.0,1.0,0.0); // 绕Y轴旋转三角形
glRotatef(rtri,1.0,0.5,-1.0); // 在各个轴旋转三角形

glBegin(GL_TRIANGLES); // 绘制三角形 (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, 1.0); // 三角形的左下顶点 (前侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f( 1.0,-1.0, 1.0); // 三角形的右下顶点 (前侧面)

glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (右侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f( 1.0,-1.0, 1.0); // 三角形的左下顶点 (右侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f( 1.0,-1.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, -1.0); // 三角形的左下顶点 (后侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f(-1.0,-1.0, -1.0); // 三角形的右下顶点 (后侧面)

glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (左侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f(-1.0,-1.0,-1.0); // 三角形的左下顶点 (左侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f(-1.0,-1.0, 1.0); // 三角形的右下顶点 (左侧面)
glEnd(); // 三角形绘制结束

glLoadIdentity(); // 重置模型观察矩阵,将画三角时改变的坐标复位
glTranslatef(Axis_X+1.7,0.0,QUADS_Z); // 右移1.7单位,并移入屏幕 8.0,比三角形移动多一点以保持视觉
// glRotatef(rquad,1.0,1.0,1.0); // 绕在XYZ轴上旋转立方体
glRotatef(rquad,1.0,0.5,1.0); // 在各个轴上旋转立方体

glBegin(GL_QUADS); // 绘制正方形 (GL_QUADS 画法:必须是四个顶点为一组地画)
glColor3f(0.0,1.0,0.0); // 颜色改为蓝色
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右上顶点 (顶面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左上顶点 (顶面)
glVertex3f(-1.0, 1.0, 1.0); // 四边形的左下顶点 (顶面)
glVertex3f( 1.0, 1.0, 1.0); // 四边形的右下顶点 (顶面)

glColor3f(1.0,0.5,0.0); // 颜色改成橙色
glVertex3f( 1.0,-1.0, 1.0); // 四边形的右上顶点(底面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的左上顶点(底面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左下顶点(底面)
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右下顶点(底面)

glColor3f(1.0,0.0,0.0); // 颜色改成红色
glVertex3f( 1.0, 1.0, 1.0); // 四边形的右上顶点(前面)
glVertex3f(-1.0, 1.0, 1.0); // 四边形的左上顶点(前面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的左下顶点(前面)
glVertex3f( 1.0,-1.0, 1.0); // 四边形的右下顶点(前面)

glColor3f(1.0,1.0,0.0); // 颜色改成黄色
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右上顶点(后面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左上顶点(后面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左下顶点(后面)
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右下顶点(后面)

glColor3f(0.0,0.0,1.0); // 颜色改成蓝色
glVertex3f(-1.0, 1.0, 1.0); // 四边形的右上顶点(左面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左上顶点(左面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左下顶点(左面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的右下顶点(左面)

glColor3f(1.0,0.0,1.0); // 颜色改成紫罗兰色
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右上顶点(右面)
glVertex3f( 1.0, 1.0, 1.0); // 四边形的左上顶点(右面)
glVertex3f( 1.0,-1.0, 1.0); // 四边形的左下顶点(右面)
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右下顶点(右面)
glEnd(); // 正方形绘制结束

rtri:=rtri+3; // 增加三角形的旋转变量
rquad:=rquad-4.5; // 减少四边形的旋转变量
end;

{--------------------------------------------------------------}
{ 销毁 OpenGL 占用的资源和程序窗口,防止内存泄露 }
{--------------------------------------------------------------}
procedure glKillWnd(Fullscreen : Boolean);
begin
if Fullscreen then // 检查是否处于全屏模式
begin
ChangeDisplaySettings(devmode(nil^), 0); // 是的话,切换回桌面
ShowCursor(True); // 显示鼠标指针
end;

if (not wglMakeCurrent(h_DC, 0)) then // 可以释放着色描述表和设备描述表吗
MessageBox(0, '释放 DC 和 RC 失败', 'Error', MB_OK or MB_ICONERROR);

if (not wglDeleteContext(h_RC)) then // 能删除着色描述表吗
begin
MessageBox(0, '释放 rendering context (RC) 失败', 'Error', MB_OK or MB_ICONERROR);
h_RC := 0; // 将着色描述表设为 0
end;

if ((h_DC = 1) and (ReleaseDC(h_Wnd, h_DC) <> 0)) then // 能释放设备描述表吗
begin
MessageBox(0, '释放 device context (DC) 失败', 'Error', MB_OK or MB_ICONERROR);
h_DC := 0; // 将设备描述表设为 0
end;

if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then // 能销毁窗口吗
begin
MessageBox(0, '不能销毁窗口', 'Error', MB_OK or MB_ICONERROR);
h_Wnd := 0; // 将窗口设为 0
end;

if (not UnRegisterClass('OpenGL', hInstance)) then // 能注销窗口类吗
begin
MessageBox(0, '不能注销窗口类', 'Error', MB_OK or MB_ICONERROR);
hInstance := 0; // 将 hInstance 设为 0
end;
end;

{--------------------------------------------------------------}
{ 创建程序窗口和进行 OpenGL 设置 }
{--------------------------------------------------------------}
function glCreateWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean;
var
wndClass : TWndClass;
dwStyle : DWORD;
dwExStyle : DWORD;
dmScreenSettings : DEVMODE;
PixelFormat : GLuint;
h_Instance : HINST;
pfd : TPIXELFORMATDESCRIPTOR;
begin
h_Instance := GetModuleHandle(nil); // 取得窗口的实例
ZeroMemory(@wndClass, SizeOf(wndClass)); // 清除原有的窗口类内容

with wndClass do // 填充窗口类的内容
begin
style := CS_HREDRAW or // 无论何时只要窗口发生变化时就强制重画
CS_VREDRAW or // 无论何时只要窗口发生变化时就强制重画
CS_OWNDC; // 意味着 DC 不能在程序间共享
lpfnWndProc := @WndProc; // 窗口过程以处理消息
hInstance := h_Instance; // 设置实例
hCursor := LoadCursor(0, IDC_ARROW); // 装入鼠标指针
lpszClassName := 'OpenGL'; // 设定类名字
end;

if (RegisterClass(wndClass) = 0) then // 尝试注册窗口类
begin
MessageBox(0, '注册窗口类失败', 'Error', 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 or DM_PELSHEIGHT or DM_BITSPERPEL; // 指明有效域
end;

if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) = DISP_CHANGE_FAILED) then // 尝试设置显示模式并返回结果
begin
MessageBox(0, '无法切换为全屏幕显示', 'Error', MB_OK or MB_ICONERROR);
Fullscreen := False;
end;
end;

if (Fullscreen) then // 仍处于全屏模式吗
begin // 下面的窗口风格在全屏幕时使用
dwStyle := WS_POPUP or // 弹出式
WS_CLIPCHILDREN // OpenGL 程序,必须要有这个风格
or WS_CLIPSIBLINGS; // OpenGL 程序,必须要有这个风格
dwExStyle := WS_EX_APPWINDOW; // 顶级窗体风格
ShowCursor(False); // 隐藏鼠标指针
end
else // 下面的窗口风格在非全屏幕时使用
begin
dwStyle := WS_OVERLAPPEDWINDOW or // 普通窗口
WS_CLIPCHILDREN or // OpenGL 程序,必须要有这个风格
WS_CLIPSIBLINGS; // OpenGL 程序,必须要有这个风格
dwExStyle := WS_EX_APPWINDOW or // 顶级窗体风格
WS_EX_WINDOWEDGE; // 有边框
end;

// 下面创建实际的程序窗口
h_Wnd := CreateWindowEx(dwExStyle, // 窗口的扩展风格
'OpenGL', // 窗口类名
WND_TITLE, // 窗口标题
dwStyle, // 窗口风格
0, 0, // 窗口位置
Width, Height, // 窗口大小
0, // 没有父窗口
0, // 没有菜单
h_Instance, // Instance
nil);
if h_Wnd = 0 then // 检查窗口是否正常创建
begin
glKillWnd(Fullscreen); // 清除所有已经建立的对象
MessageBox(0, '不能创建窗口', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

// 试着取得 DC
h_DC := GetDC(h_Wnd);
if (h_DC = 0) then
begin
glKillWnd(Fullscreen);
MessageBox(0, '不能取得 device context (DC)', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

// 下面设置 OpenGL 的内容
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; // 选定 OpenGL 色彩深度
cRedBits := 0; // 红色彩位
cRedShift := 0; // 忽略红色彩位
cGreenBits := 0; // 绿色彩位
cGreenShift := 0; // 忽略绿色彩位
cBlueBits := 0; // 蓝色彩位
cBlueShift := 0; // 忽略蓝色彩位
cAlphaBits := 0; // 不支持 Alpha 位
cAlphaShift := 0; // 忽略 Alpha 位
cAccumBits := 0; // 无积聚缓存
cAccumRedBits := 0; // 忽略红积聚缓存
cAccumGreenBits := 0; // 忽略绿积聚缓存
cAccumBlueBits := 0; // 忽略蓝积聚缓存
cAccumAlphaBits := 0; // 忽略 Alpha 积聚缓存
cDepthBits := 16; // 确定 16位 Z-缓存 (深度缓存)
cStencilBits := 0; // 无模板缓存
cAuxBuffers := 0; // 无辅助缓存
iLayerType := PFD_MAIN_PLANE; // 主绘图层
bReserved := 0; // 保留
dwLayerMask := 0; // 忽略遮罩层
dwVisibleMask := 0; // 忽略透明色
dwDamageMask := 0; // 忽略 Damage 遮罩层
end;

PixelFormat := ChoosePixelFormat(h_DC, @pfd); // 系统找到相应的象素格式了吗
if (PixelFormat = 0) then
begin
glKillWnd(Fullscreen);
MessageBox(0, '找不到相配的象素格式', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then // 设置象素格式
begin
glKillWnd(Fullscreen);
MessageBox(0, '无法设置到指定的象素格式', 'Error', 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 着色描述表', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

if (not wglMakeCurrent(h_DC, h_RC)) then // 尝试激活着色描述表
begin
glKillWnd(Fullscreen);
MessageBox(0, '无法激活 OpenGL 着色描述表', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

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;
Done : Boolean;
begin
Done := False;
if (MessageBox(0,'希望运行在全屏幕模式?', 'Start FullScreen?',MB_YESNO or MB_ICONQUESTION))=IDYES then
fullscreen:=True;

if not glCreateWnd(640,480,fullscreen, 32) then
begin
Result := 0;
Exit;
end;

{ 其他需要初始化项目,如声音等,可以放在这个位置 }

// 下面进入主消息循环
while not Done do
begin
if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // 选择属于自己的消息
begin
if (keys[VK_ESCAPE]) then // ESC 键按下了吗
Done := True;

if (keys[VK_F4]) then // F4 键按下了吗(允许使用 F4 键在全屏模式和窗口模式间切换)
begin
keys[VK_F4]:=False; // 使对应的 Keys 数组中的值为 FALSE
glKillWnd(fullscreen); // 销毁当前的窗口
fullscreen:=not fullscreen; // 切换 全屏/窗口 模式
if not glCreateWnd(640,480,fullscreen, 32) then // 重建 OpenGL 窗口
begin
Result := 0;
Exit;
end;
end;

if (keys[VK_UP]) then // 前后移动三角
TRIANGLES_Z:=TRIANGLES_Z-0.5;
if (keys[VK_DOWN]) then
TRIANGLES_Z:=TRIANGLES_Z+0.5;

if (keys[VK_PRIOR]) then // 前后移动立方
QUADS_Z:=QUADS_Z-0.5;
if (keys[VK_NEXT]) then
QUADS_Z:=QUADS_Z+0.5;

if (keys[VK_LEFT]) then // 整体左右移动
Axis_X:=Axis_X-0.2;
if (keys[VK_RIGHT]) then
Axis_X:=Axis_X+0.2;

if (keys[Ord('R')]) then // 使各轴复位
begin
TRIANGLES_Z:=-7.0;
QUADS_Z:=-8.0;
Axis_X:=0.0;
end;

if (keys[Ord('T')]) then // 控制透明与否
begin
keys[Ord('T')]:=False;
Transparence:=not Transparence;
if Transparence then
glEnable(GL_BLEND) // 打开透明选项
else glDisable(GL_BLEND); // 关闭透明选项
end;

{ 其他键盘控制代码可以放在这个位置 }

if (msg.message = WM_QUIT) then // 是退出命令
Done := True
else
begin // 进入消息循环
TranslateMessage(msg);
DispatchMessage(msg);
end;
end
else
if active then
begin
glDraw; // 绘制场景
SwapBuffers(h_DC); // 将绘好的画面显示出来(交换缓存)
end
else
begin
SwapBuffers(h_DC); // 重绘非活化时的窗口内容
WaitMessage;
end;
end; // 结束 while 循环

glKillWnd(fullscreen);
Result := msg.wParam;
end;

{--------------------------------------------------------------}
{ 程序开始 }
{--------------------------------------------------------------}
begin
TRIANGLES_Z:=-7.0;
QUADS_Z:=-8.0;
Axis_X:=0.0;
WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.

上面的代码,保存为 Project6.dpr ,使用 Delphi5 编译并执行。
其中各按键的作用如下:
Esc : 关闭程序
F4 : 切换 全屏幕/窗口 显示模式
R : 使各个三维轴恢复到初始状态
PageUP : 控制立方体向屏幕内移动
PageDown:控制立方体向屏幕外移动
箭头上 : 控制三角体向屏幕内移动
箭头下 : 控制三角体向屏幕外移动
箭头左 : 画面整体向左移动
箭头右 : 画面整体向右移动
T : 控制打开和关闭半透明效果
=========================================================================
原始问题链接:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1590427
 
呵呵,有空聊聊,我做过一年的OpengGL!
 
TO:爱元元的哥哥
我在 http://www.delphibbs.com/delphibbs/dispq.asp?lid=1590427 有邮件地址,
有空给我来信。
 

Similar threads

I
回复
0
查看
721
import
I
I
回复
0
查看
632
import
I
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
560
import
I
顶部