MFC+OpneGL学习笔记

零基础搭建OpenGL开发环境[0]
OPENGL的介绍就不用了,他的好处书上也很多。开始之前记录一个学习openGL的网站:http://nehe.gamedev.net/ NEHE的OpenGL学习网站。其他相关openGL的知识的书也希望我去好好看看。
1.openGL的库。使用OpenGL开发当然要使用到他的库咯。他的头文件包括:
gl.h glu.h glaux.h 等核心的库,还有一个我们用的很多很多的glut.h头文件。
为了使用它,我们还有相应的.lib文件和.dll文件。
2.把这些使用到的东东放到他该有的位置。
头文件的位置:放到VS安装目录下的VC->include目录下,可以自己建立一个gl文件夹
我的位置是:C:/Program Files/Microsoft Visual Studio 8/VC/include/gl
 
因为我是用VS2005安装在C盘的。这个要看具体目录而定。
Lib文件的位置,同理,有include就有lib,找到对应vc->lib目录,你是不是发现了很多.lib文件,对,这里就是他的位置了。
我的位置是:C:/Program Files/Microsoft Visual Studio 8/VC/lib
 
.dll文件
Dll文件就放在windos下的sysytem32目录下:
我的是:C:/WINDOWS/system32
 
基本就是这些东西,我们的Opengl开发环境搭建完毕。理论上来说是可以编写OpenGL程序了。
由于我英语很烂,居然没有在官网中找到最新的Opengl库文件,只好用以前的库了,整理了一下。如果你也没有找到,就凑合用他吧:

下载地址:http://download.csdn.net/source/1221084 

OpenGL学习笔记[1]

1.库更新的问题,首先鄙视一下自己的英语,再鄙视一下opengl官网。英语烂居然在官网找不到要使用到得openGL使用的头文件库。官网也是,不给一个明显的下载标志,反而给了很多工具的下载。郁闷啊。然后去网上找也是怎么找也找不到,最后还是放弃用最新的Opnegl库,用了以前的文件,发现gl.h时98年的。反正很多库都文件都是很久很久的。希望能在网上找到,或则有人提供一下。就好了。
2.包含库的应用问题:今天本来打算学习NEHE的第六课贴图的课程,可是发现居然直接编译不通过,是link的错误。什么什么没有找到,我地一反应时没有相应的.lib文件,我把lib拷到vc目录下(不会不知道怎么拷吧!把LIB文件复制,找到VC目录下VC-LIB里面点粘贴,我的目录是:C:/Program Files/Microsoft Visual Studio 8/VC/lib,我是在C盘嘛。)然后还是不可以,我紧接着可能是连接没有连接上,用#pragma comment(lib, "glu32.lib") 和#pragma(lib, "glaux.lib") 来强行的静态链接,结果还是错误。我无语,难道这也有错,我改了配置,在link的附加依赖项里面手动添加了依赖,还是不行。我几乎崩溃了。只有注释法,先让他通过再说以增加自己的信心。后来发现调用auxDIBImageLoad(Filename);这个函数有问题。哎,这个明显是glaux里面的函数,可是我有连接啊,我再次怀疑是不是他没有静态链接,而是用的动态链接.dll,然后在用把dll放到动态system32目录下,郁闷的是glaux是没有dll的,而且还发现了我的glu32.dll是有问题的,不能读取。没有办法。我几乎崩溃的时候,突然发现我以前的程序有一个用到auxDIBImageLoad这个函数的,马上找出来,编译一次,OK,successful(不对,应该是成功,因为我用的是中文版的VS2005)。然后对比一下,发现我多包含了一个glut.h,如法炮制,结果成功了。问题是解决了,可是这明显浪费了我时间啊。觉得一个辅助库glut的功能比核心库没有错误,好用的多。哎。Openggl的发展啊。我暂时定义为我的头文件和lib文件有问题,不是最新的,或则是有bug的。而刚好glut没有问题。哈哈。也许是我的水平太低,没有学好吧。无论哪种原因,再次BS一下自己,英语一定要加油学啊,不然一个必须得资料的找不到,还学什么?
3.加油加油,一边学习,一边找到opengl的最新资源。希望能每天努力点提高英语水平。

OpenGL学习笔记【3】——OpenGL学习起始框架

今天学习了OpenGL的入门,了解了一下他的流程框架,具体什么什么直接操作硬件啊什么的OpenGL的资料就不讲了,什么时候整理一下。直接进入流程框架:
我们用的glut辅助库,他能让我们减少好多的操作,例如创建窗口,初始化设备,他都为我们建好了。
开始:
1.初始化opengl
2.设置渲染模式为:GLUT_DOUBLE | GLUT_RGBA
3.设置窗口大小,和标题,
4.创建窗口,
5.进入Opnegl里面的初始化。Opengl里面的初始化这里的初始化一定要在创建窗口以后。
6.设置渲染的函数
7.设置变化窗口大小,调整视口的函数
8.主程序循环。
这就是程序的主框架,我们只要把这些内容写入到main函数中,然后再自己实现相关的函数就可以了。是不是给我们带来了很大的方便呢。废话少说。奉上源代码:

#include 

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    
    glBegin(GL_TRIANGLES);            //绘制一个三角型
    glColor3f(1.0,0,0);                //绘制颜色为红色
    glVertex3f (0, 0, -2.0);        //绘制三角型的一个顶点0,0,-2
    glColor3f(0,1.0,0);                //同理绘制其他两个顶点
    glVertex3f (1, 1, -2.0);
    glColor3f(0,0,1.0);    
    glVertex3f (1, 0, -2.0);
    glEnd();                    //结束绘制三角型

    glutSwapBuffers();            //交换缓冲区。显示图形
}


//初始化
void init (void) 
{
    glClearColor (1.0, 0.0, 0.0, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)
}


//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)


    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA


    glutInitWindowSize (250, 250);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutMainLoop();                            //主循环。
    return 0;  
}
在这里只是话了一个三角形。呵呵。

OpenGL学习笔记【4】——给立方体纹理贴图(texture)

今天我学习了对一个正方体贴纹理:
这次先奉上源代码:

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

GLuint g_texture = 0;
GLfloat xrot =0;
GLfloat yrot =0;
GLfloat zrot =0;                                    // Keep Going

//绘制一个立方体
int DrawCube(void)
{
    glBindTexture(GL_TEXTURE_2D, g_texture);        //使用贴图纹理
    glPushMatrix();        //压入变换矩阵
    glRotatef(xrot,1.0f,0.0f,0.0f);            //旋转矩阵,这里绕x轴旋转。
    glRotatef(yrot,0.0f,1.0f,0.0f);            //旋转矩阵,这里绕y轴旋转。
    glRotatef(zrot,0.0f,0.0f,1.0f);            //绕z轴旋转,这里zrot是角度制的度数。

    glBegin(GL_QUADS);  //启用四边形带绘制模式绘制

    // 绘制前面,这里开始确定纹理坐标,然后是确定点的位置
    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);
    glTexCoord2f(0.0f, 1.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);
    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(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);
    glTexCoord2f(1.0f, 1.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);
    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, 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);
    glTexCoord2f(0.0f, 0.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);
    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();

    glPopMatrix(); //弹出变换矩阵

    return 1;
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glLoadIdentity();                                    // Reset The View
    glTranslatef(0.0f,0.0f,-5.0f);

    DrawCube();

    glutSwapBuffers();            //交换缓冲区。显示图形
}


//载入一个.bmp格式的贴图纹理
int LoadGLTextures(GLuint& unTexture, const char* chFileName)                
{
    AUX_RGBImageRec *TextureImage;                    //保存贴图数据的指针
    TextureImage = auxDIBImageLoad("Data/NeHe.bmp"); //载入贴图数据

    glGenTextures(1, &unTexture);                    // 创建一个纹理,unTexture

    glBindTexture(GL_TEXTURE_2D, unTexture);        //绑定纹理,然后对该纹理区添加纹理数据

    //设置纹理的信息,
    glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //设置滤波为线性滤波
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);    //线性滤波

    if (TextureImage)                //释放资源
    {
        if (TextureImage->data)
        {
            free(TextureImage->data);
        }
        free(TextureImage);
    }

    return 1;
}
//初始化
void init (void) 
{
    glClearColor (0.0, 0.0, 0.0, 0.0);            //清理颜色,为黑色,(也可认为是背景颜色)

    glCullFace(GL_BACK);                        //背面裁剪(背面不可见)
    glEnable(GL_CULL_FACE);                        //启用裁剪
    glEnable(GL_TEXTURE_2D);
    LoadGLTextures(g_texture, "Data/NeHe.bmp");            //载入纹理贴图
}
//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)

    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}
//闲置函数,当主循环空闲时就会调用这个函数
void MyIdle(void)
{
    Sleep(10);
    xrot+=0.3f;        //增加旋转的角度。
    yrot+=0.2f;
    zrot+=0.4f;                                    
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutIdleFunc(MyIdle);
    glutMainLoop();                            //主循环。
    return 0;  
}

主要流程:
OpneGL的流程,先初始化。
1. 在Init函数中,初始化我们的信息:
glClearColor (0.0, 0.0, 0.0, 0.0); //清理颜色,为黑色,(也可认为是背景颜色)
glCullFace(GL_BACK); //背面裁剪(背面不可见)
glEnable(GL_CULL_FACE); //启用裁剪
glEnable(GL_TEXTURE_2D);
LoadGLTextures(g_texture, "Data/NeHe.bmp"); //载入纹理贴图
这里的顺序是可以打乱的,记住一定要载入纹理,我这里是写了一个函数来载入。然后要启用纹理贴图。glEnable(GL_TEXTURE_2D);。还有一件事情是比不可少的,就是一定要启用裁剪,并且一定要用GL_BACK。我也不知道为什么,反正用glut创建的窗口就不可以,如果是直接用windows下创建的不用这个也是可以的。原理暂时还不清楚。
2 . 然后是绘制图形:
就是绘制一个正方体,并贴上图。
glTexCoord2f(0.0f, 1.0f); 这是贴图的纹理坐标,在0-1范围内,他就是把一张纹理看成0-1的区域,这就是用他该区域的纹理贴图。
glVertex3f(-1.0f,  1.0f, -1.0f); //画点,这里画点后,他的纹理就有上面的贴图的纹理坐标来确定。就确定了这点的贴图信息。
3.新加了一个idle函数,他能在循环空闲的时候调用,我们用他来改变旋转的角度并重画图形,这样就可以看到图形动起来了。

OpenGL学习笔记【5】——自我安慰和鼓励

学习OpenGL也有一些日子的,感觉总是空范范的, 1.很多函数只知道大概是做什么的,却没能深入体会他的用法和精髓,更别说原理的理解了。不过没有关系,我先学会怎么用,尽量理解的深点,等会用了我在转头再学一遍,应该理解会更深吧。毕竟OpenGL还是一个满基础的东西的,如果OpenGL学好了,以后学DirectX应该也挺快的吧。呵呵。。 2.在编写OpengGL程序的时候,总是很很多都编译不通过,甚至还有gl.h头文件出错的情况,我都不知道我是怎么回事,难道库有问题。我的处理就是不导入gl.h头文件了,直接用glut.h头文件,ok,就没有问题了。 3.需要静态链接LIB文件,一定要把对应的lib手动静态链接过来,我也不清楚为什么我明明放在Lib目录了还不能静态链接。#pragma comment(lib, "XXX.lib")来静态链接,当然也可以在属性,链接的附加依赖项里面添加要连接的文件。 4.还有就是UNICODEMultiByte 字节的转换。导致有些函数说不能有XXX转换到XXx。我的处理就是直接在属性->常规->字符集改为多字节字符。这样就可以了。不过目前推荐用UNICODE,但是很多时候需要什么WideCharToMultiByte()MultiBytToWideChar的转换,导致用的不爽。所以就不用了,因为只是学习嘛。
5.
我发现了一本学习opneGL比较好的书,他讲解里面的函数的用法都挺好挺实用的,附上他连接:
http://download.csdn.net/source/1247246
呵呵。。继续加油吧。一定要坚持下去啊。。

OpenGL学习笔记【6】——初学光照

今天学习了OpenGL的光照,我觉得我以前学习OpenGL的方法有写不对,试着改变一下。换一本书。坚持,我不想就这么放弃。。 
OpenGL光照就使用OpenGL的函数给世界带来光,他的具体什么数学知识,光线的原理啊,什么的,我现在都不知道。以后再去了解一下,毕竟这些都是数学家做的事情,我没有那么厉害全部搞定,只能用现成的东西:OpenGL提供的函数来实现光照。
首先奉上源代码:按键盘1,2,3,4,5,6,7来控制光的属性:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);

    glLoadIdentity();        //初始变换矩阵为单位矩阵

    glPushMatrix();            //压入变换矩阵那
    glTranslated(0,0,-5);    //平移0,0,-5向Z负方向平移5个单位
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();            //弹出矩阵。

    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    glClearColor (0.5, 0.5, 0.5, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)
    GLfloat light_param[] =  { 1, 1, 1, 0.0 };    //初始化光参数。
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_param);    //设置光为环境光。
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glDepthFunc(GL_LEQUAL);    
    glEnable(GL_DEPTH_TEST);
}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)

    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

void Keyboard(unsigned char key, int x, int y)
{
    if (key == '1')
     {
        GLfloat light_param[] =  { 5.0, 5.0, -1.0,1.0 };
        glLightfv(GL_LIGHT0, GL_POSITION, light_param);
    }
    else if (key == '2')
     {
        GLfloat light_param[] =  { 0.0, 0.0, -1.0,1.0 };
        glLightfv(GL_LIGHT0, GL_POSITION, light_param);
    }
    else if (key == '3')
     {
        GLfloat light_ambient[4] =  {0.8,0.8,0.8,1.0};
        glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    }
    else if (key == '4')
     {
        GLfloat light_ambient[4] =  {0.8,0.8,0.0,1.0};
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_ambient);
    }
    else if (key == '5')
     {
        GLfloat light_ambient[4] =  {0.0,0.0,0.8,1.0};
        glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    }
    else if (key == '6')
     {
        GLfloat light_ambient[4] =  {1.0,0.0,1.0,1.0};
        glLightfv(GL_LIGHT0, GL_SPECULAR, light_ambient);
    }
    else if (key == '7')
     {
        GLfloat light_ambient[4] =  {1.0,0.0,0.0,1.0};
        glLightfv(GL_LIGHT1, GL_DIFFUSE, light_ambient);
        glEnable(GL_LIGHT1);
    }
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (250, 250);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutKeyboardFunc(Keyboard);
    glutMainLoop();                            //主循环。
    return 0;  
}

OpenGL有五种光,环境光,点光源,漫反射光,镜面反射光,聚光源。OpenGL可以使用GL_LIGHT0-GL_LIGHT7七 盏光。

每种关具体的参数请看书上的表:

pname 参数名

缺省值

说明

GL_AMBIENT

(0.0, 0.0, 0.0, 1.0)

RGBA模式下环境光

GL_DIFFUSE

(1.0, 1.0, 1.0, 1.0)

RGBA模式下漫反射光

GL_SPECULAR

(1.0,1.0,1.0,1.0)

RGBA模式下镜面光

GL_POSITION

(0.0,0.0,1.0,0.0)

光源位置齐次坐标(x,y,z,w)

GL_SPOT_DIRECTION

(0.0,0.0,-1.0)

点光源聚光方向矢量(x,y,z)

GL_SPOT_EXPONENT

0.0

点光源聚光指数

GL_SPOT_CUTOFF

180.0

点光源聚光截止角

GL_CONSTANT_ATTENUATION

1.0

常数衰减因子

GL_LINER_ATTENUATION

0.0

线性衰减因子

GL_QUADRATIC_ATTENUATION

0.0

平方衰减因子

表10-1 函数glLight*()参数pname说明

设置光源:

我们先对启用关照才能使用光源,启用光照的函数是:

glEnable(GL_LIGHTING);

然后我们可以使用:

glEnable(GL_LIGHT0);

来启用GL_LIGHT0这个光。

基本知识就学了这么多,然后是使用它的过程,

glEnable(GL_LIGHTING);

GLfloat light_param[] = { 5.0, 5.0, -1.0,1.0 };

glLightfv(GL_LIGHT0GL_POSITIONlight_param);

glEnable(GL_LIGHT0);

放在程序的init函数里面,因为这是初始化的一部分。

他的意思就是启用光照,设置GL_LIGHT0的属性为点光源,他为位置是:[5.0,5.0,-1.0,1.0]对应的其次坐标。我也不知道他具体做什么,现在就当做是他的坐标吧。

这次加了一个键盘监听的处理函数。可以响应键盘按键了,在这个程序中用1,2,3,4等键可以切换灯光。

这次学习的疑惑:

点光源:就是从一点发出的光源,向四周扩散,就相当于一个火把,一个灯泡类型的光。所以他的位置就决定了他的照射的状态。但是奇怪我怎么设置它的光的属性啊,例如我想用一个红色的点光源怎么办?继续学习。他的位置书上说是一个其次坐标,有什么用了,我也不知道。

其他光源的的参数就是个颜色分量的强度,1.0是最强的,0是没有,所以通过个子分量的强度来达到光的效果。不过在我眼里就是颜色的问题。0.5,0.5,0.5就是灰色,1.0,0,0就是红色。呵呵。不过不知道他第四个参数有什么用。什么试了也没有反应,感觉没有效果。

感觉每个GL_LIGHT0都能过设置所有的光源效果,而且是可以叠加的,就是我可以只用GL_LIGHT0可以实现环境光,漫反射光,点光源等。所以要小心,如果你开始设置glLightfv(GL_LIGHT0, GL_POSITION, XXX)的话,然后在重新设置环境光,这里GL_LIGHT0会有两种都有。所以在使用的时候要小心一些。呵呵。

光的衰减还没有学会,继续努力。

感觉OpenGL没有这么学好。不过没有关系,我会一直努力下去的。加油。。

OpenGL学习笔记【7】——材质学习 

今天学习了材质,奉上源代码:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 
float yRot = 0;
unsigned int nPre = 0;
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);
    glLoadIdentity();        //初始变换矩阵为单位矩阵

    GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0};
    GLfloat mat_ambient[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat mat_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat mat_specular[] =  {1.0, 1.0, 1.0, 1.0};
    GLfloat no_shininess[] = {0.0};
    GLfloat low_shininess[] = {5.0};
    GLfloat hig_shininess[] = {100.0};
    GLfloat mat_emission[] = {0.3,0.8, 0.0, 1.0};



    glPushMatrix();            //压入变换矩阵那

    //材质设置有效一直保持到改变为止。

    //第一行第一列的球,仅有慢反射光,而无环境光喝镜面光。
    glPushMatrix();
    glTranslatef(-3.75, 3.0, 0.0);    //第一个球的位置
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();            //弹出矩阵。

    //第一行第二列的球,有漫反射光喝镜面光,低高光,并无环境光
    glPushMatrix();
    glTranslatef(-1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT,GL_AMBIENT, no_mat);    
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT,GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT,GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    //第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光 
    glPushMatrix();
    glTranslatef(1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT,GL_AMBIENT, no_mat);    
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT,GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT,GL_SHININESS, hig_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    //第一行第四列绘制的球有漫反射光和辐射光,而无环境和镜面反射光
    glPushMatrix();
    glTranslatef(3.75, 3.0, 0.0);
    glMaterialfv(GL_FRONT,GL_AMBIENT, no_mat);    
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT,GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT,GL_SHININESS, hig_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    glPopMatrix();        //这里会沿用以前的设置的材质。
    glTranslatef(3.75, 0.0, 0.0);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    
    //其他的不写了。。
    //第二行第一列绘制的球有漫反射光和环境光,而镜面反射光。
    //第二行第二列绘制的球有漫反射光、环境光和镜面光,且有低高光
    //第二行第三列绘制的球有漫反射光、环境光和镜面光,且有很亮的高光
    //第二行第四列绘制的球有漫反射光、环境光和辐射光,而无镜面光
    //第三行第一列绘制的球有漫反射光和有颜色的环境光,而无镜面光。
    //第三行第二列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有低高光
    //第三行第三列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有很亮的高光
    //第三行第四列绘制的球有漫反射光和有颜色的环境光以及辐射光,而无镜面光
    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    glClearColor (0.5, 0.5, 0.5, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)

    
    GLfloat light_diffuse[]= { 0.0, 0.0, 1.0, 1.0};//蓝色        //有灯光才能体现材质的效果,他的灯光的强度是与的关系。貌似是两个相乘什么的。(0-1)范围。
    GLfloat light_position[] = { 0, 3, 2.0, 0.0 };        //设置点光源的矩阵,这个向量也忒奇怪了,1不跟着变,0跟着变,设置为透视之后又是1跟着变,0不跟着变。
    GLfloat light_specular[] = { 1.0, 1.0, 0.0, 1.0 };        //反射光
    GLfloat light_ambient[] = {0.5, 0.5, 0.5, 1.0};

    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);        //,漫射光会产生漫射的效果和高光的效果
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);    //点光源没有漫射光的效果,会一直是黑色的。但会有高光反射的效果。
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);        //反射光基本没有效果。可能是我不知道吧

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);    //如果什么都不设置,GL_LIGHT有默认的值。
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glDepthFunc(GL_LEQUAL);    
    glEnable(GL_DEPTH_TEST);
}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)

    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    //gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10);    //为了不变形,则要长和宽成比例
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutMainLoop();                            //主循环。
    return 0;  
}

1.材质在光的照耀下才能发挥他的作用。没有光,材质是不能显示的。
2.他和光的设置基本一样。光设置的函数是glLightfv(XX,XXX,XX);材质的设置是void glMaterialf(
  GLenum face, //设置材质的面片,是前面,后面,还是双面
  GLenum pname, //材质的类型,是环境光材质,漫反射,反射,高光,辐射光等
  GLfloat param //参数,跟光的参数一样,表示对应的值。
);
材质有环境光,漫反射,镜面反射,辐射,高光等几种设置。里面的颜色参数代表他对该颜色的反射强度,1,最强,0表示完全吸收。也就是说他会跟光做一个乘法。得出来的光就颜色就是反射的我们眼睛的颜色。例如:[1.0,  0.0, 1.0]的材质,本来呈现紫色,如果用[1.0,1.0,1.0]的光去照射就是紫色。如果是[0.0,1.0,1.0]的光照射就是蓝色。因为最后他们各分量相乘得到了[0,0,1]就呈现蓝色了。
4.心的:
补上上次的,点光源设置的是一个位置的向量,他会跟随变换矩阵变化。但是不清楚他的最后一个参数是什么,而且最后一个参数在透视投影和正交投影有相反的表现。哎。还需继续学习。
材质有有保存的,所以如果你设置过材质,一定要注意在新的物体重新设置它的材质,不然会用先前设置的材质。
gluperspective(XXXX)的函数是设置透视矩阵的,因为这次有多个球,想对比更强烈点,书上是用哦正交矩阵
glOrtho(XXX);//他的参数是世界坐标系的点哦。如果想不变形的话,一定要保证长和宽要和窗口的长宽协调。

OpenGL学习笔记【8】——颜色材质

今天学习了颜色材质:奉上源代码:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 
float yRot = 0;
unsigned int nPre = 0;
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);
    glLoadIdentity();        //初始变换矩阵为单位矩阵

    GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0};
    GLfloat mat_ambient[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat mat_diffuse[] = {1.0, 0.0, 0.0, 1.0};
    GLfloat mat_specular[] =  {1.0, 1.0, 1.0, 1.0};
    GLfloat no_shininess[] = {0.0};
    GLfloat low_shininess[] = {5.0};
    GLfloat hig_shininess[] = {100.0};
    GLfloat mat_emission[] = {0.3,0.8, 0.0, 1.0};



    glPushMatrix();            //压入变换矩阵那

    //材质设置有效一直保持到改变为止。
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, hig_shininess);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glColorMaterial(GL_FRONT,GL_DIFFUSE);    //最开始颜色材质对应的是ambient的。所以要给为diffuse
    glColor4f(0,0,0,1);        
    glEnable(GL_COLOR_MATERIAL);        //启动颜色材质


    glPushMatrix();
    glTranslatef(-3.75, 3.0, 0.0);    //第一个球的位置    
    glColorMaterial(GL_FRONT, GL_SHININESS);    //这个事无效的
    glColor4f(0.0, 0.0, 1.0, 1.0);        //颜色材质为蓝色
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();            //弹出矩阵。

    glPushMatrix();
    glTranslatef(-1.25, 3.0, 0.0);
    glColor4f(1.0, 0.0, 1.0, 1.0);    //颜色材质为紫色

    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    glPushMatrix();        
    glTranslatef(1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);    //用设置矩阵堆栈的方式来用材质,发现他以颜色材质为准。
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    //第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光 
    glPushMatrix();
    glTranslatef(1.25, 0.0, 0.0);
    glDisable(GL_COLOR_MATERIAL);        //禁用颜色材质之后,就可以用堆栈方式了。
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    glPushMatrix();        //这里会沿用以前的设置的材质。
    glTranslatef(3.75, 0.0, 0.0);
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();

    glPopMatrix();

    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    glClearColor (0.5, 0.5, 0.5, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)


    GLfloat light_diffuse[]= { 1.0, 1.0, 1.0, 1.0};//蓝色        //有灯光才能体现材质的效果,他的灯光的强度是与的关系。貌似是两个相乘什么的。(0-1)范围。
    GLfloat light_position[] = { 0, 3, 2.0, 0.0 };        //设置点光源的矩阵,这个向量也忒奇怪了,1不跟着变,0跟着变,设置为透视之后又是1跟着变,0不跟着变。
    GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };        //反射光
    GLfloat light_ambient[] = {0.5, 0.5, 0.5, 1.0};

    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);        //,漫射光会产生漫射的效果和高光的效果
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);    //点光源没有漫射光的效果,会一直是黑色的。但会有高光反射的效果。
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);        //反射光基本没有效果。可能是我不知道吧

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);    //如果什么都不设置,GL_LIGHT有默认的值。
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glDepthFunc(GL_LEQUAL);    
    glEnable(GL_DEPTH_TEST);
}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    //gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10);    //为了不变形,则要长和宽成比例
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutMainLoop();                            //主循环。
    return 0;  
} 

他和矩阵堆栈的材质不同,他是通过设置改变材质的什么属性,然后通过颜色来设置材质的,书上说他的效率要高一点。
相关函数;
glEnable(GL_COLOR_MATERIAL);  //启动颜色材质, 允许使用颜色材质。启动之后我们才能通过颜色来设置材质。
glDisable(GL_COLOR_MATERIAL);  //禁用颜色材质,禁用之后就不用颜色材质了。这样可以减小开销。
glColorMaterial(GL_FRONT,GL_DIFFUSE); 设置颜色改变哪个材质属性,和设置材质是差不多的,只是少了一个参数。第一个是材质面,第二个是材质类型枚举:环境光,漫反射等材质类型。
设置了之后我们通过
glColor4f(0,0,0,1); 来更改对应材质类型的材质了。
学习心得:
3.1使用颜色材质的优先级要比使用矩阵的高,也就是说使用了颜色材质设置之后,你的矩阵材质就会失效。
如果你没有设置对应的颜色材质,他才会去看是矩阵材质。所以一定程度上矩阵材质和颜色材质可以共存。他也会保存上一次的材质信息。及时你disable之后再enable,也会保存。所以要注意。
3.2开始使用glEnable(GL_COLOR_MATERIAL)的时候,改变颜色改变的是ambient材质。但是你定位改变材质类型之后,无论你多少次的disable和enable都是改变上次定位的材质属性。
3.3 glColorMaterial.设置颜色材质类型只能使有颜色的类型,例如漫反射,辐射,环境光,反射等,对于高光这种不是颜色中设置不可以的。

OpneGL学习笔记【9】——纹理学习

今天学习了纹理,奉上源代码:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 

/* 创建纹理 */
#define ImageWidth 64
#define ImageHeight 64
GLubyte Image[ImageWidth][ImageHeight][3];
GLfloat sgenparams[] = {1.0,1.0,1.0};

void makeImage(void)
{
    int i, j, r,g,b;
    for (i = 0; i < ImageWidth; i++)
    {
        for (j = 0; j < ImageHeight; j++)
        {
            r=(i*j)%255;
            g=(4*i)%255;
            b=(4*j)%255;
            Image[i][j][0] = (GLubyte) r;
            Image[i][j][1] = (GLubyte) g;
            Image[i][j][2] = (GLubyte) b;
        }
    }
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);
    glLoadIdentity();        //初始变换矩阵为单位矩阵

    glColor3f(1,1,1);        //设置颜色为白色
    
    //绘制一个实心的茶壶
    glPushMatrix ();
    glTranslatef(-4,2,0);
    glFrontFace(GL_CW);
    glutSolidTeapot(1);
    glFrontFace(GL_CCW);
    glPopMatrix ();

    //绘制一个实心的球体
    glPushMatrix();
    glTranslatef(-1, 2, 0);
    glutSolidSphere(1, 32,32);
    glPopMatrix();

    //绘制一个面
    glPushMatrix();
    glFrontFace(GL_CW);
    glBegin(GL_QUADS);
    glTexCoord2f(0,0); glVertex3f(0,0,0);
    glTexCoord2f(0,1); glVertex3f(0,3,0);
    glTexCoord2f(1,1); glVertex3f(3,3,0);
    glTexCoord2f(1,0); glVertex3f(3,0,0);
    glEnd();
    glPopMatrix();



    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    glClearColor (0.5, 0.5, 0.5, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)
    makeImage();        //创建纹理数据
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);    //设置像素存储方式

    glTexImage2D(GL_TEXTURE_2D, 0, 3, ImageWidth, ImageHeight, 
        0, GL_RGB, GL_UNSIGNED_BYTE, &Image[0][0][0]);    //设置纹理信息
    
    //设置s方向纹理重复,为重复设置。
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);    
    //是指t方向的纹理重复,超出1范围的像素纹理都为1处的纹理像素
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);    
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);    

    //设置滤波方式为线性滤波
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    //设置纹理和物体表面颜色处理方式
    //只用纹理颜色,不关心物体表面颜色
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    //和物体表面颜色做与运算。
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    //做融合运算,我还不知道具体是什么东东。
//    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);

    //glEnable(GL_BLEND);

    //自动生成坐标的方式。
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);        
    glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams);


    //如果有自动生成坐标,他就会自动生成,就算你有glTexCoord2f()。
    //glEnable(GL_TEXTURE_GEN_T);
    //glEnable(GL_TEXTURE_GEN_S);                            //启动自动生成s方向自动生成纹理
    glEnable(GL_TEXTURE_2D);                            //启动一维纹理

    

    GLfloat ligPos[] = {0,0,5,0} ;
    glLightfv(GL_LIGHT0, GL_POSITION, ligPos);
    //glEnable(GL_LIGHTING);                                //启动光照
    glEnable(GL_LIGHT0);                                //启动第一个光源light0

    //glEnable(GL_AUTO_NORMAL);                            //XXX不知道
    //glEnable(GL_NORMALIZE);                                //XXx不知道
    //不知道是什么,用了,球就不能正常显示了。,但是不用,茶壶就不能正常显示了。
    //glFrontFace(GL_CW);                                    
    glMaterialf (GL_FRONT, GL_SHININESS, 64.0);            //设置材质的高光为64

    glEnable(GL_DEPTH_TEST);                            //启动深度裁剪
    glDepthFunc(GL_LEQUAL);                                //裁剪方式为小于等于
    glCullFace(GL_BACK);                                //裁剪方式为背面剔除
    glEnable(GL_CULL_FACE);                                //启动面片剔除

}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)

    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    //gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10);    //为了不变形,则要长和宽成比例
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutMainLoop();                            //主循环。
    return 0;  
} 

这章学的太晕,还需要回头再学习,记得当时也是纹理处了问题换的学习方法,这次还是有问题。呵呵。看来基础不好学这里是会卡壳的。学到的主要有:
设置纹理的流程:
创建纹理数据,书上说必须是2的整数倍,而且最小为64。-->设置纹理数据,用glTexImage2D设置一个二维的纹理数据-->设置纹理映射的控制参数,参数主要包括滤波,重复和简约,函数用glTexParameterf()。映射中和物体表面颜色的处理函数用glTexEnvf等。-->启动纹理.glEnable(GL_TEXTURE_2D);--》绘制图形。主要流程就是这样了。
主要函数:
void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width, glsizei height,GLint border,GLenum format,GLenum type, const GLvoid *pixels);Target就设置为GL_TEXTURE_2D, level表示纹理分级的级数,我们现在只有一种纹理,就设置为0参数level表示多级分辨率的纹理图像的级数,若只有一种分辨率,则level设为0。components参数是哪些颜色分量进行调整和混合。具体功能不知道,我用的是3,表示RGB。Width,height参数是像素的宽和高,border是边框大小,format是颜色类型,我选择的是GL_RGB,type是数据的类型,就用GL_UNSIGNED_BYTE,pixels参数就是数据源了。
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);设置重复设置方式,这里是S方向的,也就是说如果纹理坐标超过了这个范围,就从头算的。
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 滤波方式,这里是线性滤波,也就是说算两个像素的插值时用线性的方法算。这样可以更平滑一点。
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); 就是映射中和物体表面颜色的处理方式,我选择的纹理颜色。
初始化就差不多了,还有很多其他的函数,也不完全清楚是做什么的。
在绘制图形的时候,就用glTexCoord2f(0,0); 来确定纹理的坐标。
这次学的晕晕的,以后再回来学习,函数参数的具体说明请看书上,书上说的很好,可惜我没有消化。哎。。。加油。


OpenGL学习笔记【10】——移动光源,光照小结

今天学习了移动光源,奉上源代码:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 

float yRot = 0;
unsigned int nPre = 0;
GLfloat light_position[4] =  {0,0,0,1};        //光位置
GLfloat light_diffuse[4] =  {1,0,1,1};        //光的漫反色
GLfloat light_direction[4] =  {-1, -2, -1, 1};    //光源聚光灯方向
GLfloat light_change[3] =  {3,3,-1};            //光源移动位置。

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);    
    glLoadIdentity();        //初始变换矩阵为单位矩阵

    glTranslated(0,-1,-5);    //平移0,0,-5向Z负方向平移5个单位

    glPushMatrix();        //压缩矩阵,设定光源的位置
    glDisable(GL_LIGHTING);    
    glRotatef(yRot, 0, 1, 0);    //光源的旋转
    glTranslatef(light_change[0],light_change[1],light_change[2]);    //光源的位置
    glTranslatef(light_position[0], light_position[1],light_position[2]);    //光源位置
    
    glutSolidSphere(0.1, 4,4);//利用库函数绘制一个半径为1的球体。表示光源在这里
    glEnable(GL_LIGHTING);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glPopMatrix();
    light_direction[0] = -light_change[0];
    light_direction[1] = -light_change[1];
    light_direction[2] = -light_change[2];
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glPopMatrix();        //光源设置完毕

    glPushMatrix();            //要入矩阵,绘制地面
    glBegin(GL_QUADS);
    glVertex3f(-3,0,3);
    glVertex3f(3,0,3);
    glVertex3f(3,0,-3);
    glVertex3f(-3,0,-3);
    glEnd();
    glPopMatrix();            //地面绘制完毕

    glPushMatrix();            //压入变换矩阵那
    glutSolidSphere(1, 30,30);//利用库函数绘制一个半径为1的球体。
    glPopMatrix();            //弹出矩阵。

    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    //srand(0);    随机种子
    glClearColor (0.5, 0.5, 0.5, 0.0);    //清理颜色,为黑色,(也可认为是背景颜色)
    
    GLfloat light_param[] =  { 1, 1, 1, 1.0 };    //初始化光参数。
    //glLightfv(GL_LIGHT0, GL_AMBIENT, light_param);    //设置光为环境光。
    //glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0); //设置聚光的范围为45度。
    glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,2.0);    //设置聚光灯的聚光强度。
    
    glMaterialfv(GL_FRONT, GL_SPECULAR, light_param);    //设置材质的漫反射属性
    //glMaterialfv(GL_FRONT, GL_AMBIENT, light_param);    //设置材质的环境属性
    glMaterialf(GL_FRONT, GL_SHININESS, 64);    //设置材质的高光属性
    

    glEnable(GL_LIGHTING);        //启动光照
    glEnable(GL_LIGHT0);        //启动GL_LIGHTO光
    glCullFace(GL_BACK);        //剔除背面
    glEnable(GL_CULL_FACE);        //启动剔除
    glDepthFunc(GL_LEQUAL);        //深度检测为小于等于
    glEnable(GL_DEPTH_TEST);    //启动深度检测
    glFrontFace(GL_CCW);        //定义逆时针为正面

}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    //这里小说明一下:矩阵模式是不同的,他们各自有一个矩阵。投影相关
    //只能用投影矩阵。(只是目前情况下哦,等我学多了可能就知道为什么了。)

    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    //glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10);    //为了不变形,则要长和宽成比例
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

void Keyboard(unsigned char key, int x, int y)
{
}

//闲置函数,当主循环空闲时就会调用这个函数
void MyIdle(void)
{
    unsigned int nNow = ::GetTickCount();
    float delt = nNow - nPre;
    if (delt >  100)
     {
        nPre = nNow;
        yRot += 0.1 * delt;    //旋转角度
        /**//*light_diffuse[0] = (rand() % 255) / 255.0;//太花不用了。
        light_diffuse[1] = (rand() % 255) / 255.0;
        light_diffuse[2] = (rand() % 255) / 255.0;*/
        glutPostRedisplay();
    }
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    glutKeyboardFunc(Keyboard);
    glutIdleFunc(MyIdle);
    glutMainLoop();                            //主循环。
    return 0;  
}

学习光源已经好几天,始终入不了门。不过这次学习移动光源之后,有一点点感觉。函数的功能就不能介绍了。书上有,再次分享一下这本书,下载链接为:
http://download.csdn.net/source/1247246
主要心得:
1.每个光源GL_LIGHT0--7都有相应的环境光,点光源,聚光灯,漫射光等所有光的属性,我们设置的属性也只属于这个光源。当光源照射到物体上时,OpenGL的函数会用这些所有的属性与该物体做光照射的计算,实现光的效果。而没有照射到得物体就不会计算。例如设置了环境光为[0.5,0.5,0.5,1.0],漫反射光为[1,0,1,1];如果照射到物体上,他会分别计算环境光的效果和漫射光的效果,然后再叠加他们的效果。叠加方式为取分量的最大值。若物体没有被照射,则所有效果都不会被计算。也就是说会呈现黑色。我开始就没有理解这些属性关系,以为只要设置的环境光之后就能所有物体都能用了。其实不然,只有照射到得物体才会计算。如果想所有物体都有环境光,设置全局环境光才能达到这个效果。
2.什么时候计算光照,在物体绘制的时候光照效果会计算。他会把光照设置光源的属性通过矩阵变换到该物体坐标系中,然后在进行光照计算。也就是他会跟着物体变化。例如:设置了一个点光源在这个物体的前方。如果是通过矩阵变换来改变物体的位置。那么光源会一直在该物体的前方,因为他是以物体坐标系参照的。所以这里要注意,并不是说物体glTranslate(),glRotate()之后光照会发生变化。光的位置也会跟着变,使光照不变化。如果你想光源不随着变化的话,在设置光源位置的时候,就要反着变一下。在设置光源的时候,也可以用平移旋转的能矩阵运算。
3.两个物体之间光照是否有影响:两个物体光照不会有影响,也就是说不会出现一个物体遮住另一个物体的情况。因为他是在一个物体的物体坐标系中计算效果的,而且只对该物体计算效果。所以不会对其他物体产生影响,如果要真实,就得自己算出阴影在绘制。我还没有学会。呵呵。如果不想物体产生光照,就用glDisable(GL_LIGHTIING);就可以了。在绘制其他物体再启动他。
4.聚光灯:聚光灯我是没有弄懂的,特别是他的方向,很晕很晕。感觉是向量,有感觉不像向量。到底怎么回事还得努力学习,希望能碰到高手指点一下。
5.其他方面:
glFrontFace(GL_CW); 确定顺时针为front面,默认是GL_CCW既逆时针为正面。所以在绘制茶壶和球的时候会出问题,在绘制一个矩形的时候也要注意这个问题。

OpenGL学习笔记【11】——融合学习

今天学习了a的透明通道,书上说是融合,反正一个意思。奉上源代码:

#pragma comment(lib, "glaux.lib")
#include "gl/glaux.h"
#include 

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色数据和深度数据(清屏)
    glColor3f(1.0,1.0,1.0);    
    glLoadIdentity();        //初始变换矩阵为单位矩阵
    glPushMatrix();

    glBegin(GL_QUADS);

    //绘制两个矩形,他们位置相同,主要是看融合后的效果
    glColor4f(0.0, 1.0, 0.0, 0.5);        
    glVertex3f(-2, 3, -2);
    glVertex3f(-2, -1, -2);
    glVertex3f(2, -1, -2);
    glVertex3f(2, 3, -2);

    glColor4f(1.0, 1.0, 0.0, 0.3);
    glVertex3f(-2, 3, -2);
    glVertex3f(-2, -1, -2);
    glVertex3f(2, -1, -2);
    glVertex3f(2, 3, -2);
    glEnd();
    glPopMatrix();

    glDisable(GL_BLEND);    //关闭融合

    //绘制一个没有融合的举行,把颜色设置和计算后一样的颜色。
    //看看是不是学对公式了。呵呵
    glBegin(GL_QUADS);        
    glColor4f(0.65,1.0,0.35, 1);
    glVertex3f(-4, 3, -3);
    glVertex3f(-4, -1, -3);
    glVertex3f(-2, -1, -3);
    glVertex3f(-2, 3, -3);
    glEnd();
    glEnable(GL_BLEND);


    glutSwapBuffers();            //交换缓冲区。显示图形
}

//初始化
void init (void) 
{
    glClearColor(1,1,1, 0);        //清除颜色,也是背景颜色
    glEnable(GL_BLEND);            //启动混合

    //源的融合因子用他颜色的a值,目标物体的融合因子用1-源物体的a值。
    //这是用的最多的融合规则。
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glShadeModel(GL_FLAT);

    //glEnable(GL_LIGHTING);    
    //glEnable(GL_LIGHT0);

    //glEnable(GL_COLOR_MATERIAL);
    //glColorMaterial(GL_FRONT, GL_DIFFUSE);
    

    //glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDisable(GL_DEPTH_TEST);
    //glDepthMask( GL_FALSE );    //据说是深度检测只读。不会用。
}

//当窗口大小改变时,会调用这个函数
void reshape(GLsizei w,GLsizei h)
{
    glViewport(0,0,w,h);        //设置视口
    glMatrixMode(GL_PROJECTION);    //设置矩阵模式为投影变换矩阵,
    glLoadIdentity();                //变为单位矩阵
    //gluPerspective(60, (GLfloat)w / h, 0, 1000);    //设置投影矩阵
    glOrtho(-6.0, 6.0, -6.0 * h / w, 6.0* h / w, -10, 10);    //为了不变形,则要长和宽成比例
    glMatrixMode(GL_MODELVIEW);        //设置矩阵模式为视图矩阵(模型)
    glLoadIdentity();                //变为单位矩阵
}

void Keyboard(unsigned char key, int x, int y)
{
}

//闲置函数,当主循环空闲时就会调用这个函数
void MyIdle(void)
{
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);        //Opnegl初始化
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA); //设置显示模式为双缓冲,RGEBA

    glutInitWindowSize (800, 600);            //窗口大小
    glutInitWindowPosition (100, 100);        //窗口位置
    glutCreateWindow ("hello");                //创建一个标题为hello的窗口
    init ();                                //初始化资源,这里一定要在创建窗口以后,不然会无效。
    glutDisplayFunc(display);                //窗口大小改变时的回调
    glutReshapeFunc(reshape);                //绘制图形时的回调
    //glutKeyboardFunc(Keyboard);
    //glutIdleFunc(MyIdle);
    glutMainLoop();                            //主循环。
    return 0;  
}

主要的心得:
怎样开启alpha通道:开启alpha 也是调用OpenGL的函数,函数名为glEbable(GL_BLEND);blend我查字典是融合混合的意思。开启之后我们还要设置融合的参数设置,调用函数是:glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 这两句调用好了,我们就能看到融合效果了。画两个矩形试试。。
融合的顺序:因为融合需要两个或多个物体来算他们各自颜色的比例,从而组成一个新的颜色,例子就是玻璃窗看外面的树。玻璃窗式透明的,透过玻璃窗看树,树的颜色是玻璃窗和树本生颜色的融合。我们叫玻璃窗为源物体,树为目标物体。因此,在前面的物体时源物体,透过源物体看到的物体我称之为目标物体。他应该在源物体的后面。在程序中也一样,2D中先画的物体在后画物体的后面。所以后画的问题在融合中充当源物体的角色,先画的是目标物体。当我们绘制物体的时候,绘制一个时,我们会先把他作为源物体和他后面的物体做融合计算。当然如果只有一个就和背景颜色做融合计算。然后计算之后就是融合的值。然后我们画下一个物体的时候,他会跟这个已经融合计算的目标物体做新的融合计算。再次算出画这个物体呈现的颜色。大概就是这样了吧。例如物体A[0.6,0.6,1,0.8],在绘制的时候他会跟背景颜色[0.5,0.5,0.5,0]做融合,得到[0.58,0.58,0.9]的颜色值,作为他的颜色。然后绘制物体B[0.1,0.9,0.5,0.5],他和A相交的部分与A算出的颜色做融合计算得到[0.32,0.72, 0.7]就为B最后的颜色。他的计算就差不多了。
融合参数设置:用到融合的时候,颜色都是glColor4f(1.0,1.0,1.0,1.0);来表示的,前三个值表示物体的RGB颜色。最后一个值就是alpha通道,是不透明度。也就是说1表示完全不透明,0表示完全透明,中间就是不透明的比率了。之后不透明度还不够,我们是用一个融合的函数计算融合值,他与不透明度有关系,但是不透明度并不完全表示他的融合参数。我们怎么设置融合参数呢:就是用glBlendFunc(XXX, XXX);来设置的,他的主要参数包括在这个表内:

常数

相关因子

计算后得到的融合因子

GL_ZERO

源因子或目的因子

(0,0,0,0)

GL_ONE

源因子或目的因子

(1,1,1,1)

GL_DST_COLOR

源因子

(Rd,Gd,Bd,Ad)

GL_SRC_COLOR

目的因子

(Rs,Gs,Bs,As)

GL_ONE_MINUS_DST_COLOR

源因子

(1,1,1,1)-(Rd,Gd,Bd,Ad)

GL_ONE_MINUS_SRC_COLOR

目的因子

(1,1,1,1)-(Rs,Gs,Bs,As)

GL_SRC_ALPHA

源因子或目的因子

(As,As,As,As)

GL_ONE_MINUS_SRC_ALPHA

源因子或目的因子

(1,1,1,1)-(As,As,As,As)

GL_DST_ALPHA

源因子或目的因子

(Ad,Ad,Ad,Ad)

GL_ONE_MINUS_DST_ALPHA

源因子或目的因子

(1,1,1,1)-(Ad,Ad,Ad,Ad)

GL_SRC_ALPHA_SATURATE

源因子

(f,f,f,1);f=min(As,1-Ad)

表15-1 源因子和目的因子

这些设置参数有什么用:有这么多的参数,他们的作用就是计算确定融合因子的规则,融合因子就是计算融合颜色时候的比例。他的格式为[Sr,Sg,Sb,Sa]对应着物体相对颜色的比例,例如Sr就是对应着红色的比例,他和物体颜色计算的公式是[Rs*Sr Gs*Sg, Bs*Sb, As*Sa]。就这样就计算了一个物体融合后本来颜色的值,不过等等,还有他后面的目标物体呢?目标物体也是根据这个算出来的。公式一样,不过他的表示为[Rd*Dr, Gd*Dg, Bd*Db, Ad*Da]。也就是说,这样有两个融合因子,一个源物体的,一个是目标物体的。然后各自去和对应的颜色算值得到各自的比重,然后我们把他们加起来就是最后的颜色值了。
[Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da]
如何的计算看了,怎么读上面的表呢?第一栏是宏值,用他就能在函数里设定融合因子的规则了。第二列没有什么大的用处,就是说这个规则适用于哪类物体。第三列就是融合的规则了,他对应计算后的融合因子,例如:GL_SRC_APHA 这个融合方式,他的计算规制对应的是:(As,As,As,As)也就是他的融合因子为[Sr,Sg,Sb,Sa] = [As,As,As,As];就是他的a值例如物体A的颜色为[0.4,0.7,0.6,0.3]那他对应的融合因子就为[0.3,0.3,0.3,0.3]。然后在看一个GL_SRC_COLOR的融合计算,上一个颜色,计算的融合因子结果[0.4,0.7,0.6,0.3]。因为他的规则就是物体的颜色。然后我们再根据融合因子和物体颜色求出物体颜色分量。我们对源物体和目标物体都做这样的计算之后用上面的公式得出总的颜色结果,就是融合后的颜色。
这里举个例子:
源颜色为[1.0, 0.0, 0.0, 0.3] 目标物体颜色为[0.0, 1.0, 0.0, 0.8];
如果采用glBendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)这样的参数来处理融合因子:这计算的为:源融合因子计算结果:[0.3, 0.3, 0.3] 地想融合因子为[1,1,1] - [0.3,0.3,0.3] = [0.7,0.7,0.7];融合因子算出来了。通过上面的公式算出最后的颜色为
[1.0 * 0.3 + 0.0 * 0.7, 0.0*0.3+1.0*0.7,0.0*0.3+0.0*0.7 ] = [0.3,0.7,0];

要想3D情况中使用透明,也就是深度不同的情况能出现透明效果,必须要吧深度检测去掉,不然深度检测会剔除不可见物体,这不能达到透明效果了。不过对于z一样的情况下,去掉不去掉深度检测都一样。如果希望能既有深度检测,又有透明效果,可以先开启深度检测,绘制不透明物体,关闭深度检测,绘制透明物体。深度检测启动和禁用的方法不能在glBegin(); glEnd()中,必须在这连个函数的外面。关闭深度检测之后要注意,谁先画谁在后面。而不是看深度了。
遇到的问题:背景也会被融合,所以要注意背景的颜色。融合中可以用光照,裁剪,但是不要用深度检测。如果是在测试融合的结果的话,最好把光照光闭,刚才就因为开了光照总觉得颜色不对,还以为是我公式没有学对,其实是光照的效果。启动关闭融合的时候,不能在glBegin(); glEnd()。这里面只能是绘制图形相关的。以后少玩点游戏,大把时间都浪费掉了。

glPushMatrix();
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
glColor4f(0.0, 1.0f, 0.0f, 0.5f);
glTranslatef(0.20f, 0.0f, 0.0f);
this->drawCube(0.60f, 1.0f, 1.0f, 0.1f);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}   


 






你可能感兴趣的:(MFC,include,dll,c)