配置openGL并且运行第一个程序
安装:
- 选一个编译环境
现在Windows系统的主流编译环境有Visual Studio,Broland C++ Builder,Dev-C++等,它们都是支持OpenGL的。但老师上课选择VC++ 6.0作为学习OpenGL的环境。
但是我自己选的是VS2010 比较好用。
- 安装GLUT工具包
GLUT不是OpenGL所必须的,但它会给我们的学习带来一定的方便,推荐安装。
Windows环境下的GLUT下载地址:(大小约为150k)
http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip
无法从以上地址下载的话请使用下面的连接:
http://upload.programfan.com/upfile/200607311626279.zip
2.安装glew-1.9.0-win32
在官方网站上面下载:
http://sourceforge.net/projects/glew/
以前那个官网已经没有了,这个是新的官网
解压后.h文件放在../Microsoft Visual Studio\VC98\include\GL文件夹里,.lib文件放在lib文件夹里,.dll放在system32里面
创建工程:
(1)创建一个Win32 Console Application。
(2)链接OpenGL libraries。在Visual C++中先单击Project,再单击Settings,再找到Link单击,最后在Object/library modules 的最前面加上opengl32.lib Glut32.lib Glaux.lib glu32.lib 。
(3)单击Project Settings中的C/C++标签,将Preprocessor definitions 中的_CONSOLE改为__WINDOWS。最后单击OK。
下面就可以添加代码啦:
/*
第一个OPENGL程序
*/
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/glut.h>
#include <stdio.h>
#include<windows.h> // Header File For Windows
#include<stdlib.h>
#pragma comment ( lib , "opengl32.lib" )
#pragma comment ( lib , "glu32.lib" )
#pragma comment ( lib , "glew32.lib" )
#pragma comment ( lib , "glew32s.lib" )
#pragma comment ( lib , "glut32.lib" )
#ifdef GL_VERSION_1_3
void setupPointer (void )
{
static GLint vertices [] = {
25, 25,
75, 75,
100, 125,
150, 75,
200, 175,
250, 150,
300, 125,
100, 200,
150, 250,
200, 225,
250, 300,
300, 250};
glEnableClientState (GL_VERTEX_ARRAY );
glVertexPointer (2, GL_INT , 0, vertices );
}
void init (void )
{
GLenum err = glewInit ();
if (err != GLEW_OK )
{
exit(-2);
}
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH );
setupPointer ();
}
void display (void )
{
static GLubyte oneIndices [] = {0, 1, 2, 3, 4, 5, 6};
static const GLubyte twoIndices [] = {1, 7, 8, 9, 10, 11};
static GLsizei count [] = {7, 6};
static const GLvoid * indices [2] = {oneIndices , twoIndices };
glClear (GL_COLOR_BUFFER_BIT );
glColor3f (1.0, 1.0, 1.0);
glMultiDrawElementsEXT (GL_LINE_STRIP , count , GL_UNSIGNED_BYTE ,
indices , 2);
// 上面的一句相当于下面的两句
//glDrawElements(GL_LINE_STRIP, count[0], GL_UNSIGNED_BYTE, oneIndices);
//glDrawElements(GL_LINE_STRIP, count[1], GL_UNSIGNED_BYTE, twoIndices);
glFlush ();
}
void reshape (int w , int h )
{
glViewport (0, 0, (GLsizei ) w , (GLsizei ) h );
glMatrixMode (GL_PROJECTION );
glLoadIdentity ();
gluOrtho2D (0.0, (GLdouble ) w , 0.0, (GLdouble ) h );
}
void keyboard (unsigned char key , int x , int y )
{
switch (key ) {
case 27:
exit (0);
break ;
}
}
int main (int argc , char ** argv )
{
glutInit (&argc , argv );
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize (350, 350);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv [0]);
init ();
glutDisplayFunc (display );
glutReshapeFunc (reshape );
glutKeyboardFunc (keyboard );
glutMainLoop ();
return 0;
}
#else
int main(int argc, char** argv)
{
fprintf (stderr, "This program demonstrates a feature which is not in OpenGL Version 1.0.\n");
fprintf (stderr, "If your implementation of OpenGL Version 1.0 has the right extensions,\n");
fprintf (stderr, "you may be able to modify this program to make it run.\n");
return 0;
}
#endif
演示出来的效果是这个样子的:
然后我自己去另外找了一份疯狂代码里面的文章看看,反正我是没有运行成功,有谁会用的话,请教一下!
/////////////代码
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include<windows.h> // Header File For Windows
#include<stdio.h> // Header File For Standard Input/Output
#include<stdlib.h>
#include<gl\\gl.h> // Header File For The OpenGL32 Library
#include<gl\\glu.h> // Header File For The GLu32 Library
#include<gl\\glaux.h> // Header File For The GLaux Library
////全局变量//////////////////////////////////////////////////////////////////////////////////
HGLRC hRC=NULL; //设置个渲染描述表,将OpenGL连接到设备描述表
HDC hDC=NULL; //设置个设备描述表,将窗口连接到 GDI(Graphics Device Interface, 图形设备接口)
HWND hWnd=NULL; //保存 Windows 分配给窗口句柄
HINSTANCE hInstance; //保存应用例子句柄
bool keys[256]; //用于接收键盘输入,支持同时按下多个键
bool active=TRUE; //是否被最小化,当最小化时候挂起
bool fullscreen=TRUE; //是否运行于全屏幕模式,如果运行于窗口模式,它就为FALSE
bool blend=TRUE; //是否打开混合
//浮点数是OpenGL编程中最基本东西
GLfloat rtri=0.0f; //保存 4凌锥旋转角度
GLfloat rquad=0.0f; //保存立方体旋转角度
GLfloat xrot=0.0f; //控制立方体在x轴上旋转角度
GLfloat yrot=0.0f; //控制立方体在y轴上旋转角度
GLfloat zrot=0.0f; //控制立方体在z轴上旋转角度
GLfloat xspeed=0.2f; //控制立方体在x轴上旋转速度
GLfloat yspeed=0.3f; //控制立方体在x轴上旋转速度
GLfloat z=-5.0f; //控制立方体在屏幕中深度
BOOL light=false; //记录光照是否打开
BOOL lp=false; //键盘上L键是否被按下?
BOOL fp=false; //键盘上F键是否被按下?
BOOL bp=false; //键盘上B键是否被按下?
//设置光照(光照参数)
GLfloat LightAmbient= { 0.5f, 0.5f, 0.5f, 1.0f }; //创建半亮度白色环境光.参数都是0.5f,所以是个介于无光(黑
//)和全亮(白)灯光.
//没有环境光话,漫射光照不到地方将会非常黑暗
GLfloat LightDfuse= { 1.0f, 1.0f, 1.0f, 1.0f }; //用于创建个非常明亮,全亮度漫射光.所有值都是1.0f,是可以达到
//最亮灯光
//设置光照位置
GLfloat LightPosition= { 0.0f, 0.0f, 2.0f, 1.0f };//前 3个参数当然是用于指定其坐标x,y和z,最后个参数是1.0f告
//知OpenGL指定坐标就是光源位置
//你可以想象显示器玻璃平面就是z轴上0.0f平面,把光源放在2.0f位置上,所以如果你真能看到这个光源话,它应该
在你显示器玻璃屏上飘浮着
//当你到达0.0f时,图像看起来会很大,充斥了整个屏幕;而如果你向里到达个极限值时候,图像就看不见了
GLu filter; //用于指定显示哪个纹理.第个纹理(纹理0)使用GL_NEAREST过滤(无平滑),第 2个纹理(纹理1)使用
GL_LINEAR 过滤,得到平滑图像.第 3个纹理(纹理2)使用 mipmap 纹理,创建非常漂亮纹理外观.默认值0
GLu texture[3]; //用于给3个区别纹理创建存储空间
//mipmap纹理按照观察距离选择区别尺寸纹理,实现多层次细节.mipmap 纹理显示更好外观,但占用更多内存
////声明//////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //声明窗口回调 WndProc
/////////////////////////////////////////////////////////////////////////////////////////////////
//纹理图像宽度和高度必须是2幂.宽度或高度最小应是64个像素,为了兼容性,最多应是256个像素
AUX_RGBImageRec *LoadBMP(char *Filename) //读入位图文件.果文件不存在将返回NULL值代表文件不能
//被读取
{
FILE *File=NULL; //创建个文件句柄
(!Filename) //检测文件名是否合法
{
NULL; //If Not Return NULL
}
File=fopen(Filename,"r"); //检测文件是否存在
(File) //文件是否存在?
{
fclose(File); //关闭文件
auxDIBImageLoad(Filename); //返回auxDIBImageLoad(Filename)读入图像数据
} //使用aux库读入位图,所以要保证aux库被包含了.Delphi和Visual C都有aux库
NULL; //If Load Failed Return NULL
}
////////////////////////////////////////////////////////////////////////////////////////
LoadGLTextures //读取位图(通过上面代码)并转换成纹理
{
Status=FALSE; //记录是否成功地读取了位图并建造了纹理.化为FLASE(代表什么都没有读取和建造)
AUX_RGBImageRec *TextureImage[1]; //保存位图图像记录,持有图像宽度,高度和数据
mem(TextureImage,0,(void *)*1); //清空图像记录
//读入目录中*.bmp Check For Errors, If Bitmap's Not Found Quit
(TextureImage[0]=LoadBMP("Data/Data.bmp"))
{
Status=TRUE; //Set The Status To TRUE
//建造纹理
glGenTextures(3, &texture[0]); //获得3个未使用纹理名称
//第纹理使用GL_NEAREST过滤,它几乎不做过滤,低运算量,但效果很差
//如果某个游戏纹理看起来都是锯齿,可能使用就是这种过滤.不过通常它可以在慢速电脑上运行良好
glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定个纹理名称到个纹理对象
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //NEW
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //NEW
//定义个2D纹理
//0代表图像详细级别,这通常为0 (和多纹理贴图有关)
//3指定数据成分,这里图像是红,绿,蓝组成,所以为3
//TextureImage[0]->sizeX是纹理宽度,TextureImage[0]->sizeY是纹理高度
//0是纹理边界,通常为 0.GL_RGB告知OpenGL图像数据是红,绿,蓝顺序存储
//GL_UNSIGNED_BYTE表示图像数据类型是8位无符号整数.TextureImage[0]->data指定纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->data);
//第 2个纹理使用linear过滤建造纹理,区别是这次储存在texture[1]
glBindTexture(GL_TEXTURE_2D, texture[1]);
//下面两行代码分别用于设置在放大(GL_TEXTURE_MAG_FILTER)和缩小(GL_TEXTURE_MIN_FILTER)纹理贴图
时候所使用过滤
//通常将它们设置为GL_LINEAR,使纹理贴图在距离屏幕很远和很近时候都能看起来很平滑
//使用GL_NEAREST可能会出现些锯齿.也可以把它们结合起来使用,放大用种,缩小用种
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//线性过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//线性过滤
//定义个2D纹理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->data);
//创建mipmap纹理
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); // New
//要创建个 2D 纹理,使用3种颜色(RGB),TextureImage[0]->sizeX是图像宽度,TextureImage[0]->sizeY是图像
//高度
//GL_RGB表示使用红绿蓝顺序,GL_UNSIGNED_BYTE表示图像数据类型是字节,TextureImage[0]->data指定
//纹理数据
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->data);
}
//释放掉存储位图数据所有内存
(TextureImage[0]) //检查是否有位图保存在
{
(TextureImage[0]->data) //检查是否有数据
{
free(TextureImage[0]->data); //有即释放掉
}
free(TextureImage[0]); //释放掉图像结构
}
Status; //如果切顺利变量Status将为TRUE,否则为FALSE
}
//////////////////////////////////////////////////////////////////////////
//当窗口大小被调整时 (对于窗口模式) 调整 OpenGL 场景大小,至少会在首次运行时候被次,用来设置透视
.Resize And Initialize The GL Window
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
(height0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0, 0, width, height); // Re The Current Viewport
glMatrixMode(GL_PROJECTION); //设置当前矩阵为投影矩阵,给场景增加透视
glLoadIdentity; //重置当前指定矩阵为单位矩阵
//设置透视图:基于窗口宽和高,透视被设置为 45 度,视野指定透视深度:始点0.1f末点100.0f
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); //设置当前矩阵为模型视图矩阵,储存有关物体信息
glLoadIdentity; //重置当前指定矩阵为单位矩阵
}
//////////////////////////////////////////////////////////////////////////
//GL状态机化 All Setup For OpenGL Goes Here
InitGL(GLvoid)
{
(!LoadGLTextures) //读取位图并建造纹理
{
FALSE; //If Texture Didn't Load Return FALSE
}
glEnable(GL_TEXTURE_2D); //启用(激活)纹理映射
glShadeModel(GL_SMOOTH); //打开平滑阴影,平滑阴影会在多边形内精细地混合颜色和平滑光照
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //设置清除屏幕所用颜色,产生黑色背景
//设置深度缓存Cache(Depth Buffer),深度缓存Cache会拣选出哪个物体需要被先绘制,这样如果你在个圆形后
//面绘制个正方形,那么正方形不会覆盖到圆形上面来
//深度缓存Cache实际上存储了屏幕中每个像素点深度值,这样具有较小深度值像素(距离我们近像素)会把具有较
//大深度值像素(距离我们远像素)覆盖掉
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glH(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //最好透视修正,使透视图看起来好些
//设置光照
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); //设置light1发出环境光.使用LightAmbient存储环境
//光参数(半强度环境光)
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDfuse); //设置light1发出散射光.保存在LightDfuse中参数,全亮度
//白光
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);//设置light1光源位置,参数保存在LightPosition 中
glEnable(GL_LIGHT1); //开启light1.ight1已经设置好了,在没有开启GL_LIGHTING 的前,仍然不会有光照
glBlendFunc(GL_SRC_ALPHA,GL_ONE); //设置混合类型
TRUE; // Initialization Went OK
}
//////////////////////////////////////////////////////////////////////////
DrawGLScene(GLvoid) //绘图代码
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕到的前指定颜色,清除深度缓存Cache
//当你glLoadIdentity时候会回到屏幕(场景)中心位置,
//X轴是从左到右方向,Y轴是从下往上方向,Z轴是从屏幕里面射出屏幕方向
//OpenGL屏幕(场景)中心位置是在X轴,Y轴和Z轴上都为0.0f位置
//这样,中心左面是负值.右面是正值(X轴);下面是负值,上面是正值(Y轴);里面是负值,外面是正值(Z轴)
glLoadIdentity; //重置当前视图模型矩阵
glTranslatef(-2.0f,0.0f,-7.0f); //glTranslatef(x, y, z)功能是沿X轴Y轴和Z轴做移动.在X轴上向左移动2.0个单位
//,Y轴上没有移动(0.0),Z轴上向屏幕里面移动7.0个单位
//glRotatef(Angle,Xvector,Yvector,Zvector)用于绕轴旋转物体,Angle是个用于指定旋转角度数字(通常存储于
//变量中)
//Xvector,Yvector和Zvector这 3个参数用于描述条向量,以规定物体旋转轴.如果使用(1,0,0)这样值就描述了条
//长度为1个单位顺着x轴指向右方向量
//X 轴 - 你正在使用台台锯,木头穿过锯刀中心.锯刀在x轴上飞速旋转,刀齿看起来是向上切或者向下切,这取决于
//锯刀旋转方向.这和在OpenGL中以x轴旋转物体相类似
//Y 轴 - 想象下,原野上挂起了龙卷风.龙卷风中心正处于y轴上,它刮起泥土还有碎片正绕着y轴(龙卷风中心)旋转
//着,从左到右或从右到左.这和在OpenGL中以y轴旋转物体相类似
//Z 轴 - 你正看着台旋转着电风扇,电风扇中心点面向着你.电风扇扇片绕着z轴旋转,顺时针或逆时针方向.这和在
//OpenGL中以z轴旋转物体相类似
glRotatef(rtri,0.0f,1.0f,0.0f); // Rotate The Triangle On The Y axis
//如果想使物体绕某轴旋转,物体中心应该在(000)
//平滑上色会混合 3角形 3个顶点 3种颜色,形成漂亮混合色彩
glBegin(GL_TRIANGLES); //开始绘制个 4棱锥
glColor3f(1.0f,0.0f,0.0f); //设置为红色(红色亮度满没有绿和蓝)
glVertex3f( 0.0f, 1.0f, 0.0f); //正面 3角形顶点
glColor3f(0.0f,1.0f,0.0f); //颜色为绿色
glVertex3f(-1.0f,-1.0f, 1.0f); //正面 3角形左下点
glColor3f(0.0f,0.0f,1.0f); //设置为蓝色
glVertex3f( 1.0f,-1.0f, 1.0f); //正面 3角形右下点
glColor3f(1.0f,0.0f,0.0f); //设置为红色(红色亮度满没有绿和蓝)
glVertex3f( 0.0f, 1.0f, 0.0f); //右面 3角形顶点
glColor3f(0.0f,0.0f,1.0f); //设置为蓝色
glVertex3f( 1.0f,-1.0f, 1.0f); //右面 3角形左下点
glColor3f(0.0f,1.0f,0.0f); //颜色为绿色
glVertex3f( 1.0f,-1.0f, -1.0f); //右面 3角形右下点
glColor3f(1.0f,0.0f,0.0f); //设置为红色(红色亮度满没有绿和蓝)
glVertex3f( 0.0f, 1.0f, 0.0f); //背面 3角形顶点
glColor3f(0.0f,1.0f,0.0f); //颜色为绿色
glVertex3f( 1.0f,-1.0f, -1.0f); //背面 3角形左下点
glColor3f(0.0f,0.0f,1.0f); //设置为蓝色
glVertex3f(-1.0f,-1.0f, -1.0f); //背面 3角形右下点
glColor3f(1.0f,0.0f,0.0f); //设置为红色(红色亮度满没有绿和蓝)
glVertex3f( 0.0f, 1.0f, 0.0f); //左面 3角形顶点
glColor3f(0.0f,0.0f,1.0f); //设置为蓝色
glVertex3f(-1.0f,-1.0f,-1.0f); //左面 3角形左下点
glColor3f(0.0f,1.0f,0.0f); //颜色为绿色
glVertex3f(-1.0f,-1.0f, 1.0f); //左面 3角形右下点
glEnd; //完成绘制
glLoadIdentity; //坐标系已经被旋转,所以重置当前视图模型矩阵
glTranslatef(2.5f,0.0f,-8.0f); //在X轴上向右移动2.5个单位,Y轴上没有移动(0.0),Z轴上向屏幕里面移动8.0个单
//位
glRotatef(rquad,1.0f,1.0f,1.0f); //同时围绕 3个轴旋转
//以顺时针顺序将绘制出 4边形背面,也可以说实际上看到是它背面.
//物体沿逆时针顺序被绘制话就会以正面面向,这里6个 4边形都是按逆时针顺序绘制:右上,左上,左下,右下
//拿张白纸画上坐标系标出每个面每个顶点就可以直观地看出面及顶点顺序
glBegin(GL_QUADS); //绘制立方体
glColor3f(0.0f,1.0f,0.0f); //设置颜色绿色
glVertex3f( 1.0f, 1.0f,-1.0f); //顶面右上点
glVertex3f(-1.0f, 1.0f,-1.0f); //顶面左上点
glVertex3f(-1.0f, 1.0f, 1.0f); //顶面左下点
glVertex3f( 1.0f, 1.0f, 1.0f); //顶面右下点
glColor3f(1.0f,0.5f,0.0f); //设置颜色为橘色
glVertex3f( 1.0f,-1.0f, 1.0f); //底面右上点
glVertex3f(-1.0f,-1.0f, 1.0f); //底面左上点
glVertex3f(-1.0f,-1.0f,-1.0f); //底面左下点
glVertex3f( 1.0f,-1.0f,-1.0f); //底面右下点
glColor3f(0.5f,0.5f,1.0f); //纯蓝色
glVertex3f( 1.0f, 1.0f, 1.0f); //正面右上点
glVertex3f(-1.0f, 1.0f, 1.0f); //正面左上点
glVertex3f(-1.0f,-1.0f, 1.0f); //正面左下点
glVertex3f( 1.0f,-1.0f, 1.0f); //正面右下点
glColor3f(1.0f,1.0f,0.0f); //黄色
glVertex3f( 1.0f,-1.0f,-1.0f); //背面右上点
glVertex3f(-1.0f,-1.0f,-1.0f); //背面左上点
glVertex3f(-1.0f, 1.0f,-1.0f); //背面左下点
glVertex3f( 1.0f, 1.0f,-1.0f); //背面右下点
glColor3f(0.0f,0.0f,1.0f); //兰色
glVertex3f(-1.0f, 1.0f, 1.0f); //左面右上点
glVertex3f(-1.0f, 1.0f,-1.0f); //左面左上点
glVertex3f(-1.0f,-1.0f,-1.0f); //左面左下点
glVertex3f(-1.0f,-1.0f, 1.0f); //左面右下点
glColor3f(1.0f,0.0f,1.0f); //桃红色
glVertex3f( 1.0f, 1.0f,-1.0f); //右面右上点
glVertex3f( 1.0f, 1.0f, 1.0f); //右面左上点
glVertex3f( 1.0f,-1.0f, 1.0f); //右面左下点
glVertex3f( 1.0f,-1.0f,-1.0f); //右面右下点
glEnd; //完成绘制
glLoadIdentity; //重置当前视图模型矩阵
glColor3f(1.0f,1.0f,1.0f); //白色
// glColor4f(1.0f,1.0f,1.0f,0.5f); //颜色设置为全亮度和50%alpha(不透明度).这意味着当混合打开时物体会以
//50% 透明度绘制
glTranslatef(0.0f,0.0f,z); //Z轴上向屏幕里面移动z个单位
//在x,y和z轴上旋转立方体,旋转角度有分别由变量xrot,yrot和zrot控制
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(zrot,0.0f,0.0f,1.0f); // Rotate On The Z Axis
//选择要使用纹理.如果想变换纹理,就需要绑定另个纹理.绑定纹理操作不能在glBegin和glEnd的间进行
//当按下F键时,变量filter会增1,当其大于2时,就会回到0,开始时filter会化为0.通过这种方式来选择使用哪个纹理
glBindTexture(GL_TEXTURE_2D, texture[filter]); // Select A Texture Based On filter
//必须确保纹理和顶点右上角,左上角,右下角和左下角都能正确地对应,否则纹理有可能被倒置过来,也有可能歪
斜了,或者根本没贴上
//为了和物体坐标相区分,纹理坐标般使用字母s和t代替x和y.纹理坐标范围是0到1
//glTexCoord2f第个参数0.0f就是纹理左边0.5f就是纹理中间1.0f就是纹理右边
//第 2个参数是y坐标,0.0f就是纹理底边,0.5f是中间,而1.0f就是纹理顶边(最上边)
glBegin(GL_QUADS);
//法线(normal)是垂直于多边形表面向量,当使用光照时候必须要指定法线向量
//glNormal3f告诉OpenGL多边形朝向(OpenGL通过法线向量确定在顶点处物体接收了多少光)
//前面
glNormal3f( 0.0f, 0.0f, 1.0f); // Normal Poing Towards Viewer
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和 4边形左下点
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //右下点
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //右上点
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //左上点
//背面
glNormal3f( 0.0f, 0.0f,-1.0f); // Normal Poing Away From Viewer
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和 4边形右下点
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //右上点
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //左上点
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //左下点
//顶面
glNormal3f( 0.0f, 1.0f, 0.0f); // Normal Poing Up
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //纹理和 4边形左上点
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //左下点
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //右下点
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //右上点
//底面
glNormal3f( 0.0f,-1.0f, 0.0f); // Normal Poing Down
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和 4边形右上点
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //左上点
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //左下点
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //右下点
//右面
glNormal3f( 1.0f, 0.0f, 0.0f); // Normal Poing Right
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); //纹理和 4边形右下点
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); //右上点
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //左上点
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //左下点
//左面
glNormal3f(-1.0f, 0.0f, 0.0f); // Normal Poing Left
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //纹理和 4边形左下点
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //右下点
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //右上点
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //左上点
glEnd;
//数值越高,物体旋转得就越快;数值越低,物体旋转得就就越慢.改变代码中+号和-号物体以相反方向旋转
rtri0.2f; //Increase The Rotation Variable For The Triangle
rquad-=0.15f; //Decrease The Rotation Variable For The Quad
xrotxspeed; // Add xspeed To xrot
yrotyspeed; // Add yspeed To yrot
zrot0.4f; // Z Axis Rotation
TRUE; // Everything Went OK
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
GLvoid KillGLWindow(GLvoid) //退出的前被.释放 RC,DC还有窗口句柄
{
(fullscreen) //检查我们是否处于全屏幕模式,是话需要先切换回桌面
{
ChangeDisplaySettings(NULL,0); //输入NULL和0强制Windows使用注册表中值(默认分辨率,颜色深度,刷新
//率等)来有效地恢复原来桌面
ShowCursor(TRUE); //恢复了鼠标指针可见
}
(hRC) //然后检查我们是否有个Rendering Context(hRC)
{
(!wglMakeCurrent(NULL,NULL)) //下面代码将检查我们能否将hRC从hDC分开
{
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK |
MB_ICONINFORMATION);
}
(!wglDeleteContext(hRC)) //接下来释放RC
{
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK |
MB_ICONINFORMATION);
}
hRC=NULL; //设置hRC为 NULL
}
(hDC && !ReleaseDC(hWnd,hDC)) //检查是否拥有DC,有话将其释放
{
MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK |
MB_ICONINFORMATION);
hDC=NULL; //设置hDC为NULL
}
(hWnd && !DestroyWindow(hWnd)) //释放窗口句柄,销毁窗口
{
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK |
MB_ICONINFORMATION);
hWnd=NULL; //设置hWnd为NULL
}
(!UnregisterClass("OpenGL",hInstance)) //注销窗口类
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK |
MB_ICONINFORMATION);
hInstance=NULL; //设置hInstance为NULL
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//接收5个参数:窗口标题,窗口宽度,窗口高度,色彩深度(16/24/32)还有全屏幕模式开关.TRUE代表使用全屏幕模
式,FALSE代表使用窗口模式
//返回个BOOL值来表明窗口创建是否成功
BOOL CreateGLWindow(char* title, width, height, bits, bool fullscreenflag)
{
GLu PixelFormat; //保存Windows给出匹配像素点格式
WNDCLASS wc; //保存窗口类结构
DWORD dwExStyle; //用于存放扩展窗口风格信息
DWORD dwStyle; //存放通常窗口风格信息
//获取矩形左上角和右下角值,窗口是具有边框,所以般窗口尺寸会大于绘图区尺寸
RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right values
WindowRect.left=(long)0; // Set Left value To 0
WindowRect.right=(long)width; // Set Right value To Requested Width
WindowRect.top=(long)0; // Set Top value To 0
WindowRect.bottom=(long)height; // Set Bottom value To Requested Height
fullscreen=fullscreenflag; //把fullscreenflag值赋给全局变量fullscreen
hInstance = GetModuleHandle(NULL); //获取应用例子句柄,然后定义窗口类
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //窗口在调整尺寸时重绘,创建个私有窗口DC
wc.lpfnWndProc = (WNDPROC) WndProc; //窗口过程 WndProc Handles Messages
wc.cbClsExtra = 0; //不需要额外窗口数据
wc.cbWndExtra = 0; //不需要额外窗口数据
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Poer
wc.hbrBackground = NULL; //的后在OpenGL中设置窗口背景色
wc.lpszMenuName = NULL; //不需要菜单
wc.lpszClassName = "OpenGL"; //设置类名
(!RegisterClass(&wc)) //注册窗口类
{
MessageBox (NULL," Failed To Register The Window Class.","ERROR"
,MB_OK|MB_ICONEXCLAMATION);
FALSE; //退出
}
(fullscreen) //切换到全屏幕模式
{
DEVMODE dmScreenSettings; // Device Mode
mem(&dmScreenSettings,0,(dmScreenSettings)); //清除用于保存显示设置参数空间
dmScreenSettings.dmSize=(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = width; //设置需要宽,在全屏幕模式下使用窗口宽和高应该和在窗口模式
//中使用宽和高相同
dmScreenSettings.dmPelsHeight= height; //设置需要高
dmScreenSettings.dmBitsPerPel = bits; //设置色彩深度
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
//尝试设置和dmScreenSettings中相匹配模式
//NOTE:CDS_FULLSCREEN使得在切换全屏模式时候移除底部开始菜单任务栏,而且在整个切换过程中不会影响
//到桌面上其它窗口尺寸.
(ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
//如果所请求全屏幕模式不被支持,将弹出个消息框.你可以选择使用窗口模式或退出
(MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\\nYour Video Card. Use
Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)IDYES)
{
fullscreen=FALSE; // Select Windowed Mode (Fullscreen=FALSE)
}
{
//弹出个消息框告诉用户即将结束,窗口创建失败
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
FALSE; //退出
}
}
}
(fullscreen) //仍在全屏设置中
{
dwExStyle=WS_EX_APPWINDOW; //设置扩展风格为WS_EX_APPWINDOW,强制使窗口可见于最前面
dwStyle=WS_POPUP; //设置通常风格为WS_POPUP,没有边框弹出式窗口,使得全屏模式窗口完美显示
ShowCursor(FALSE); //禁止鼠标箭头
}
//转为窗口模式继续运行
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; //增加WS_EX_WINDOWEDGE到扩展风格,使
//窗口具有 3D 外观
dwStyle=WS_OVERLAPPEDWINDOW; //用WS_OVERLAPPEDWINDOW代替WS_POPUP,具有标题栏,窗口
//菜单,最大化最小化按钮和可调整尺寸窗口
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); //根据窗口风格来调整窗口尺寸,对于全
//屏幕模式来说这条没有效果
//创建窗口
(!(hWnd=CreateWindowEx( dwExStyle, //扩展窗口风格
"OpenGL", //类名(必须和的前注册类名相同)
title, //窗口标题
WS_CLIPSIBLINGS | //WS_CLIPSIBLINGS和WS_CLIPCHILDREN 风格,这是保证OpenGL正常运行所必须.
WS_CLIPCHILDREN | //能预防其它窗口在OpenGL窗口上进行绘图
dwStyle, //通常样式
0, 0, //窗口左上角坐标
WindowRect.right-WindowRect.left, //窗口宽和高
WindowRect.bottom-WindowRect.top,
NULL, //没有父窗口
NULL, //不需要菜单
hInstance, //应用句柄
NULL))) // Don't Pass Anything To WM_CREATE
{ //创建不成功
KillGLWindow; // Re The Display
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
FALSE; // Return FALSE
}
//描述象素点格式
PIXELFORMATDEscriptOR pfd= // pfd Tells Windows How We Want Things To Be
{
(PIXELFORMATDEscriptOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | //格式支持 OpenGL
PFD_DOUBLEBUFFER, //支持双缓冲
PFD_TYPE_RGBA, //支持RGBA 模式
bits, //要求色彩深度相匹配色深
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Sht Bit Ignored
0, // No Accumulation Buffer(积累缓存Cache)
0, 0, 0, 0, // Accumulation Bits Ignored
16, //设置个16bitZ-缓存Cache(Depth Buffer)
0, // No Stencil Buffer(模版缓存Cache)
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
(!(hDC=GetDC(hWnd))) //尝试获取个OpenGL Device Context
{
KillGLWindow; //Re The Display
MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
FALSE; //退出
}
(!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) //找出个和上面所描述相匹配像素点格式
{
KillGLWindow; // Re The Display
MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
FALSE; //退出
}
(!SetPixelFormat(hDC,PixelFormat,&pfd)) //设置像素点格式
{
KillGLWindow; // Re The Display
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
FALSE; //Return FALSE退出
}
(!(hRC=wglCreateContext(hDC))) //获取个Rendering Context
{
KillGLWindow; //Re The Display
MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR",
MB_OK|MB_ICONEXCLAMATION);
FALSE; //Return FALSE退出
}
(!wglMakeCurrent(hDC,hRC)) //激活Rendering Context
{
KillGLWindow; // Re The Display
MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR",
MB_OK|MB_ICONEXCLAMATION);
FALSE; // Return FALSE
}
ShowWindow(hWnd,SW_SHOW); //将窗口显示出来 Show The Window
SetForegroundWindow(hWnd); //并把它设到前台 Slightly Higher Priority
SetFocus(hWnd); //设置焦点到窗口上 Sets Keyboard Focus To The Window
ReSizeGLScene(width, height); //将窗口宽和高作为参数来ReSizeGLScene以设置OpenGL透视
(!InitGL) // Initialize Our Newly Created GL Window
{
KillGLWindow; // Re The Display
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
FALSE; // Return FALSE
}
TRUE; //返回TRUE告知WinMain未发生
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
switch (uMsg) //uMsg用来保存待处理消息名字 Check For Windows Messages
{
WM_ACTIVATE: // Watch For Window Activate Message
{
(!HIWORD(wParam)) //检查窗口是否还处于活动状态
{
active=TRUE; //窗口处于活动状态
}
{
active=FALSE; //窗口处于非活动状态
}
0; // Return To The Message Loop
}
WM_SYSCOMMAND: //(系统消息)
{
switch (wParam) // Check Calls
{
SC_SCREENSAVE: //代表屏幕保护将启动
SC_MONITORPOWER: //代表显示器将进入节能模式
0; //返回0以阻止这种事情发生
}
; // Exit
}
WM_CLOSE: //窗口被关闭
{
PostQuitMessage(0); //发出条退出消息
0; //Jump Back
}
WM_KEYDOWN: //某个键被按下,支持多个键同时按下思路方法
{
keys[wParam] = TRUE; //keys中和那个键相对应元素将被设置为TRUE
0; // Jump Back
}
WM_KEYUP: //某个键抬起
{
keys[wParam] = FALSE; //keys中和那个键相对应元素将被设置为FALSE
0; // Jump Back
}
WM_SIZE: //调整窗口尺寸消息
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); //读取lParam 低字和高字值可以获取新窗口尺寸宽
和高,以新尺寸值作为参数ReSizeGLScene,OpenGL场景做出相应尺寸调整
0; // Jump Back
}
}
//其余消息递给DefWindowProc,让 Windows 自行处理
DefWindowProc(hWnd,uMsg,wParam,lParam);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
WINAPI WinMain (HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
nCmdShow) // Window Show State
{
MSG msg; //用于检测是否有消息需要处理 Windows Message Structure
BOOL done = FALSE; //当它为TRUE时候就会退出 Bool Variable To Exit Loop
//询问是否要运行于全屏幕模式
(MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?"
,MB_YESNO|MB_ICONQUESTION)IDNO)
{
fullscreen=FALSE; //选择NO变量fullscreen从TRUE(默认值)变为FALSE.并且会运行于窗口模式
}
//创建OpenGL窗口
(!CreateGLWindow("OpenGL",640,480,16,fullscreen))
{
0; // Quit If Window Was Not Created
}
while(!done) // Loop That Runs Until done=TRUE
{
(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //否有 Windows 消息待处理.使用PeekMessage 检索消息
可以避免等待
{
(msg.messageWM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
// If Not, 解释消息
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
//没有消息话绘制OpenGL场景
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene
(active) //检查窗口是否处于活动状态
{
(keys[VK_ESCAPE]) // Was ESC Pressed?
{
done=TRUE; // ESC Signalled A Quit
}
// Not Time To Quit, Update Screen
{
//如果处于活动状态并且 ESC 按钮没有被按下
DrawGLScene; //绘制场景
SwapBuffers(hDC); //交换缓冲区(使用双缓冲技术可以得到平滑无闪烁动画)
(keys['L'] && !lp) //L键是否被按下?
{ //lp初值为false.false意味着L键不处于压下状态,或早已释放.true意味着L键处于压下状态
lp=TRUE; //lp置为true.为了避免如果按住L键光照就会反复开、关而闪烁
light=!light; //转换光照开和关.变量light只能是true或false,如果它是true话就会变成false,是false话就会变成
true
(!light) //light为false
{
glDisable(GL_LIGHTING); //关闭光照
}
//light为true
{
glEnable(GL_LIGHTING); //打开光照
}
}
(!keys['L']) //检测是否已经释放L键
{
lp=FALSE; //是话就置变量lp为false
}
(keys['F'] && !fp) //检测F键是否被按下?
{ //同上方式
fp=TRUE; // fp Becomes TRUE
filter1; //F键被按下次变量filter就会增加1
(filter>2) //当其大于2时
{
filter=0; //回到0
}
}
(!keys['F']) //是否已经释放F键?
{
fp=FALSE; //是话就置变量fp为false
}
(keys[VK_PRIOR]) //检测是否按下"Page Up"?
{
z-=0.02f; //是话变量z就会有减量.把木箱向屏幕里方向移动
}
(keys[VK_NEXT]) //检测是否按下"Page Down"键
{
z0.02f; //是话变量z就会有增量,DrawGLScene中glTranslatef(0.0f,0.0f,z)就会把木箱向外移动
}
//检测方向键是否被按下
//按下左或右键,变量xspeed就会相应地减量或增量;按下上或下键,变量yspeed就会相应地减量或增量
//xspeed或yspeed(绝对)值越高,木箱旋转就会越快.所以按住某个方向键时间越长,木箱在对应方向就会旋转越
快
(keys[VK_UP]) // Is Up Arrow Being Pressed?
{
xspeed-=0.01f; // If So, Decrease xspeed
}
(keys[VK_DOWN]) // Is Down Arrow Being Pressed?
{
xspeed0.01f; // If So, Increase xspeed
}
(keys[VK_RIGHT]) // Is Right Arrow Being Pressed?
{
yspeed0.01f; // If So, Increase yspeed
}
(keys[VK_LEFT]) // Is Left Arrow Being Pressed?
{
yspeed-=0.01f; // If So, Decrease yspeed
}
//在绘制透明物体时候,关闭深度缓存Cache,希望在半透明物体后面物体能被绘制,这并不是使用混合正确方式
,但是在情况简单时候它会工作得很好
//正确思路方法是在整个场景绘制完的后再绘制所有透明(alpha < 1.0)多边形,而且要按照由远及近深度顺序
//这是由于事实上按照区别顺序混合两个(1和2)多边形会得到区别结果
//假如多边形1距离我们最近,那么正确思路方法是先绘制多边形2,然后是多边形1
//如果你看着它,那么真实情况就是它们后面光首先经过多边形2,然后经过多边形1,最后到达你眼睛
//所以,需要按照深度将透明多边形进行排序,开着深度缓存Cache并在整个场景绘制完毕的后再绘制它们,否则将
得到不正确结果
(keys['B'] && !bp) //检查键盘上B键是否被按下?
{
bp=TRUE; // If So, bp Becomes TRUE
blend = !blend; // Toggle blend TRUE / FALSE
(blend) //混合是关?
{
glEnable(GL_BLEND); //打开混合
glDisable(GL_DEPTH_TEST); //关闭深度测试
}
//混合是开
{
glDisable(GL_BLEND); //关闭混合
glEnable(GL_DEPTH_TEST); //打开深度测试
}
}
(!keys['B']) //B被释放?
{
bp=FALSE; //bp置为FALSE
}
}
}
//使用 F1 切换全屏幕模式和窗口模式
(keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow; // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
(!CreateGLWindow("OpneGL",640,480,16,fullscreen))
{
0; // Quit If Window Was Not Created
}
}
}
}
//退出,完全地摧毁窗口,所有东西都释放掉
KillGLWindow; // Kill The Window
(msg.wParam); // Exit The Program
}