踏入OpenGL大门——VS2015开发环境配置:测试环境、永久配置环境、解决常见错误(详细图文)

承接上文,以下就让我们来测试下配置的开发环境能否正常工作。

编写代码,让我们简单的创建一个窗口先。

导入头文件,注意 #pragma comment(lib,"glew32.lib")(经测试,这个glew库文件在2015中必须显式包含——代码包含或者在附加依赖项中添加

另外需要注意的是:glew.h需要先包含在前面,然后才是freeglut.h

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO:  在此处引用程序需要的其他头文件
#include <glew.h> // 注意glew.h在前面,然后才是freeglut.h
#include <freeglut.h>
#pragma comment(lib,"glew32.lib") // 你也可以在项目->属性->链接器->输入->附加依赖项中添加这个库文件
#include <iostream>
using namespace std;

main函数代码,创建一个窗口(注意未调用OpenGL的代码,只是调用freeglut、glew的代码)。

// 第一个OpenGL程序.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"


void displayFunc();
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutCreateWindow("第一个OpenGL程序");
    if (glewInit())
    {
        cerr << "Unable to initialize GLEW ... exiting" << endl;
        exit(EXIT_FAILURE);
    }
    glutDisplayFunc(displayFunc);
    glutMainLoop();
    return 0;
}

void displayFunc()
{

}

运行结果:


测试OpenGL开发环境,测试结果:glew、freeglut均能正常工作

使用《OpenGL开发指南 原书第8版》的第一章例子测试开发环境

让我们重新创建一个工程,重新配置OpenGL开发环境之后,再编写一个较为复杂的程序——这个程序是OpenGL红宝书的第一章的例子

不过这个例子还需要另外一些文件才行,你需要在这里下载必需文件。

解压下载的文件之后,工程中和原先一样配置glew、freeglut的包含目录、库目录、显式包含glew32.lib库文件、exe同目录下需要复制 .dl文件之外,还需要在包含目录加入 ...\oglpg-8th-edition\include路径,在库目录加入 ...\oglpg-8th-edition\bin路径,工程中添加LoadShaders.cpp文件:

包含目录中添加该路径
库目录中加入该路径

然后在工程中的解决方案上右键,添加现有项:

在解决方案上右键添加现有项
添加LoadShaders.cpp文件

把 triangles.vert, triangles.frag文件复制到工程目录下:


找到 triangles.vert, triangles.frag文件
复制到工程目录下

另外需要注意的是,如果运行窗口上的三角形是白色,并且控制台输出错误提示: 类似version: 450 字样,这说明当前电脑的显卡不支持这个版本的OpenGL;

这个只需查看你的电脑的显卡支持的OpenGL版本,然后把triangles.frag、triangles.vert文件中的版本修改为我们当前电脑的OpenGL版本即可(version: 450 是OpenGL最新版本4.5,但当前大多数显卡只支持到4.4,即version 440):

运行窗口上的三角形是白色,并且控制台输出错误提示: version:450 字样

假设你的显卡支持的OpenGL版本是4.4,那么,修改值为440,如果显卡支持的OpenGL版本是4.3,则修改为430,依次类推:

.vert文件的修改 假设你的显卡支持的OpenGL版本是4.4,那么,修改值为440,如果显卡支持的OpenGL版本是4.3,则修改为430,依次类推
.frag文件的修改,假设你的显卡支持的OpenGL版本是4.4,那么,修改值为440,如果显卡支持的OpenGL版本是4.3,则修改为430,依次类推

查看本机显卡支持的OpenGL版本,可以自行百度如何查看OpenGL版本,这个OpenGLExtension Viewer可以为你帮助。

输入代码

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO:  在此处引用程序需要的其他头文件

#include <GL/glew.h>
#include <GL/freeglut.h> 
#include <vgl.h>
#include <LoadShaders.h>
#pragma comment(lib,"glew32.lib")

#include <iostream>
using namespace std;
```
```
// 1.2 初识OpenGL程序.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, Numbuffer };
enum Attrib_IDs { vPosition = 0 };

GLuint VAOs[NumVAOs];
GLuint Buffers[Numbuffer];
const GLuint NumVertives = 6;

void init()
{
    glGenVertexArrays(NumVAOs, VAOs);
    glBindVertexArray(VAOs[Triangles]);

    GLfloat vertives[NumVertives][2] = {
        {-0.90,-0.90},
        { 0.85,-0.90},
        {-0.90, 0.85},
        { 0.90,-0.85},
        { 0.90, 0.90},
        {-0.85, 0.90}
    };
    glGenBuffers(Numbuffer, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertives), vertives, GL_STATIC_DRAW);
    ShaderInfo shaders[] = {
        {GL_VERTEX_SHADER, "triangles.vert"},
        {GL_FRAGMENT_SHADER, "triangles.frag"},
        {GL_NONE, NULL}
    };
    GLuint program = LoadShaders(shaders);
    glUseProgram(program);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(vPosition);
}

void displayFunc();
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowSize(512, 512);
    glutInitContextVersion(4, 3);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutCreateWindow(argv[0]);
    if (glewInit())
    {
        cerr << "Unable to initialize GLEW ... exiting" << endl;
        exit(EXIT_FAILURE);
    }
    init();
    glutDisplayFunc(displayFunc);
    glutMainLoop();
    return 0;
}
void displayFunc()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, NumVertives);

    glFlush();
}
```
**注意: 如果提示“无法打开freeglutd.lib”,则在VC++目录中的库目录需要包含freeglut的Debug下的lib文件;如果提示“无法打开freeglut.lib”,则在VC++目录中的库目录需要包含Release下的lib.文件**

####运行结果
![测试结果:glew、freeglut、OpenGL都可以正常使用](http://upload-images.jianshu.io/upload_images/1490569-a66c20502c0b68f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


#永久配置OpenGL开发环境
折腾了半天,我们知道了一个OpenGL程序的运行,需要使用到glew、freeglut的所有.h、对应版本的 .lib、.dll文件,只要把这些文件一次性配置好,一个OpenGL程序需要的环境就基本配置完毕。

随便打开一个VS工程,点击项目->属性->VC++目录,查看包含目录或库目录发现,VS本身配置有默认值:

![VS包含目录中设置的默认值](http://upload-images.jianshu.io/upload_images/1490569-8e468d81e0f917cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这些默认值在不同电脑、不同版本的系统中对应的路径是不同的,找到这些路径就成了我们永久配置OpenGL环境的关键——**只要把glew、freeglut必需的 .h文件、.lib文件复制到VS默认的包含目录和库目录中即可**。

这样复制之后,**以后再创建任何OpenGL程序时,就不需要在配置包含目录和库目录了,只需要在exe同目录下复制相应的 .dll 文件**即可。

这种办法不止适用与OpenGL的配置,任何库的配置都可以这样配置,就算是其他编译器,如XCode,也可以这样配置,参照的原理是一样。

**但有一点要格外注意,在操作VS默认的目录时,要格外小心,不然麻烦只会更多;一旦操作不当,很可能就是给自己挖一个隐藏的大坑。**

####好了,那么以下,我们就小心翼翼的在VS默认目录中尝试配置下glew、freeglut
之前我们已经知道我们需要的文件其实只有两类:.h文件、.lib文件 —— 显然,.h文件要拷贝到VS的包含目录中、.lib文件则要拷贝到库目录中。

剩下的问题就是找到VS默认目录,那么我们现在再次新建一个C++控制台工程。

找VS默认目录的方法上面也介绍了,我们先来看看包含目录(**注意你此时的电脑很大很大的可能和下图显示内容不同,这是正常的,不必惊慌。继续向下阅读...**):
![计算的值和继承的值](http://upload-images.jianshu.io/upload_images/1490569-1a22ec28677f66bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

即使我们不知道微软把计算的值和继承的值定义为何种含义,我们也能猜出来:计算的值表示这台电脑的VS将默认目录的实际文件路径——可以复制这个路径,直接可以直达它指示的位置;而继承的值,从名称上看,显然意思是表示两类路径:VC的路径、windowSDK的路径。

好了,还记得OpenGL的头文件所在位置嘛?  好吧,我也忘记了,我们重新找出来。

输入#include <gl\GL.h>、右键打开文档、再右键打开所在的文件夹:

```
#include <gl\GL.h>
```
... 具体步骤常见[上文开头部分](http://www.jianshu.com/p/68c314fa9fea)...
![操作结果](http://upload-images.jianshu.io/upload_images/1490569-ee2c532a024a4d7f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![对比结果](http://upload-images.jianshu.io/upload_images/1490569-cf612fd8aeb45f60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

显而易见,我们找到我们想要的东西了,我觉得OpenGL相关的内容,就让我们永久配置在上图那个默认的文件夹中吧,这样好找也容易归类。
####OpenGL的 .h文件 永久配置
笔者在这个gl文件夹下创建了 glew 2.0.0、freeglut 3.0.0文件夹,并拷贝相关.h文件到里面,读者可以随意命名,位置随意(如果你真的明白这么做的意义):
![gl文件夹下创建glew 2.0.0文件夹,并拷贝相应.h文件进来。](http://upload-images.jianshu.io/upload_images/1490569-8b96c2a2be70575b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![gl文件夹下创建freeglut 3.0.0文件夹,并拷贝相应.h文件进来。](http://upload-images.jianshu.io/upload_images/1490569-7f76d297237ce01c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**好了,OpenGL的包含目录永久配置完成。**
####OpenGL的 lib 文件永久配置
库目录也类似,找到VS默认库目录,选择一个合适的位置,然后拷贝文件进入。但是VS的默认库目录路径却只有32位的,没有表示64位的默认库目录,

![VS默认库目录样式](http://upload-images.jianshu.io/upload_images/1490569-7fd5168da5db70d9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我们该如何抉择?是在这个目录下拷贝64位的进去还是32位的呢?看起来貌似哪个都行的通。

其实主要看你创建的应用程序是32位还是64位,进一步理解[可以在这里可以获得帮助](http://blog.csdn.net/github_27886083/article/details/45456809):
简单而言,此时:

![创建的是32位应用程序还是64位应用程序](http://upload-images.jianshu.io/upload_images/1490569-a68aff50f5acdd2d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
若你创建的是32位应用程序则拷贝32位 .lib文件即可;反之,创建的是64位应用程序,则拷贝64位 .lib文件即可。

那么我们的现在创建的是32位应用程序,则选择32的.lib文件拷贝进去:
![打开VS的一个默认库目录文件夹,拷贝glew的32位 .lib 文件进入即可](http://upload-images.jianshu.io/upload_images/1490569-98941b3633931610.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

至于拷贝freeglut的 .lib 文件之前,你确认用CMake编译好了的VS2015工程环境是否是32位的,确认后那么干脆再F6编译下,然后再拷贝文件到上图路径中:

![笔者在32位&Release下,再次编译工程。](http://upload-images.jianshu.io/upload_images/1490569-a5cfa12a649d518b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如图拷贝freeglut的.lib文件到VS默认的32位库目录中,**建议读者在Release和Debug模式下分别编译依次,然后拷贝里面的 .lib文件。**

![拷贝了6个.lib文件](http://upload-images.jianshu.io/upload_images/1490569-6aa5657be284897d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**OpenGL的库目录永久配置完毕**

好,此时,就可以拷贝 动态链接库到exe同目录下,然后编写OpenGL代码了,

下面就是简单的复制、粘贴,只有在引入头文件时有一些变化:
```
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO:  在此处引用程序需要的其他头文件
#include <gl\glew 2.0.0\glew.h>
#pragma comment(lib,"glew32.lib")
#include <gl\freeglut 3.0.0\freeglut.h>

#include <iostream>
using namespace std;
```
```
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"



void displayFunc();
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutCreateWindow("第一个OpenGL程序");
    if (glewInit())
    {
        cerr << "Unable to initialize GLEW ... exiting" << endl;
        exit(EXIT_FAILURE);
    }
    glutDisplayFunc(displayFunc);
    glutMainLoop();
    return 0;
}

void displayFunc()
{

}
```

![运行结果:正常](http://upload-images.jianshu.io/upload_images/1490569-101db2ef80a77b8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####OpenGL dll文件永久配置
如果这些dll文件你也不想每次都拷贝,想要像OpenGL相关头文件、库文件一样永久配置它们,那么你可以依照以下的操作,把dll文件永久配置到系统中。

关于dll 拷贝到系统目录时需要考虑的细节,[在这里可以给你更详细的帮助](http://tieba.baidu.com/p/3337331207),简单而言,就是要注意你本机系统是那种类型的(32位?64位?):
![将dll文件拷贝到系统目录中](http://upload-images.jianshu.io/upload_images/1490569-931f8dd7dfda3843.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


glew、freeglut都有32位和64位的dll文件,我们依次拷贝即可(**freeglut需要分别在Win32、Win64的工程中,才能编译生成期望的文件**):

笔者是64位系统,所以稍微复杂点,如下图(freeglut需要Win64环境,进行编译后,才能生成64位的dll,[请阅读上文介绍CMake Configure 选择VS编译器时选择Win64...](http://www.jianshu.com/p/68c314fa9fea)):
![拷贝32位dll到SysWOW64文件夹中](http://upload-images.jianshu.io/upload_images/1490569-a8dcb3b988d75742.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![拷贝64位dll到System32文件夹中](http://upload-images.jianshu.io/upload_images/1490569-862c89ee3161d953.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**OpenGL 所需的dll文件永久配置完毕**

删除原来在工程exe同目录下的所有dll文件,运行工程:
![删除原来在工程exe同目录下的所有dll文件](http://upload-images.jianshu.io/upload_images/1490569-9d4557a27bd05cd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![运行正常](http://upload-images.jianshu.io/upload_images/1490569-5db3e05d999f49e2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**在处理系统目录时,请务必不要乱动文件,当遇到不知道有什么作用的文件时,就什么也不要做**

#解决常见错误
> - **无法打开文件“xxx.lib”** 
**如:无法打开文件“freeglutd.lib”  —— 这种错误原因是编译器需要使用 该lib文件时,却在相应的目录(VC++目录中库目录的添加的所有路径)中找不到;此时,可以添加手动缺少库文件(添加库文件路径或拷贝库文件到VS一个默认库目录中);如果依然提示该错误,可是再添加代码(如 `#pragma comment(lib,"glew32.lib")`)加载该lib;当提示无法打开“freeglutd.lib”时,[除了手动添加相应库文件(添加库文件路径或拷贝库文件到VS一个默认库目录中)之外,你也可以在 项目->属性->C/C++ ->预处理器->预处理器定义->编辑中输入NDEBUG即可](http://blog.csdn.net/yapingxin/article/details/46440307)。**
![无法打开文件“freeglut.lib” 或者 无法打开文件“freeglutd.lib“ 或者 无法打开文件“glew32.lib”](http://upload-images.jianshu.io/upload_images/1490569-b33aebadd57e117f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- **无法解析外部符号_imp_glewInit@0 
该错误的原因是,程序要中使用了一个名称,但没有链接到该名称的实现部分,就好像是你声明了一个函数,却忘记实现这个函数了,这时就会出现这种错误;而如果无法解析的外部符号中有gl、glew、glut字样时,表示相应的OpenGL实现、glew实现、glut实现不存在,其中一个可能原因是相应的 .lib 文件没有加载到,例如没有加载到glew32.lib文件,而程序中又调用了某glew系列函数,这时,系统就会报无法解析外部符号的错误。
![无法解析外部符号: glew字样的符号 或者 无法解析外部符号: glut字样的符号、无法解析外部符号: gl字样的符号](http://upload-images.jianshu.io/upload_images/1490569-474f70f8a0338789.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
解决办法同上(和无法打开文件“xxx.lib”解决方法一样,把相应库配置好,VS能找到相应函数实现就行了。)。**
- **无法启动应用程序**
这种错误原因是应用程序运行需要 某某某.dll 动态链接库,而系统没有找到该 dll文件。
![无法启动此程序,因为计算机丢失 freeglut.dll (或者丢失freeglutd.dll 或者 丢失 glew32.dll),建议重新安装该程序...](http://upload-images.jianshu.io/upload_images/1490569-c68b6a85ba8f1401.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
解决办法是拷贝该dll文件到exe同目录下即可,[或者将dll拷贝到系统相应的文件夹内](http://tieba.baidu.com/p/3337331207)。

推荐阅读更多精彩内容