环境搭建
此次主要是是哟给你Clion进行OpenGL的学习,主要的语音为C.
开始搭建:
文件下载和安装
1 下载并安装Clion
2 下载MinGW64
3 下载glfw此次主要是用编译好的库
4 下载GLAD访问配置并下载
文件解压和配置
1 进行Clion的MinGW64配置
2 新建工程,选择C项目
3 打开工程所在文件夹, 创建include 和 lib 文件夹
3.1 解压GLFW,GLAD
3.2 将GLFW中的include中内容复制到项目中的include中 , lib-mingw-w64文件夹中内容复制到项目中lib文件夹内
3.3 将GLAD中include中内容复制到项目中的include中, 将src中内容复制到项目内即可.完成后呈现如下图
4 配置CMakeLists.txt文件夹, 如下
cmake_minimum_required(VERSION 3.16)
project(openglc C)
include_directories(include) # 头文件
link_directories(lib) # 库文件
set(CMAKE_C_STANDARD 99)
add_executable(openglc main.c glad.c)
target_link_libraries(openglc glfw3 opengl32)
至此完成所有配置
测试
在main.c中复制如下代码
#include <stdio.h>
#include <glad/glad.h>
#include<GLFW/glfw3.h>
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
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"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
// 片元着色起代码
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main() {
// 初始化版本等
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 初始化创建一个窗口
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL) { // 验证是否创建成功
printf("Failed to create GLFW window");
glfwTerminate();
return -1;
}
// 设置当前创建好的窗口
glfwMakeContextCurrent(window);
// 设置窗口变化的回调
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
printf("Failed to initialize GLAD");
return -1;
}
// 创建一个顶点着色起
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
// 设置定点着色起程序
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
// 继续编译
glCompileShader(vertexShader);
// 检查编译结果
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n");
}
//同上 片元着色起
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);
printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n");
}
// 创建一个渲染管道
int shaderProgram = glCreateProgram();
// 和定点着色器链接
glAttachShader(shaderProgram, vertexShader);
// 和片元着色起链接
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// 检查
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n");
}
// 完成并释放空间
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 设置顶点数组
float vertices[] = {
// x y z
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
// 顶点索引 和顶点数组配合使用
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int VBO, VAO, EBO;
// 创建一个顶点缓冲区
glGenVertexArrays(1, &VAO);
// 创建一个顶点和顶点索引缓冲
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 创建完成,需要绑定, 告诉状态机.现在操作的缓冲区为 VAO
glBindVertexArray(VAO);
// 绑定一个顶点缓冲 VBO 并设置数据
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 绑定一个顶点缓冲 VEO 索引 并设置数据
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 绑定使用顶点的规则
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// 解绑
glEnableVertexAttribArray(0);
// 可以解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
// 不可以解绑
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// 可以将顶点缓冲区 解绑 ,因为已经有了该索引VAO 需要时直接VAO绑定即可
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
// 电脑输入
processInput(window);
// 清除并设置背景色
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
// 清除颜色缓冲
glClear(GL_COLOR_BUFFER_BIT);
// 激活渲染管道
glUseProgram(shaderProgram);
// 绑定VAO 如果只有一个 也可以在循环外绑定一次即可
glBindVertexArray(VAO);
// 进行绘制
//glDrawArrays(GL_TRIANGLES, 0, 6); // 根据顶点数组绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 根据顶点索引绘制
// glBindVertexArray(0); // 如果下次循环还需要, 则不需要解绑 ,如果需要使用绘制其他顶点数据, 直接绑定其他的索引即可, 但是最终需要释放.
// 交换缓冲区和轮询IO事件(按键/释放、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
// 绘制结束需要释放 缓冲区 渲染管路
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
// 终止,清除以前分配的所有glfw资源
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, 1);
}
// 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);
}