OpenGL中的3D文字绘制

转自http://blog.csdn.net/augusdi/article/details/20572533

代码如下:

/*****************************************新添加的代码*****************************************/  
#include <Windows.h>  
#include <stdio.h>                                                   //标准输入/输出库的头文件  
#include <math.h>                                                    //数学库  
#include <stdarg.h>                                                  //用来定义可变参数的头文件  
/**********************************************************************************************/  
#include <GL/glut.h>                                                 //包含OpenGL实用库  
#pragma comment(lib,"glut32.lib")  
  
  
HDC       hDC   = NULL;                                              //窗口着色描述表句柄  
HWND      hWnd  = NULL;                                              //保存窗口句柄  
HGLRC     hGLRC = NULL;                                              //OpenGL渲染描述表句柄  
HINSTANCE hInstance;                                                 //保存程序的实例  
  
BOOL keys[256];                                                      //保存键盘按键的数组  
BOOL active     = TRUE;                                              //窗口的活动标志, 缺省为TRUE  
BOOL fullscreen = TRUE;                                              //全屏标志, 缺省为全屏模式  
UINT winWidth   = 640,                                               //窗体宽度  
     winHeight  = 480,                                               //窗体高度  
     winBits    = 16;                                                //颜色深度(可选8/16/32)  
  
/*****************************************新添加的代码*****************************************/  
GLuint base;                                                         //绘制字体的显示列表的开始位置  
GLYPHMETRICSFLOAT gmf[256];                                          //保存256个轮廓字体显示列表中对应的每一个列表的位置和方向的信息  
  
void BuildFont()  
{  
    HFONT font, oldfont;                                             //字体句柄, 旧的字体句柄  
  
    base = glGenLists(256);                                          //创建256个显示列表  
    font = CreateFont(                                               //创建字体  
        -24,                                                         //字体高度(告诉Windows寻找基于CHARACTER高度的字体.如果是正数, 就寻找基于CELL的高度相匹配的字体)  
        0,                                                           //字体宽度(使用默认值)  
        0,                                                           //字体的旋转角度Angle Of Escapement  
        0,                                                           //字体底线的旋转角度Orientation Angle  
        FW_BOLD,                                                     //字体的重量(0-1000)[FW_DONTCARE是0, FW_NORMAL是400, FW_BOLD是700, FW_BLACK是900]  
        FALSE,                                                       //是否使用斜体  
        FALSE,                                                       //是否使用下划线  
        FALSE,                                                       //是否使用删除线  
        ANSI_CHARSET,                                                //设置字符集  
        OUT_TT_PRECIS,                                               //输出精度  
        CLIP_DEFAULT_PRECIS,                                         //裁剪精度  
        ANTIALIASED_QUALITY,                                         //输出质量  
        DEFAULT_PITCH | FF_DONTCARE,                                 //Pitch And Family  
        "Times New Roman"                                            //字体名称  
    );  
  
    oldfont = (HFONT)SelectObject(hDC, font);                        //选择需要的字体  
    wglUseFontOutlines(                                              //使用Windows的wgl函数来创建字体  
        hDC,                                                         //设置当前窗口设备描述表的句柄  
        0,                                                           //用于创建显示列表字体的第1个字符的ASCII值  
        255,                                                         //字符数  
        base,                                                        //第1个显示列表的名称  
        0.0f,                                                        //字体的光滑度, 越小越光滑, 0.0为最光滑的状态  
        0.2f,                                                        //在Z方向突出的距离(即轮廓字体的厚度)  
        WGL_FONT_POLYGONS,                                           //使用多边形来生成字符, 每个顶点具有独立的法线(WGL_FONT_LINES:使用线形生成字符)  
        gmf                                                          //一个接收字形度量数据的数组的地址, 每个数组元素用它对应的显示列表字符的数据填充  
    );  
    SelectObject(hDC, oldfont);                                      //选择原来的字体  
    DeleteObject(font);                                              //删除字体  
}  
  
void glPrintf(const char *fmt, ...)  
{  
    if(!fmt) return;                                                 //如果无输入则返回  
  
    char text[256];                                                  //保存文字串  
    va_list ap;                                                      //指向一个变量列表的指针  
    va_start(ap, fmt);                                               //分析可变参数  
        vsprintf(text, fmt, ap);                                     //把参数值写入字符串  
    va_end(ap);                                                      //结束分析  
  
    /将字符串居中/  
    float length = 0.0f;                                             //保存字符串的长度  
    for(UINT i=0;i<strlen(text);i++){                                //查找整个字符串的长度  
        length += gmf[text[i]].gmfCellIncX;                          //计算轮廓后字符串的宽度(gmfCellIncX表示显示位置从已绘制上的上一个字符向右移动的真正距离)  
    }  
    glTranslatef(-length/2.0f, 0.0f, 0.0f);                          //把字符串置于最左边  
    //  
  
    glPushAttrib(GL_LIST_BIT);                                       //把显示列表属性压入属性堆栈  
    glListBase(base);                                                //设置显示列表的基础值为0  
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);               //调用显示列表绘制字符串  
    glPopAttrib();                                                   //弹出属性堆栈  
}  
  
void KillFont()                                                      //删除显示列表  
{  
    glDeleteLists(base, 256);                                        //删除256个显示列表  
}  
/**********************************************************************************************/  
  
//重置OpenGL窗口大小  
GLvoid ReSizeGLScene(UINT width, UINT height)  
{  
    if(height <= 0){ height = 1; }                                   //防止被零除且防止负数存在  
  
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);               //重置当前的视口  
  
    glMatrixMode(GL_PROJECTION);                                     //选择投影矩阵  
    glLoadIdentity();                                                //重置投影矩阵  
  
    gluPerspective(45.0f, (GLdouble)width / (GLdouble)height, 0.1f, 100.0f); //设置视口的大小  
  
    glMatrixMode(GL_MODELVIEW);                                      //选择模型观察矩阵  
    glLoadIdentity();                                                //重置模型观察矩阵  
}  
  
//对OpenGL窗口进行初始化设置  
BOOL InitGL(GLvoid)  
{  
    glShadeModel(GL_SMOOTH);                                         //启用阴影平滑  
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);                            //黑色背景  
    glClearDepth(1.0f);                                              //设置深度缓存  
    glEnable(GL_DEPTH_TEST);                                         //启用深度测试  
    glDepthFunc(GL_LEQUAL);                                          //所作深度测试的类型  
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);               //告诉系统对透视进行修正  
/*****************************************新添加的代码*****************************************/  
    BuildFont();                                                     //创建字体  
/**********************************************************************************************/  
    return TRUE;                                                     //初始化成功  
}  
  
//从这里开始进行所有的绘制  
BOOL DrawGLScene(GLvoid)  
{  
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);              //清除屏幕和深度缓存  
    glLoadIdentity();                                                //重置当前的模型观察矩阵  
/*****************************************新添加的代码*****************************************/  
    static GLfloat rot = 0.0f;                                       //旋转变量  
    glTranslatef(0.0f, 0.0f, -15.0f);                                //移入屏幕15个单位  
  
    glRotatef(rot, 1.0f, 0.0f, 0.0f);                                //沿X轴旋转  
    glRotated(rot * 1.5f, 0.0f, 1.0f, 0.0f);                         //沿Y轴旋转  
    glRotatef(rot * 1.4f, 0.0f, 0.0f, 1.0f);                         //沿Z轴旋转  
  
    /根据字体位置设置颜色/  
    float r = 1.0f * float(cos(rot / 20.0f)),                        //红色  
          g = 1.0f * float(sin(rot / 25.0f)),                        //绿色  
          b = 1.0f - 0.5f * float(cos(rot / 17.0f));                 //蓝色  
    glColor3f(r, g, b);                                              //设置颜色  
    //  
  
    glPrintf("3D Active OpenGL Text - %3.2f", rot / 50);             //输出文字到屏幕  
  
    rot += 0.5f;                                                     //增加旋转变量  
/**********************************************************************************************/  
    return TRUE;                                                     //绘制场景成功  
}  
  
//销毁窗口  
GLvoid KillGLWindow(GLvoid)  
{  
    if(fullscreen)                                                  //是否处于全屏模式  
    {  
        ChangeDisplaySettings(NULL, 0);                              //切换回桌面  
        ShowCursor(TRUE);                                            //显示鼠标指针  
    }  
  
    if(hGLRC)  
    {                                                       //是否拥有OpenGL描述表  
        if(!wglMakeCurrent(NULL, NULL))  
        {                                                   //是否已释放DC和RC描述表  
            MessageBox(NULL, "释放DC或RC失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        }  
  
        if(!wglDeleteContext(hGLRC))  
        {                                                   //是否已删除RC  
            MessageBox(NULL, "释放RC失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        }  
        hGLRC = NULL;                                                //将RC设为NULL  
    }  
  
    if(hDC && !ReleaseDC(hWnd, hDC))  
    {                                //是否已释放DC  
        MessageBox(NULL, "释放DC失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        hDC = NULL;                                                  //将DC设为NULL  
    }  
  
    if(hWnd && !DestroyWindow(hWnd))  
    {                                //是否已销毁窗口  
        MessageBox(NULL, "销毁窗口失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        hWnd = NULL;                                                 //将hWnd设为NULL  
    }  
  
    if(!UnregisterClass("OpenGL", hInstance))  
    {                       //是否已注销类  
        MessageBox(NULL, "注销窗口类失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        hInstance = NULL;                                            //将hInstance设为NULL  
    }  
/*****************************************新添加的代码*****************************************/  
    KillFont();                                                      //删除字体  
/**********************************************************************************************/  
}  
  
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){  
    //WndProc(窗口的句柄, 窗口的消息, 附加的消息内容, 附加的消息内容)  
    switch(uMsg)  
    {                                                    //检查Windows消息  
        case WM_ACTIVATE:                                            //监视窗口激活消息  
            if(!HIWORD(wParam))  
            {                                     //检查最小化状态  
                active = TRUE;                                       //程序处于激活状态  
            }  
            else  
            {  
                active = FALSE;                                      //程序不再激活  
            }  
            return 0;                                                //返回消息循环  
  
        case WM_CLOSE:                                               //收到Close消息  
            PostQuitMessage(0);                                      //发出退出消息  
            return 0;                                                //返回  
  
        case WM_KEYDOWN:                                             //有键被按下  
            keys[wParam] = TRUE;                                     //设为TRUE  
            return 0;                                                //返回  
  
        case WM_KEYUP:                                               //有键被放开  
            keys[wParam] = FALSE;                                    //设为FALSE  
            return 0;                                                //返回  
  
        case WM_SIZE:                                                //调整OpenGL窗口大小  
            ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));           //LoWord=Width, HiWord=Height  
            return 0;                                                //返回  
  
        case WM_SYSCOMMAND:                                          //系统中断命令  
            switch(wParam)  
            {                                          //检查系统调用  
                case SC_SCREENSAVE:                                  //运行屏保  
                case SC_MONITORPOWER:                                //显示器要进入节电模式  
                    return 0;                                        //阻止发生  
            }  
            break;                                                   //退出  
    }  
    return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}  
  
BOOL CreateGLWindow(const char *title, UINT width, UINT height, UINT bits, BOOL fullscreenflag)  
{  
    //CreateGLWindow(标题, 宽度, 高度, 颜色的位深, 是否使用全屏模式)  
    GLuint   PixelFormat;                                            //保存查找匹配的结果  
    DWORD    dwStyle, dwExStyle;                                     //窗口风格, 扩展窗口风格  
    RECT     WindowRect;                                             //取得矩形的左上角和右下角的坐标值  
    WNDCLASS wc;                                                     //窗口类结构  
  
    hInstance  = GetModuleHandle(NULL);                              //取得我们窗口的实例  
    fullscreen = fullscreenflag;                                     //设置全局全屏标志  
  
    WindowRect.top    = (long)0;                                     //将Top    设为 0  
    WindowRect.left   = (long)0;                                     //将Left   设为 0  
    WindowRect.right  = (long)width;                                 //将Right  设为要求的宽度  
    WindowRect.bottom = (long)height;                                //将Bottom 设为要求的高度  
  
    /* 
            像素格式明确了OpenGL绘制平面的特性, 如象素缓冲区是单缓冲还是双缓冲, 数据是 RGBA方式还是Color Index方式等.每个OpenGL显示设 
        备一般用名为PIXELFORMATDESCRIPTOR的结构来表示某个的像素格式, 这个结构包含26个属性信息.Win32定义PIXELFORMATDESCRIPTOR如下所示: 
 
        typedef struct tagPIXELFORMATDESCRIPTOR 
        { //pfd 
          WORD  nSize;           //是象素格式描述子结构的大小, sizeof(PIXELFORMATDESCRIPTOR)设定其值 
          WORD  nVersion;        //是PIXELFORMATDESCRIPTOR结构的版本, 一般设为1 
          DWORD dwFlags;         //是一组表明象素缓冲特性的标志位, 如缓冲是否支持GDI或OpenGL等 
          BYTE  iPixelType;      //说明象素数据类型是RGBA还是颜色索引 
          BYTE  cColorBits;      //每个颜色缓冲区中颜色位平面的数目, 对颜色索引方式是缓冲区大小 
          BYTE  cRedBits;        //每个RGBA颜色缓冲区中红色位平面的数目 
          BYTE  cRedShift;       //每个RGBA颜色缓冲区中红色位平面的偏移数 
          BYTE  cGreenBits;      //每个RGBA颜色缓冲区中绿色位平面的数目 
          BYTE  cGreenShift;     //每个RGBA颜色缓冲区中绿色位平面的偏移数 
          BYTE  cBlueBits;       //每个RGBA颜色缓冲区中蓝色位平面的数目 
          BYTE  cBlueShift;      //每个RGBA颜色缓冲区中蓝色位平面的偏移数 
          BYTE  cAlphaBits;      //每个RGBA颜色缓冲区中alpha位平面的数目(保留的, 现不支持) 
          BYTE  cAlphaShift;     //每个RGBA颜色缓冲区中alpha位平面的偏移数(保留的, 现不支持) 
          BYTE  cAccumBits;      //累加缓冲区中全部位平面的数目 
          BYTE  cAccumRedBits;   //累加缓冲区中红色位平面的数目 
          BYTE  cAccumGreenBits; //累加缓冲区中绿色位平面的数目 
          BYTE  cAccumBlueBits;  //累加缓冲区中蓝色位平面的数目 
          BYTE  cAccumAlphaBits; //累加缓冲区中alpha位平面的数目 
          BYTE  cDepthBits;      //Z(深度)缓冲区的深度 
          BYTE  cStencilBits;    //模板缓冲区的深度 
          BYTE  cAuxBuffers;     //轴向缓冲区的数量(一般1.0版本不支持) 
          BYTE  iLayerType;      //被忽略, 为了一致性而包含的 
          BYTE  bReserved;       //表层和底层平面的数量::位0-3表最多15层表层平面, 位4-7表底层 
          DWORD dwLayerMask;     //被忽略, 为了一致性而包含的 
          DWORD dwVisibleMask;   //是透明色彩的值(RGBA方式)或是一个底层平面的索引(Index) 
          DWORD dwDamageMask;    //被忽略, 为了一致性而包含的 
        } PIXELFORMATDESCRIPTOR; 
    */  
  
    const PIXELFORMATDESCRIPTOR pfd =                                //pfd告诉窗口使用的像素格式  
    {  
        sizeof(PIXELFORMATDESCRIPTOR),                               //上述格式描述符的大小  
        1,                                                           //版本号  
        PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,  //格式支持双缓冲, 支持窗口, 支持OpenGL  
        PFD_TYPE_RGBA,                                               //申请RGBA格式  
        bits,                                                        //选定色彩深度  
        0, 0, 0, 0, 0, 0, 0, 0,                                      //忽略的色彩位(前6位), 无Alpha缓存(第7位), 忽略Shift Bit(第8位)  
        0,                                                           //无累加缓存  
        0, 0, 0, 0,                                                  //忽略聚集位  
        16,                                                          //16位Z-缓存(深度缓存)   
        0,                                                           //无蒙板缓存  
        0,                                                           //无辅助缓存  
        PFD_MAIN_PLANE,                                              //主绘图层  
        0,                                                           //不使用重叠层  
        0, 0, 0                                                      //忽略层遮罩  
    };  
  
    wc.cbClsExtra     = 0;                                           //无额外窗口数据  
    wc.cbWndExtra     = 0;                                           //无额外窗口数据  
    wc.hbrBackground  = NULL;                                        //GL不需要背景  
    wc.hCursor        = LoadCursor(NULL, IDC_ARROW);                 //装入鼠标指针  
    wc.hIcon          = LoadIcon(NULL, IDI_WINLOGO);                 //装入缺省图标  
    wc.hInstance      = hInstance;                                   //设置实例  
    wc.lpfnWndProc    = (WNDPROC)WndProc;                            //WndProc处理消息  
    wc.lpszClassName  = "OpenGL";                                    //设定类名字  
    wc.lpszMenuName   = NULL;                                        //不需要菜单  
    wc.style          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;          //移动时重画, 并为窗口取得DC  
  
    if(!RegisterClass(&wc))  
    {                                                                //尝试注册窗口类  
        MessageBox(NULL, "注册窗口类错误!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //退出并返回FALSE  
    }  
  
    if(fullscreen)  
    {                                                                //尝试全屏模式  
        DEVMODE dmScreenSettings;                                    //设备模式  
        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));      //确保内存清空为零  
        dmScreenSettings.dmSize       = sizeof(dmScreenSettings);    //DEVMODE结构的大小  
        dmScreenSettings.dmBitsPerPel = bits;                        //每象素所选的色彩深度  
        dmScreenSettings.dmPelsWidth  = width;                       //所选屏幕宽度  
        dmScreenSettings.dmPelsHeight = height;                      //所选屏幕高度  
        dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;  
  
        //尝试设置显示模式并返回结果(注:CDS_FULLSCREEN 移去了状态条)  
        if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)  
        {  
            if(MessageBox(NULL, "全屏模式失败!是否使用窗口模式?", "错误", MB_YESNO | MB_ICONQUESTION) == IDYES)  
            {  
                fullscreen = FALSE;                                  //选择窗口模式  
            }  
            else  
            {  
                MessageBox(NULL, "程序退出!", "错误", MB_OK | MB_ICONSTOP);  
                return FALSE;                                        //退出并返回FALSE  
            }  
        }  
    }  
  
    if(fullscreen)  
    {                                                                //仍处于全屏模式  
        dwStyle   = WS_POPUP;                                        //窗体风格  
        dwExStyle = WS_EX_APPWINDOW;                                 //扩展窗体风格  
        ShowCursor(FALSE);                                           //隐藏鼠标指针  
    }  
    else  
    {  
        dwStyle   = WS_OVERLAPPEDWINDOW;                             //窗体风格  
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;              //扩展窗体风格  
    }  
  
    AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);      //调整窗口达到真正要求的大小  
  
    if(!(hWnd = CreateWindowEx(dwExStyle,                            //扩展窗体风格  
                               "OpenGL",                             //类名字  
                               title,                                //窗口标题  
                               dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, //必须的窗体风格属性  
                               0, 0,                                 //窗口左上角X坐标和Y坐标位置  
                               WindowRect.right - WindowRect.left,   //计算调整好的窗口高度的宽度  
                               WindowRect.bottom - WindowRect.top,   //计算调整好的窗口高度的高度  
                               NULL,                                 //无父窗口  
                               NULL,                                 //无菜单  
                               hInstance,                            //实例  
                               NULL))){                              //不向WM_CREATE传递任何信息  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "窗口创建失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //窗口创建失败  
    }  
  
    if(!(hDC = GetDC(hWnd)))  
    {                                                                //是否取得设备描述表  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "创建设备描述表失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //创建设备描述表失败  
    }  
  
    if(!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))  
    {                                                                //是否Windows找到相应的象素格式  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "没有相匹配的像素格式!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //没有相匹配的像素格式  
    }  
  
    if(!SetPixelFormat(hDC, PixelFormat, &pfd))  
    {                                                                //是否能设置象素格式  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "设置像素格式失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //设置像素格式失败  
    }  
  
    if(!(hGLRC = wglCreateContext(hDC)))  
    {                                                                //是否能取得OpenGL渲染描述表  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "创建OpenGL渲染表失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //创建OpenGL渲染表失败  
    }  
    if(!wglMakeCurrent(hDC, hGLRC))  
    {                                                                //尝试激活着色描述表  
        KillGLWindow();                                              //重置显示区  
        MessageBox(NULL, "激活当前OpenGL渲染表失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //激活当前OpenGL渲染表失败  
    }  
  
    ShowWindow(hWnd, SW_SHOW);                                       //显示窗口  
    SetForegroundWindow(hWnd);                                       //略略提高优先级  
    SetFocus(hWnd);                                                  //设置键盘的焦点至此窗口  
    ReSizeGLScene(width, height);                                    //设置透视GL屏幕  
  
    if(!InitGL())  
    {                                                                //初始化新建的GL窗口  
        KillGLWindow();  
        MessageBox(NULL, "初始化失败!", "错误", MB_OK | MB_ICONEXCLAMATION);  
        return FALSE;                                                //初始化失败  
    }  
  
    return TRUE;                                                     //创建窗口成功  
}  
  
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)  
{  
    //WinMain(当前窗口实例, 前一个窗口实例, 命令行参数, 窗口显示状态)  
    MSG  msg;                                                        //Windowsx消息结构  
    BOOL done = FALSE;                                               //用来退出循环的BOOL变量  
  
    winWidth  = 640;                                                 //定义窗口宽度  
    winHeight = 480;                                                 //定义窗口高度  
    winBits   = 16;                                                  //定颜色深度为  
  
    //提示用户选择运行模式  
    if(MessageBox(NULL, "是否使用全屏模式?", "OpenGL", MB_YESNO | MB_ICONQUESTION) == IDNO)  
    {  
        fullscreen = FALSE;                                          //FALSE为窗口模式  
    }  
  
    //创建OpenGL窗口  
    if(!CreateGLWindow("OpenGL", winWidth, winHeight, winBits, fullscreen))  
    {  
        return 0;                                                    //失败退出  
    }  
    while(!done)  
    {                                                                //保持循环直到done=TRUE  
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))  
        {                                                            //是否在等待消息  
            if(msg.message == WM_QUIT)  
            {                                                        //收到退出消息  
                done = TRUE;                                         //是, 则done=TRUE  
            }  
            else  
            {                                                        //不是, 处理窗口消息  
                TranslateMessage(&msg);                              //翻译消息  
                DispatchMessage(&msg);                               //发送消息  
            }  
        }  
        else  
        {  
            //如果没有消息  
            //绘制场景。监视ESC键和来自DrawGLScene()的退出消息  
            if(active)  
            {                                              //程序是否激活  
                if(keys[VK_ESCAPE])  
                {                                                    //是否ESC按下  
                    done = TRUE;                                     //ESC发出退出信号  
                }  
                else  
                {                                                    //不是退出的时候, 刷新屏幕  
                    DrawGLScene();                                   //绘制场景  
                    SwapBuffers(hDC);                                //交换缓存(双缓存)  
                }  
            }  
  
            if(keys[VK_F1])  
            {                                                        //是否按下F1键  
                keys[VK_F1] = FALSE;                                 //若是, 使对应的Key数组中的值为FALSE  
                KillGLWindow();                                      //销毁当前的窗口  
                //切换全屏/窗口模式  
                if(!CreateGLWindow("OpenGL", winWidth, winHeight, winBits, !fullscreen))  
                {                                                    //重建OpenGL窗口  
                    return 0;                                        //如果窗口未能创建, 程序退出  
                }  
            }  
        }  
    }  
    //关闭程序  
    KillGLWindow();                                                  //销毁窗口  
    return msg.wParam;                                               //退出程序  
}  


 
(暂时只支持英文)

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.创建一个OpenGL窗口: 在这个教程里,我将教你在Windows环境创建OpenGL程序.它将显示一个空的OpenGL窗口,可以在窗口和全屏模式下切换,按ESC退出.它是我们以后应用程序的框架. 理解OpenGL如何工作非常重要,你可以在教程的末尾下载源程序,但我强烈建议你至少读一遍教程,然后再开始编程. 2.你的第一个多边形: 在第一个教程的基础上,我们添加了一个三角形和一个四边形。也许你认为这很简单,但你已经迈出了一大步,要知道任何在OpenGL绘制的模型都会被分解为这两种简单的图形。 读完了这一课,你会学到如何在空间放置模型,并且会知道深度缓存的概念。 3.添加颜色: 作为第二课的扩展,我将叫你如何使用颜色。你将理解两种着色模式,在左图,三角形用的是光滑着色,四边形用的是平面着色。 注意三角形上的颜色是如何混合的。 颜色为OpenGlL 工程增加很多。通过理解平面着色(flat coloring)和平滑着色(smooth coloring),你能显著的改善你的OpenGL Demo的样子。 4.旋转: 在这一课里,我将教会你如何旋转三角形和四边形。左图的三角形沿Y轴旋转,四边形沿着X轴旋转。 这一章将引入两个变量, rtri 被用来存储三角形的角度, rquad存储四边形的角度。 和容易创建一个多边形组成的场景。让这些物体动起来是整个场景变得生动起来。在后面的课程钟我将教给你如何绕屏幕上的一个点旋转物体,使得物体绕屏幕而不是它的轴转动。 5.3D形体: 既然我们已经领会到多边形,方形,色彩和旋转。现在该建立3D物体了。我将使用多边形和矩形c创建3D物体。这次我们将扩展上一章的教程,并且将三角形转换成一个彩色的棱锥,把正方形变为一个实心正方体。棱锥使用混合色,正方体每个面使用一种颜色。在3D空间创建物体可能很费时间,但是所获得的结果(收获)值得这样做。充分发挥你的想象力吧。 6.纹理映射: 你想要它,它现在就在这里了,那就是 ... 纹理映射!!!在这一章我将教会你如何将一幅位图(bitmap)映射到正方体的六个面上去。我们将使用第一章的OpenGL代码来创建工程。创建一个空的窗口比修改上一课的代码更容易。 你将会发现第一章的代码在对于快速创建工程来说是及其有价值的。第一章的代码为你设置好了一切,你所需要做的只是集精力为效果编程。 7.纹理滤波, 光照和键盘控制: 好的,我希望到现在你已经理解了所有的东西,因为这是一个巨大的教程。我想教给你两个新的方法来过滤(filter)你的纹理,简单的光照,键盘控制并且还可能更多 :) .如果你对到这一课为止你所学的东西并不充满信心,那就回头复习一下。玩一下其它课程的代码,不要操之过急。最好专心把每一课学好,而不是蜻蜓点水,只知道如何把东西做出来。 8.混合 有理由等一下,一个来自很酷的Hypercosm的程序员伙伴问(我)他是否可以写一章关于混合的教程。第八课通常正是讲混合的,所以太巧了。这一章教程扩展了第七章。混合是一项很酷的技术 .. 我希望你们能好好享受这一章教程。这一章的作者是Tom Stanis他在这制作一章上花费了很多精力,所以让他知道你觉得怎么样。混合可不是一个好讲的话题。 9.在3D空间移动位图: 这一章覆盖了一些你们要求的主题,你想知道如何移动你在3D屏幕空间上创造的物体。你想要知道如何在屏幕上绘制一幅位图,并且位图的黑色部分不会覆盖它后面的东西。你想要简单的动画,想要更多的混合的应用,这一章将教会你所有这些。You'll notice there's no spinning boxes(yaker:很惭愧这一句我不是很明白)。前面的课程覆盖了OpenGL的基础,每一章都基于前面的内容。前面的课程涵盖了基础的OpenGL,每一课都是在前一课的基础上创建的。这一课是前面几课知识的综合,当你学习这课时,请确保你已经掌握了前面几课的知识。 10.加载3D世界,并在其漫游: 你一直期待的教程来了!这一章友一个叫Lionel Brites的伙伴制作。这一课里你讲学到如何导入一个3D世界。代码仍然使用第一章的,但是,课程页面只是解释了新的部分,包括导入3D场景,在3D世界移动。下载VC++代码并且在你阅读教程的同时阅读代码。按[B]键控制混合,[F]键控制滤波,[L]键控制光照(但光并不随场景移动),还有[Page UP]和[Page Down]键。我希望你能喜欢Lionel对网站的贡献。我有空的时候我会让这个教程更容易学习。 11.旗帜效果 (飘动的纹理): 这一章教程由Bosco带给你。他就是那个创造了很酷的小Demo: worthless的家伙。他喜欢每个人对他的Demo的反映,并且决定更进一步,在他的Demo的最后解释他怎么实现这么酷的效果的。这一章教程构建在第六章的代码之上。阅读完这一章之后,你将能弯曲,折叠以及操纵你自己的纹理。这绝对是个很漂亮的效果,并且比纹理固定的旗帜好得多。如果你喜欢这一章,请发邮件给bosco让他知道。 12.显示列表 想知道如何加速你的OpenGL程序么?每次为放置一个物体在屏幕上而写很多代码让你厌烦了吧?如果是这样,这一章就是为你准备的。学习如何用OpenGL来显示列表。只用一行代码预构建和显示物体。使用预编译物体加速你的程序。不要再一次又一次写重复的代码。让显示列表为你做所有的工作吧!这一章里我们将建造Q-bert金字塔(Q-bert是一款游戏),感谢显示列表,我们只需要用不多的几行代码。 13.位图字体 这一课我们将创建一些基于2D图像的字体,它们可以缩放,但不能旋转,并且总是面向前方,但作为基本的显示来说,我想已经够了。 14.图像字体 在一课我们将教你绘制3D的图形字体,它们可像一般的3D模型一样被变换。 15.图形字体的纹理映射: 这一课,我们将在上一课的基础上创建带有纹理的字体,它真的很简单。 16.看起来很酷的雾 这一课是基于第7课的代码的,你将学会三种不同的雾的计算方法,以及怎样设置雾的颜色和雾的范围。 17.2D 图像文字 在这一课,你将学会如何使用四边形纹理贴图把文字显示在屏幕上。你将学会如何把256个不同的文字从一个256x256的纹理图像分别提取出来,并为每一个文字创建一个显示列表,接着创建一个输出函数来创建任意你希望的文字。 18.二次几何体 利用二次几何体,你可以很容易的创建球,圆盘,圆柱和圆锥。 19.粒子系统 你是否希望创建爆炸,喷泉,流星之类的效果。这一课将告诉你如何创建一个简单的例子系统,并用它来创建一种喷射的效果。 20.蒙板 到目前为止你已经学会如何使用alpha混合,把一个透明物体渲染到屏幕上了,但有的使用它看起来并不是那么的复合你的心意。使用蒙板技术,将会按照你蒙板的位置精确的绘制。 21.线,反走样,计时,正投影和简单的声音 这是我第一个大的教程,它将包括线,反走样,计时,正投影和简单的声音。希望这一课的东西能让每个人感到高兴。 22.凹凸映射,多重纹理扩展 这是一课高级教程,请确信你对基本知识已经非常了解了。这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果。 23.球面映射 这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样。 24.符号,扩展,剪裁和TGA图像文件的加载 在这一课里,你将学会如何读取你显卡支持的OpenGL的扩展,并在你指定的剪裁区域把它显示出来。 25.变形和从文件加载3D物体 在这一课,你将学会如何从文件加载3D模型,并且平滑的从一个模型变换为另一个模型。 26.剪裁平面,蒙板缓存和反射 在这一课你将学会如何创建镜面显示效果,它使用剪裁平面,蒙板缓存等OpenGL一些高级的技巧。 27.阴影 这是一个高级的主题,请确信你已经熟练的掌握了基本的OpenGL,并熟悉蒙板缓存。当然它会给你留下深刻的印象的。 28.贝塞尔曲面 这是一课关于数学运算的,没有别的内容了。来,有信心就看看它吧。 29.Blitter 函数 类似于DirectDraw的blit函数,过时的技术,我们有实现了它。它非常的简单,就是把一块纹理贴到另一块纹理上。 30.碰撞检测 这是一课激动的教程,你也许等待它多时了。你将学会碰撞剪裁,物理模拟太多的东西,慢慢期待吧。 31.模型加载 你知道大名鼎鼎的Milkshape3D建模软件么,我们将加载它的模型,当然你可以加载任何你认为不错的模型。 32.拾取, Alpha混合, Alpha测试, 排序 这又是一个小游戏,交给的东西会很多,慢慢体会吧 33.加载压缩和未压缩的TGA文件 在这一课里,你将学会如何加载压缩和为压缩的TGA文件,由于它使用RLE压缩,所以非常的简单,你能很快地熟悉它的。 34.从高度图生成的美丽地形 这一课将教会你如何从一个2D的灰度图创建地形 35.在OpenGL播放AVI视频 在OpenGL如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL,虽然很慢,但它的效果不错。你可以试试。 36.放射模糊和渲染到纹理 如何实现放射状的滤镜效果呢,看上去很难,其实很简单。把渲染得图像作为纹理提取出来,在利用OpenGL本身自带的纹理过滤,就能实现这种效果,不信,你试试。 37.卡通映射 什么是卡通了,一个轮廓加上少量的几种颜色。使用一维纹理映射,你也可以实现这种效果。 38.从资源文件载入图像 如何把图像数据保存到*.exe程序,使用Windows的资源文件吧,它既简单又实用。 39.物理模拟简介 还记得高的物理吧,直线运动,自由落体运动,弹簧。在这一课里,我们将创造这一切。 40.绳子的模拟 怎样模拟一根绳子呢,把它想象成一个个紧密排列的点,怎么样有了思路了吧,在这一课你你将学会怎样建模,简单吧,你能模拟更多。 41.体积雾 把雾坐标绑定到顶点,你可以在雾漫游,体验一下吧。 42.多重视口 画画效果,很酷吧。使用视口它变得很简单,但渲染四次可会大大降低你的显示速度哦:) 43.在OpenGL使用FreeType库 使用FreeType库可以创建非常好看的反走样的字体,记住暴雪公司就是使用这个库的,就是那个做魔兽世界的。尝试一下吧,我只告诉你了基本的使用方式,你可以走的更远。 44.3D 光晕 当镜头对准太阳的时候就会出现这种效果,模拟它非常的简单,一点数学和纹理贴图就够了。好好看看吧。 45.顶点缓存 你想更快地绘制么?直接操作显卡吧,这可是前沿的图形技术,不要犹豫,我带你入门。接下来,你自己向前走吧。 46.全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据。看看吧,驱动程序为你做完了一切。 47.CG 顶点脚本 nVidio的面向GPU的C语言,如果你相信它就好好学学吧,同样这里也只是个入门。记住,类似的语言还有微软的HLSL,OpenGL的GLSL,ATI的shaderMonker。不要选错哦:) 48.轨迹球实现的鼠标旋转
第1章 初识openscenegraph(osg). 1 1.1 场景图形初步 2 1.1.1 场景图形的概念 2 1.1.2 具体实现:三维渲染引擎 2 1.1.3 主流渲染引擎介绍 3 1.2 openscenegraph概述 4 1.2.1 诞生与发展 4 1.2.2 优势与不足 5 1.3 openscenegraph的组成结构 6 1.3.1 核心结构 6 1.3.2 资源获取 8 1.3.3 文社区 8 第2章 osg的安装与调试 9 2.1 快速安装和使用 10 2.1.1 下载预编译包 10 2.1.2 设置环境变量 11 2.1.3 建立工程环境 13 2.1.4 范例:第一个程序 15 2.2 从源代码进行编译 16 2.2.1 osg源代码的获取与更新 16 .2.2.2 编译环境生成工具cmake 19 2.2.3 基本编译选项 22 2.2.4 高级编译选项 25 2.3 调试输入与输出 28 2.3.1 命令行输入 28 2.3.2 调试输出 29 第3章 开发预备知识 31 3.1 基本数学组件 32 3.1.1 二维与多维向量 32 3.1.2 四元数 35 3.1.3 矩阵 37 3.1.4 包围体 41 3.2 数组对象 44 3.2.1 数据数组 44 3.2.2 数据索引数组 46 3.3 内存管理机制 47 3.3.1 智能指针 48 3.3.2 参照对象 51 3.3.3 范例:智能指针的使用 52 第4章 场景的组织结构 55 4.1 节点的定义与种类 56 4.1.1 场景图形bvh树 56 4.1.2 节点的父子关系 58 4.1.3 叶节点与组节点 59 4.1.4 节点的功能与分类 62 4.2 节点的访问 65 4.2.1 访问器机制 65 4.2.2 节点的遍历函数 67 4.2.3 范例:节点属性访问器 68 4.2.4 节点的更新与事件回调 70 4.2.5 范例:使用回调实现旋转动画 71 4.3 重要节点的功能实现 74 4.3.1 空间变换节点 74 4.3.2 范例:使用空间变换节点 79 4.3.3 开关节点 81 4.3.4 范例:使用开关节点 82 4.3.5 细节层次节点(lod) 83 4.3.6 范例:使用lod节点 85 4.3.7 范例:节点代理 86 第5章 绘制几何对象与文字 89 5.1 几何元素的储存 90 5.1.1 顶点属性 90 5.1.2 顶点数组、显示列表和vbo 91 5.1.3 构建几何体对象 94 5.1.4 范例:简易房屋 100 5.2 几何元素的绘制与访问 103 5.2.1 几何体的绘制实现函数 103 5.2.2 数据的更新显示 108 5.2.3 几何体的更新回调 109 5.2.4 范例:跃动的线 110 5.2.5 信息获取和统计 112 5.2.6 范例:使用仿函数遍历几何体 113 5.3 位图的显示 116 5.3.1 图像与图像的绘制 116 5.3.2 范例:在场景绘制位图 119 5.4 文字的显示 120 5.4.1 文字绘制方法 120 5.4.2 文字绘制实现函数 123 5.4.3 字符编码格式 124 5.4.4 范例:一首古诗 127 第6章 设置纹理和渲染属性 131 6.1 渲染属性与模式 132 6.1.1 opengl的渲染状态设置 132 6.1.2 节点的渲染状态集合 132 6.1.3 渲染属性概览 135 6.2 纹理与纹理属性 139 6.2.1 纹理的实现方法 139 6.2.2 纹理的分类 143 6.2.3 范例:场景的纹理设置 146 6.2.4 范例:纹理的明细层次(mipmap) 149 6.3 属性的实现与访问 152 6.3.1 将属性应用到场景 152 6.3.2 渲染状态集回调 153 6.3.3 范例:雾参数的实时更新 153 6.4 osg与opengl着色语言 155 6.4.1 opengl着色语言 155 6.4.2 着色器属性 159 6.4.3 一致变量回调 162 6.4.4 范例:在场景使用glsl着色语言 162 第7章 观察我们的世界 167 7.1 场景的观察与变换 168 7.1.1 opengl的变换 168 7.1.2 相机节点 171 7.1.3 范例:鸟瞰图相机 174 7.2 图形设备接口 176 7.2.1 图形设备与相机 176 7.2.2 窗口与像素缓存(pixel buffer) 179 7.2.3 渲染到纹理(render to texture) 181 7.2.4 范例:将场景渲染到纹理 183 7.3 视景器 186 7.3.1 视景器的主要工作 186 7.3.2 单视景器与多视景器 188 7.3.3 范例:投影墙显示 191 7.3.4 范例:多视景器系统 192 7.3.5 视景器辅助部件 194 第8章 人机交互与图形用户接口 197 8.1 获取鼠标和键盘消息 198 8.1.1 事件适配器 198 8.1.2 动作适配器 202 8.1.3 事件队列与处理器 203 8.1.4 范例:处理键盘事件.. 205 8.2 三维人机交互工具 207 8.2.1 漫游器 207 8.2.2 拖曳器 210 8.2.3 范例:场景拖曳器的实现 214 8.3 二维图形用户接口 217 8.3.1 窗口设备 217 8.3.2 windows下窗口设备的实现 219 8.3.3 范例:使用windows api构建渲染窗口 221 第9章 场景的动画效果 225 9.1 场景动画基本组件 226 9.1.1 关键帧 226 9.1.2 采样与插值 228 9.1.3 动画频道 231 9.1.4 动画更新回调 236 9.1.5 范例:关键帧路径动画 239 9.2 刚体动画 242 9.2.1 简单路径动画 242 9.2.2 范例:使用路径动画回调 244 9.2.3 动画的多频道融合 245 9.2.4 范例:基本动画管理器 246 9.3 角色与变形动画 249 9.3.1 骨骼动画 249 9.3.2 范例:骨骼运动 252 9.3.3 变形体 255 9.3.4 范例:对折硬纸 257 9.4 渲染状态与纹理动画 259 9.4.1 渐进动画(ease motion) 259 9.4.2 范例:物体的淡入淡出 262 9.4.3 纹理动画 264 9.4.4 范例:纹理动画效果 266 第10章 文件的读写机制 269 10.1 数据文件支持机制 270 10.1.1 文件格式概述 270 10.1.2 osg支持的文件格式 272 10.1.3 基本文件读写接口 277 10.2 文件读写插件 279 10.2.1 插件的编写和注册 279 10.2.2 插件的职责链机制 283 10.2.3 文件读写回调 285 10.3 插件设计方法 287 10.3.1 范例:简单插件设计 287 10.3.2 范例:文件读取进度 290 10.4 osg(即.osg)格式及其扩展 292 10.4.1 封装器 292 10.4.2 场景扩展库插件 295 第11章 场景的动态更新与裁减 297 11.1 场景的更新流程 298 11.1.1 人机交互事件的更新 298 11.1.2 用户请求与系统调度的更新 299 11.2 场景的裁减流程 300 11.2.1 裁减的意义与常用技术 300 11.2.2 裁减访问器 303 11.2.3 状态树与状态节点 305 11.2.4 状态树的构建 309 11.2.5 裁减回调 312 11.3 数据的动态调度 313 11.3.1 动态调度技术概述 313 11.3.2 分页数据库 314 11.3.3 范例:分页lod节点 316 11.3.4 分页图像库 318 第12章 场景的多线程渲染 319 12.1 多线程开发技术概述 320 12.1.1 多线程开发的常用概念 320 12.1.2 openthreads库简介 321 12.1.3 范例:线程的创建与控制 324 12.1.4 osg操作线程 325 12.2 基本场景渲染流程 327 12.2.1 osg状态机 327 12.2.2 构建场景渲染树 333 12.2.3 渲染树的优化排序 338 12.2.4 范例:广告牌森林 339 12.3 多种线程模型的讨论与实现 341 12.3.1 渲染器与场景视图 341 12.3.2 单线程模型 347 12.3.3 多设备裁减/绘制模型 348 12.3.4 多设备绘制模型 349 12.3.5 多相机绘制模型 350 12.3.6 数据变度 351 第13章 开源社区与未来 353 13.1 基于osg的开源工程 354 13.1.1 地形与地理信息 354 13.1.2 特效实现 356 13.1.3 扩展节点组件 358 13.1.4 数据和场景管理 358 13.1.5 其他语言封装 360 13.2 开发者资源 360 13.2.1 实用网址 360 13.2.2 用户群体简介 361 13.3 十条箴言 363 主要参考资料... 365
本书介绍了应用OpenGL开发三维图形的方法。内容包括:怎样利用Visual C 5.0 MFC的类建立OpenGL应用程序的基本格式,建立和控制2D形状和3D形体、标准二次曲面、Bezier曲线及曲面、NURBS曲线及曲面、点光源、无限光源、聚光、基本材质、贴图材质、Mip贴图、位图字符、文字OpenGL动画等,观察物体,操作像素、位图、图像,融合和反走样物体,雾化场景,利用帧缓存进行颜色屏蔽、深度控制、遮掩、全局场景反走样、景深模拟和场景对焦效果处理,利用对话框、菜单、鼠标选择物体、信息反馈实现OpenGL基本的交互图形程序设计。最后,本书通过6个实用例程说明如何将OpenGL的建模技术、图像处理技术和人机交互技术等3大技术进行结合。 本书涉及了所有的OpenGL核心函数和实用库函数,注重OpenGL的内存联系和实际运用。书的每个工程文件模式固定且十分简洁,内容循序渐进。本书配有CD-ROM一张,包含了书所有源程序和18个工程文件所生成的可执行文件等内容,帮助读者学习。本书适合于具有基本计算机图形学基础知识及Visual C 5.0 MFC编程基础知识的计算机软件开 图书目录: 第1章 走进三维真彩世界 第2章 OpenGL概述 第3章 极小化OpenGL 第4章 绘制二维图形 第5章 OpenGL变换 第6章 显示列表 第7章 模拟真实世界 第8章 OpenGL动画 第9章 OpenGL图像处理基础 第10章 纹理贴图 第11章 增强图像效果 第12章 实用库函数 第13章 曲线和曲面 第14章 高级制作技术 第15章 交互技术 第16章 制作技术与应用实例 附录 配书CD-ROM内容介绍

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值