用opengl画下图中的三角形

先画一个红的大三角,再画中间白的,然后用递归,高手可以帮帮我吗
freshguy2008:我用2008,结果有好多错误啊,而且好复杂,有写得简单的吗?

//编译环境VS2005 选WIN32应用程序, 我从来不用MFC 

#include <GL/GL.h> 

#include <gl/GLU.h> 

#include <gl/GLAux.h> 

#include <math.h> 

#pragma comment(lib, "opengl32.lib") 

#pragma comment(lib, "glu32.lib") 

#pragma comment(lib, "glaux.lib") 

#define MAX_LOADSTRING 100 

//定义递归调用阀值,即其中最小三角形边长 

#define SIDELENGHT (0.05) 

// Global Variables: 

HINSTANCE hInst; // current instance 

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text 

TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 

//自定义全局变量 

HGLRC g_hRC = NULL; //OpenGL 绘图上下文 

HDC g_hDC = NULL; //设备上下文 

HWND g_hWnd = NULL; //保存当前窗口句柄 

//定义三角形顶点指针 

typedef struct tagTRIANGLEPOINT 

GLfloat tpPointX; 

GLfloat tpPointY; 

}TRIANGLEPOINT,*LTRIANGLEPOINT; 

//定义最外面大三角形三个点 

TRIANGLEPOINT g_TrianglePoint[3] = {{0.0, 0.0}, {5.0, 0.0}, {2.5,2.5}}; 

// Forward declarations of functions included in this code module: 

ATOM MyRegisterClass(HINSTANCE hInstance); 

BOOL InitInstance(HINSTANCE, int); 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 

//自定义函数 

void EnableOpenGL(HWND hWnd); 

void SceneInit(); 

void SceneResizeViewport(); 

void DisableOpenGL(); 

void Display(); 

void DrawTriangle(LTRIANGLEPOINT pTrianglePoint, int iPointNum = 3); 

void DrawLargeTriangle(LTRIANGLEPOINT pTrianglePoint, int iPointNum); 

int APIENTRY _tWinMain(HINSTANCE hInstance, 

HINSTANCE hPrevInstance, 

LPTSTR lpCmdLine, 

int nCmdShow) 

UNREFERENCED_PARAMETER(hPrevInstance); 

UNREFERENCED_PARAMETER(lpCmdLine); 

// TODO: Place code here. 

MSG msg; 

HACCEL hAccelTable; 

// Initialize global strings 

LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 

LoadString(hInstance, IDC_OPENGLTRIANGLE, szWindowClass, MAX_LOADSTRING); 

MyRegisterClass(hInstance); 

// Perform application initialization: 

if (!InitInstance (hInstance, nCmdShow)) 

return FALSE; 

EnableOpenGL(g_hWnd); 

SceneInit(); 

SceneResizeViewport(); 

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OPENGLTRIANGLE)); 

// Main message loop: 

ZeroMemory(&msg, sizeof(msg)); 

while ( msg.message != WM_QUIT ) 

if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) 

if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 

TranslateMessage(&msg); 

DispatchMessage(&msg); 

else 

Display(); 

SwapBuffers(g_hDC); 

DisableOpenGL(); 

return (int) msg.wParam; 

// 

// FUNCTION: MyRegisterClass() 

// 

// PURPOSE: Registers the window class. 

// 

// COMMENTS: 

// 

// This function and its usage are only necessary if you want this code 

// to be compatible with Win32 systems prior to the 'RegisterClassEx' 

// function that was added to Windows 95. It is important to call this function 

// so that the application will get 'well formed' small icons associated 

// with it. 

// 

ATOM MyRegisterClass(HINSTANCE hInstance) 

WNDCLASSEX wcex; 

wcex.cbSize = sizeof(WNDCLASSEX); 

wcex.style = CS_HREDRAW | CS_VREDRAW; 

wcex.lpfnWndProc = WndProc; 

wcex.cbClsExtra = 0; 

wcex.cbWndExtra = 0; 

wcex.hInstance = hInstance; 

wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OPENGLTRIANGLE)); 

wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 

wcex.lpszMenuName = MAKEINTRESOURCE(IDC_OPENGLTRIANGLE); 

wcex.lpszClassName = szWindowClass; 

wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 

return RegisterClassEx(&wcex); 

// 

// FUNCTION: InitInstance(HINSTANCE, int) 

// 

// PURPOSE: Saves instance handle and creates main window 

// 

// COMMENTS: 

// 

// In this function, we save the instance handle in a global variable and 

// create and display the main program window. 

// 

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 

HWND hWnd; 

hInst = hInstance; // Store instance handle in our global variable 

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 

if (!hWnd) 

return FALSE; 

g_hWnd = hWnd; 

ShowWindow(hWnd, nCmdShow); 

UpdateWindow(hWnd); 

return TRUE; 

// 

// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 

// 

// PURPOSE: Processes messages for the main window. 

// 

// WM_COMMAND - process the application menu 

// WM_PAINT - Paint the main window 

// WM_DESTROY - post a quit message and return 

// 

// 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 

int wmId, wmEvent; 

PAINTSTRUCT ps; 

HDC hdc; 

switch (message) 

case WM_COMMAND: 

wmId = LOWORD(wParam); 

wmEvent = HIWORD(wParam); 

// Parse the menu selections: 

switch (wmId) 

case IDM_ABOUT: 

DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 

break; 

case IDM_EXIT: 

DestroyWindow(hWnd); 

break; 

default: 

return DefWindowProc(hWnd, message, wParam, lParam); 

break; 

case WM_PAINT: 

hdc = BeginPaint(hWnd, &ps); 

// TODO: Add any drawing code here... 

EndPaint(hWnd, &ps); 

break; 

case WM_DESTROY: 

PostQuitMessage(0); 

break; 

default: 

return DefWindowProc(hWnd, message, wParam, lParam); 

return 0; 

// Message handler for about box. 

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 

UNREFERENCED_PARAMETER(lParam); 

switch (message) 

case WM_INITDIALOG: 

return (INT_PTR)TRUE; 

case WM_COMMAND: 

if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 

EndDialog(hDlg, LOWORD(wParam)); 

return (INT_PTR)TRUE; 

break; 

return (INT_PTR)FALSE; 

//初始化opengl 

void EnableOpenGL(HWND hWnd) 

PIXELFORMATDESCRIPTOR pfd; 

int iFormat; 

g_hDC = GetDC(hWnd); 

ZeroMemory(&pfd, sizeof(pfd)); 

pfd.nSize = sizeof(pfd); 

pfd.nVersion = 1; 

pfd.dwFlags = PFD_DRAW_TO_WINDOW| PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 

pfd.iPixelType = PFD_TYPE_RGBA; 

pfd.cColorBits = 32; 

pfd.cDepthBits = 16; 

pfd.iLayerType = PFD_MAIN_PLANE; 

iFormat = ChoosePixelFormat( g_hDC, &pfd ); 

SetPixelFormat( g_hDC, iFormat, &pfd ); 

g_hRC = wglCreateContext(g_hDC); 

wglMakeCurrent( g_hDC, g_hRC); 

//设置着色模式 

void SceneInit() 

glShadeModel(GL_SMOOTH); 

glClearColor(1.0, 1.0, 1.0, 0.5); 

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 

//设置视口 

void SceneResizeViewport() 

RECT rect; 

int w,h; 

GLfloat aspect; 

GetClientRect( g_hWnd, &rect ); 

w = rect.right - rect.left; 

h =rect.bottom - rect.top; 

aspect = (GLfloat)w/ (GLfloat)h; 

glViewport(0,0,w,h);//设置视口 

glMatrixMode(GL_PROJECTION); 

glLoadIdentity(); 

gluOrtho2D(0.0, 5.0, 0.0, 5.0/aspect); 

void DisableOpenGL(){ 

wglMakeCurrent(NULL, NULL); 

wglDeleteContext(g_hRC); 

ReleaseDC(g_hWnd, g_hDC); 

void Display() 

glClear(GL_COLOR_BUFFER_BIT); 

glMatrixMode(GL_MODELVIEW); 

glLoadIdentity(); 

DrawLargeTriangle(g_TrianglePoint, 3); 

DrawTriangle(g_TrianglePoint, 3); 

glFlush(); 

//画大三角形 

void DrawLargeTriangle(LTRIANGLEPOINT pTrianglePoint, int iPointNum) 

glBegin(GL_LINE_LOOP); 

for ( int i = 0; i < 3; ++i) 

glColor3f(1.0,0.0,0.0); 

glVertex2f(pTrianglePoint[i].tpPointX,pTrianglePoint[i].tpPointY); 

glEnd(); 

//递归函数 

void DrawTriangle(LTRIANGLEPOINT pTrianglePoint, int iPointNum) 

//得到中间三角形的三个点 

TRIANGLEPOINT trianglepoint[3]; 

for (int i = 0; i < 3; ++i) 

if ( i == 2) 

trianglepoint[i].tpPointX = (pTrianglePoint[i].tpPointX + pTrianglePoint[0].tpPointX) / 2; 

trianglepoint[i].tpPointY = (pTrianglePoint[i].tpPointY + pTrianglePoint[0].tpPointY) / 2; 

else 

trianglepoint[i].tpPointX = (pTrianglePoint[i].tpPointX + pTrianglePoint[i+1].tpPointX) / 2; 

trianglepoint[i].tpPointY = (pTrianglePoint[i].tpPointY + pTrianglePoint[i+1].tpPointY) / 2; 

glBegin(GL_LINE_LOOP); 

for ( int i = 0; i < 3; ++i) 

glColor3f(1.0,0.0,0.0); 

glVertex2f(trianglepoint[i].tpPointX,trianglepoint[i].tpPointY); 

glEnd(); 

//构建其它三角 

TRIANGLEPOINT trianglepoint1[3]; 

TRIANGLEPOINT trianglepoint2[3]; 

TRIANGLEPOINT trianglepoint3[3]; 

ZeroMemory(&trianglepoint1, sizeof(trianglepoint1)); 

ZeroMemory(&trianglepoint2, sizeof(trianglepoint2)); 

ZeroMemory(&trianglepoint2, sizeof(trianglepoint2)); 

trianglepoint1[0] = pTrianglePoint[0]; 

trianglepoint1[1] = trianglepoint[0]; 

trianglepoint1[2] = trianglepoint[2]; 

trianglepoint2[0] = pTrianglePoint[1]; 

trianglepoint2[1] = trianglepoint[1]; 

trianglepoint2[2] = trianglepoint[0]; 

trianglepoint3[0] = pTrianglePoint[2]; 

trianglepoint3[1] = trianglepoint[2]; 

trianglepoint3[2] = trianglepoint[1]; 

//设定边界 

if(pow(abs(trianglepoint1[0].tpPointX - trianglepoint1[1].tpPointX), 2) 

+pow(abs(trianglepoint1[0].tpPointY - trianglepoint1[1].tpPointY), 2) > SIDELENGHT) 

DrawTriangle(trianglepoint1, iPointNum); 

if(pow(trianglepoint2[0].tpPointX - trianglepoint2[1].tpPointX, 2) 

+pow(trianglepoint2[0].tpPointY - trianglepoint2[1].tpPointY, 2) > SIDELENGHT) 

DrawTriangle(trianglepoint2, iPointNum); 

if(pow(trianglepoint2[0].tpPointX - trianglepoint2[1].tpPointX, 2) 

+pow(trianglepoint2[0].tpPointY - trianglepoint2[1].tpPointY, 2) > SIDELENGHT) 

DrawTriangle(trianglepoint3, iPointNum); 

}

温馨提示:答案为网友推荐,仅供参考
第1个回答  2009-03-15
OpenGL三维图形标准是由AT&T公司UNIX软件实验室、IBM
、DEC、SUN、HP、Microsoft和SGI等多家公司在GL图形库标准的基础
上联合推出的开放式图形库,它使在微机上实现三维真实
感图形的生成与显示成为可能。由于OpenGL是开放的图形标
准,用户原先在UNIX下开发的OpenGL图形软件很容易移植到微
机上的WindowsNT/95上。笔者在VisualC++4.1(以下简称VC)集
成环境下,开发了基于OpenGL的三维真实感图形应用程序,现
介绍如下。

微机上的OpenGL开发环境

基于OpenGL标准开发的应用程序必须运行于32位Windows
平台下,如WindowsNT或Windows95环境;而且运行时还需有动态
链接库OpenGL32.DLL、Glu32.DLL,这两个文件在安装WindowsNT时已
自动装载到C:\WINNT\SYSTEM32目录下(这里假定用户将WindowsNT
安装在C盘上);而对于使用Windows95平台的用户,则需手工将
两个动态库复制到Windows95目录的SYSTEM子目录中。安装了
WindowsNT/95和VC4.1后,用户就具备了基于OpenGL开发三维图
形软件的基本条件。

OpenGL程序设计的基本步骤

1.OpenGL在WindowsNT下的运行机制

OpenGL工作在客户机/服务器模式下,当客户方(即基
于OpenGL标准开发的应用程序)向服务器(OpenGL核心机制)发出
命令时,由服务器负责解释这些命令。通常情况下,客户方
和服务器是运行在同一台微机上的。由于OpenGL的运行机制
是客户机/服务器模式,这使得用户能够十分方便地在网
络环境下使用OpenGL,OpenGL在WindowsNT上的这种实现方式通常
称为网络透明性。

OpenGL的图形库函数封装在动态链接库OpenGL32.DLL中,

客户机中的所有OpenGL函数调用,都被传送到服务器上,由
WinSrv.DLL实现功能,再将经过处理的指令发送到Win32设备驱
动接口(DDI),从而实现在计算机屏幕上产生图像。

若使用OpenGL图形加速卡,则上述机制中将添加两个
驱动器:OpenGL可装载客户模块(OpenGLICD)将安装在客户端;硬
件指定DDI将安装在服务器端,与WinDDI同一级别。

2.OpenGL的库函数

开发基于OpenGL的应用程序,必须先了解OpenGL的库函
数。OpenGL函数命令方式十分有规律,每个库函数均有前缀gl
、glu、aux,分别表示该函数属于OpenGL基本库、实用库或辅助
库。WindowsNT下的OpenGL包含了100多个核心函数,均以gl作为前
缀,同时还支持另外四类函数:

OpenGL实用库函数:43个,以glu作为前缀;
OpenGL辅助库函数:31个,以aux作为前缀;
Windows专用库函数(WGL):6个,以wgl作为前缀;
Win32API函数(WGL):5个,无前缀。

OpenGL的115个核心函数提供了最基本的功能,可以实

现三维建模、建立光照模型、反走样、纹理映射等;OpenGL实
用库函数在核心函数的上一层,这类函数提供了简单的调
用方法,其实质是调用核心函数,目的是减轻开发者的编程
工作量;OpenGL辅助库函数是一些特殊的函数,可以供初学者
熟悉OpenGL的编程机制,然而使用辅助库函数的应用程序只
能在Win32环境中使用,可移植性较差,所以开发者应尽量避
免使用辅助库函数;Windows专用库函数(WGL)主要针对WindowsNT
/95环境的OpenGL函数调用;Win32API函数用于处理像素存储格
式、双缓存等函数调用。

3.VC环境下基于OpenGL的编程步骤

下面介绍在VC环境中建立基于Opeetting菜单选项,在Link栏的Lib输入域中
添加openg132.lib、glu32.lib,若需使用OpenGL的辅助库函数,则还
需添加glaux.lib。

(3)选择View/ClassWizard菜单选项,打开MFC对话框,在
ClassName栏中选择CMyTestView类,进行以下操作:

选择WM_CREATE消息,鼠标单击EditCode,将OpenGL初始化代码
添加到OnCreate()函数中:

/*定义像素存储格式*/

PIXELFORMATDESCRIPTORpfd=
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA,
24,
0,0,0,0,0,0,
0,0,0,0,0,0,0
32,
0,0,
PFD_MAIN_PLANE,
0,
0,0,0,
}
CCLientdc(this);
intpixelFormat=ChoosePixelFormat(dc.m_hDC,&pfd);
BOOLsuccess=SetPixelFormat(dc.m_hDC,pixelFormat,&pfd);
m_hRC=wglCreateContext(dc.m_hDC);

选择WM_DESTORY消息,在OnDestory()中添加以下代码:

wglDeleteContext(m_hRC);

在MyTestView.cpp中,将以下代码添加到PreCreateWindows()函数中:

cs.style|=WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
OpenGL只对WS_CLIPCHILDREN|WS_CLIPSIBLINGS类型窗口有效;

在MyTestView.cpp中,将以下代码添加到OnDraw()函数中:

wglMakeCurrent(pDC->m_hDC,m_hRC);
DrawScene();//用户自定义函数,用于绘制三维场景;
wglMakeCurrent(pDC->m_hDC,NULL);

在MyTestView.cpp中,添加成员函数DrawScene():

voidCMyTestView::DrawScene()
{/*绘制三维场景*/}
(4)在MyTestView.h中包含以下头文件并添加类成员说明:
#include
#include

#include
在CTestView类中的protected:段中添加成员变量声明:
HGLRCm_hRC;
同时添加成员函数声明:
DrawScene();

这样,一个基于OpenGL标准的程序框架已经构造好,用
户只需在DrawScene()函数中添加程序代码即可。

建立三维实体模型

三维实体建模是整个图形学的基础,要生成高逼真
度的图像,首先要生成高质量的三维实体模型。

OpenGL中提供了十几个生成三维实体模型的辅助库函
数,这些函数均以aux作为函数名的前缀。简单的模型,如球
体、立方体、圆柱等可以使用这些辅助函数来实现,如
auxWireSphere(GLdoubleradius)(绘制一半径为radius的网状球体)。
但是这些函数难以满足建立复杂三维实体的需要,所以用
户可以通过其它建模工具(如3DS等)来辅助建立三维实体模
型数据库。笔者在三维实体的建模过程中采用3DS提供的2D
Shape、3DLofter和3DEditor进行模型的编辑,最后通过将模型数

据以DXF文件格式输出存储供应用程序使用。

真实感图形的绘制

1.定义光照模型和材质

(1)光源。OpenGL提供了一系列建立光照模型的库函
数,使用户可以十分方便地在三维场景中建立所需的光照
模型。OpenGL中的光照模型由环境光(AmbientLight)、漫射光
(DiffuseLight)、镜面反射光(SpecularLight)等组成,同时还可设
置光线衰减因子来模拟真实的光源效果。

例如,定义一个黄色光源如下:

GlfloatLight_position[]={1.0,1.0,1.0,0.0,};
GlfloatLight_diffuse[]={1.0,1.0,0.0,1.0,};
glLightfv(GL_LIGHT0,GL_POSTTION,light_position);//定义光源位置
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);//定义光源漫射光
光源必须经过启动后才会影响三维场景中的实体,可以通过以下指令使光源有效:<
glEnable(LIGHTING);//启动光照模型;
glEnable(GL_LIGHT0);//使光源GL_LIGHT0有效;
OpenGL中一共可以定义GL_LIGHT0~GL_LIGHT7八个光源。

(2)材质。OpenGL中的材质是指构成三维实体的材料在
光照模型中对于红、绿、蓝三原色的反射率。与光源的定义
类似,材质的定义分为环境、漫射、镜面反射成分,另外还
有镜面高光指数、辐射成分等。通过对三维实体的材质定义
可以大大提高应用程序所绘制的三维场景的逼真程度。例
如:

/*设置材质的反射成分*/

GLfloatmat_ambient[]={0.8,0.8,0.8,1.0};
GLfloatmat_diffuse[]={0.8,0.0,0.8,1.0};/*紫色*/
GLfloatmat_specular[]={1.0,0.0,1.0,1.0};/*镜面高光亮紫色*/
GLfloatmat_shiness[]={100.0};/*高光指数*/
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);/*定义环境光反射率*/
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);/*定义漫射光反射率*/
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);/*定义镜面光反射率*/
glMaterialfv(GL_FRONT,GL_SHINESS,mat_shiness);/*定义高光指数*/

(3)材质RGB值与光源RGB值的关系。OpenGL中材质的颜色
与光照模型中光源的颜色含义略有不同。对于光源,R、G、B
值表示三原色在光源中所占有的比率;而对于材质定义,R、

G、B的值表示具有这种材质属性的物体对于三原色的反射
比率,场景中物体所呈现的颜色与光照模型、材质定义都相
关。例如,若定义的光源颜色是(Lr,Lg,Lb)=(1.0,1.0,1.0)(白光),
物体的材质颜色定义为(Mr,Mg,Mb)=(0.0,0.0,0.8),则最终到达人
眼的物体颜色应当是(Lr*Mr,Lg*Mg,Lb*Mb)=(0.0,0.0,0.8)(蓝色)。

2.读取三维模型数据

为了绘制三维实体,我们首先必须将预先生成的三
维实体模型从三维实体模型库中读出。下图描述了读取三
维实体模型的流程。

3.三维实体绘制

由于3DS的DXF文件中对于三维实体的描述是采用三角
形面片逼近的方法,而在OpenGL函数库中,提供了绘制三角形
面片的方法,所以为三维实体的绘制提供了方便。以下提供
了绘制三角形面片的方法:

glBegin(TRANGLES);//定义三角形绘制开始
glVertexf((GLfloat)x1,(GLfloat)y1,(GLfloat)z1);//第一个顶点
glVertexf((GLfloat)x2,(GLfloat)y2,(GLfloat)z2);//第二个顶点

glVertexf((GLfloat)x3,(GLfloat)y3,(GLfloat)z3);//第三个顶点
glEnd();//绘制结束

为了提高三维实时动画的显示速度,我们利用了
OpenGL库中的显示列表(DisplayList)的功能,将三维场景中的实
体分别定义为单独的显示列表,预先生成三维实体。在图形
显示时,只需调用所需的显示列表即可显示相应的三维实
体,而不需要重新计算实体在场景中的坐标,避免了大量的
浮点运算。在调用显示列表前所作的旋转、平移、光照、材
质的设定都将影响显示列表中的三维实体的显示效果。具
体实现算法如下:

for(ObjectNo=0;ObjectNo<实体个数;ObjectNo++)
{
glNewList(ObjectNo,GL_COMPILE);//创建第ObjectNo个实体的显示列表
for(Fac
相似回答