VS 2022配置openGL环境(GLFW+GLEW)

本文记录VS 2022环境下配置openGL的流程,使用GLFW和GLEW第三方库。内容大致如下:

目录

1. 创建VS项目

2. 编译GLFW源码

3. 编译GLEW源码

4. 配置VS项目属性


1. 创建VS项目

创建一个VS空项目,勾选“将解决方案文件与项目置于同一目录”(可选项)。

 在项目目录下新建文件夹"src", "lib", "include",分别用于存放源码、库文件和头文件。

其中,在"lib"文件夹下新建"debug", "release"文件夹,分别存放debug版本和release版本所使用的.lib文件。

2. 编译GLFW源码

首先,网络上通过GLFW、GLEW库的预编译来配置openGL的教程已经较多了,此处不再赘述,详情可以参考视频教程P2、P3部分

【译】TheCherno-OpenGL系列教程

之所以要采用编译源码的方式配置环境,是由于我在通过预编译文件进行配置时,遇到了运行时冲突的warning,担心后续影响工作,所以决定自行编译,统一项目所用依赖库的运行时。

GLFW库的官网链接如下:

An OpenGL library | GLFW

进入以后选择右上角的Download进入下载页面,或者直接点击右侧Download按钮下载源码。

进入下载页面以后,可以选择下载源码或者预编译文件,此处选择下载源码。

 

下载以后,解压缩文件,进入文件目录。文件目录内包含如下文件:

 

运行CMake工具,将CMakeList.txt所在目录输入到源码目录一栏("Where is the source code: ")。依照习惯,在恰当位置建立文件夹"build"用以存放生成的文件。将build文件夹路径输入到下一栏中。随后点击Configure按钮,进行生成配置。

选择项目的编译环境为"Visual Studio 17 2022",平台为win32(本案例以win32为所使用平台)。随后点击按钮“完成”。

待窗口中列出生成选项之后,注意到最后一个选项"USE_MSVC_RUNTIME_LIBRARY_DLL",此处若勾选为“是”,则编译中将使用动态运行时,若不勾选,则将使用静态运行时。由于考虑到使用动态运行时生成的程序,在转移到其他机器时容易因缺少运行时环境而无法运行,所以此处采用静态运行时,将运行时直接打包到生成的文件中。所以取消勾选该选项。

关于运行时可以参考此篇博客:带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑

 完成修改后,先点击Configure保存修改,再点击Generate生成文件。

随后在build文件夹中可以找到生成的Visual Studio项目。编译此项目即可完成GLFW的编译。

用VS 2022打开GLFW.sln文件。

在GLFW3/glfw文件上右键,选择propeties选项,打开属性界面。先在上方选择Configure为Debug,Platform为win32,转至C/C++ —>  Code Generation —> Runtime Library,检查此项是否为Multi-threaded Debug(/MTd)。同理,再将上方Configure选为Release,检查此选项是否为Multi-threaded。

退出窗口,现在上方将VS模式选择为Debug, Win32,在左侧Solution "GLFW"上右键,选择Build Solution。随后再切换模式为Release, Win32,同样Build Solution。

 编译完成后,将编译生成的.lib文件和头文件复制到自己的项目里面。

在Build目录下,进入src文件夹,内有两个目录,分别为"Debug", "Release",分别将两个文件夹内的文件复制到先前创立的VS项目中,"lib\debug"和"lib\release"目录下

又退回到CMakeList.txt所在目录下,进入include文件夹,将GLFW文件夹完整复制到自己所创建项目下的include文件夹内。

GLFW编译完成。

3. 编译GLEW源码

GLEW官方网站链接如下:

GLEW: The OpenGL Extension Wrangler Library (sourceforge.net)

进入以后,仿照先前流程,下载源码zip文件

下载之后,解压缩,进入目录。在沿路径build>vc12找到VS Solution文件,打开。

由于目前GLEW官方源码文件中的Solution文件最高仅到vc12,所以打开以后会有提示将项目进行重定向,选择“是”。

 

重定向之后,手动修改各项目的运行时库,依照GLFW配置时的操作,Debug版本使用(\MTd),Release版本使用(\MT),平台选择Win32。对四个项目都进行同样的配置。

 

设置完成后,仿照GLFW的构建,先选择Debug+win32模式进行Build,再选择Release+win32模式进行构建。注意,此处可能出现报错,如果Release模式构建成功一次以后,再次进行Build会产生“无法解释的外部符号”报错,原因未知。

 两次Build均完成以后,退回目录"glew-2.1.0",进入"./lib/Debug/Win32"目录下,将一下两个文件复制到自建项目的"lib/debug"目录下

同理,将 "./lib/Release/Win32"的以下文件也复制到自建项目的"lib/release"目录下

4. 配置VS项目属性

在VS项目的src目录下,新建"application.cpp"文件。

完成以上步骤后,VS项目的目录应该呈现如下形式:

 在项目标签上右键,选择Propeties,打开属性设置窗口:

 首先将Configuration调整为All Configuration,Platform调整为Win32。

在C/C++ > Genral > Additional include Directories处添加"$(SolutionDir)include"。

在C/C++ > Preprocessor > Preprocessor Definitions处添加"GLEW_STATIC"(这是由于我们所使用的GLEW库是静态库版本,所以需要预先声明)

 完成以上两项后,点击“应用(A)”。

随后将Configuration切换至Debug,Platform不改变。进入C/C++ > Code Generation > Runtime Library,设置为"(/MTd)"。

 进入Linker > General > Additional Library Directories,添加"$(SolutionDir)lib\debug"。 

 进入Linker > Input > Additional Dependencies,添加"glew32sd.lib","glfw3.lib","opengl32.lib"。也就是将lib\debug下的所有.lib文件添加进去,并附加上一个opengl32.lib。

应用以上修改。再将Configuration改为"Release",同理进行以上操作,只不过将Runtime Library设置为"(/MT)" ,添加的Additional Library Directories为"$(SolutionDir)lib\release",添加的Additional Dependencies是"$(SolutionDir)lib\release"下的所有lib文件以及opengl32.lib文件。

最后,退出属性配置窗口,将以下测试代码复制到application.cpp文件中:

#include <GL\glew.h>
#include <GLFW/glfw3.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"out vec3 ourColor;\n"
"void main()\n"
"{\n"
"	gl_Position = vec4(aPos, 1.0);\n"
"	ourColor = aColor;\n"
"}\0";

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"void main()\n"
"{\n"
" 	FragColor = vec4(ourColor, 1.0f);\n"
"}\n\0";
int main()
{
	// glfw: initialize and configure
	// ------------------------------
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

	// glfw window creation
	// --------------------
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	// glew: initialize library
	// ---------------------------------------
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}
	// build and compile our shader program
	// ------------------------------------
	// vertex shader
	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	// check for shader compile errors
	int success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n"
			<< infoLog << std::endl;
	}
	// fragment shader
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	// check for shader compile errors
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"
			<< infoLog << std::endl;
	}
	// link shaders
	unsigned int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	// check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success)
	{
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n"
			<< infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	// set up vertex data (and buffer(s)) and configure vertex attributes
	// ------------------------------------------------------------------
	float vertices[] = {
		// positions // colors
		0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right
		-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left
		0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top
	};

	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// position attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// color attribute
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);

	// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
	// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
	// glBindVertexArray(0);

	// as we only have a single shader, we could also just activate our shader once beforehand if we want to
	glUseProgram(shaderProgram);
	// render loop
	// -----------
	while (!glfwWindowShouldClose(window))
	{
		// input
		// -----
		processInput(window);

		// render
		// ------
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// render the triangle
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);

		// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
		// -------------------------------------------------------------------------------
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	// optional: de-allocate all resources once they've outlived their purpose:
	// ------------------------------------------------------------------------
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteProgram(shaderProgram);

	// glfw: terminate, clearing all previously allocated GLFW resources.
	// ------------------------------------------------------------------
	glfwTerminate();
	return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	// make sure the viewport matches the new window dimensions; note that width and
	// height will be significantly larger than specified on retina displays.
	glViewport(0, 0, width, height);
}

分别在Release模式和Debug模式下尝试生成解决方案:

如果无报错,尝试通过 Local Windows Debugger运行程序。若配置成功,则将显示如下三角形,并且不会闪退:

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值