话不多说直接上代码!
#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW/glfw3.h>
using namespace std;
void glfwInput(GLFWwindow* window);
const char* vertexShaderSource =
"#version 330 core \n"
"layout(location = 0) in vec3 aPos; \n"
"void main(){ gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}\n";
const char* fragmentShaderSource =
"#version 330 core \n"
"out vec4 FragColor; \n"
"void main() \n"
"{FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);} \n";
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
// The MAIN function, from here we start the application and run the game loop
int main(int argc, char* argv[])
{
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit();
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
GLuint VBO, VAO;//声明顶点缓冲,声明顶点数组用于管理顶点数据
glGenVertexArrays(1, &VAO);//创建顶点数组,返回一个独一无二的整数,标识数组
glGenBuffers(1, &VBO);//创建顶点缓冲,返回一个独一无二的整数,标识缓冲区
glBindVertexArray(VAO);//绑定顶点数组
glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲
//指定顶点数组的数据源为vertices,第四个参数代表显卡如何管理给定的数据,GL_STATIC_DRWA代表几乎不会改变
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 指定顶点属性的解析方式。即,如何从顶点缓冲获取相应的顶点属性和相应的颜色属性。或者说,顶点着色器中如何知道去哪个顶点属性分量重着色呢
//对每一个顶点而言,属性有2种,一是位置属性,而是颜色属性,因此每六个浮点数决定了一个顶点的位置和颜色
//顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location),因此第一个参数,代表属性分量的索引
//参数二:顶点位置属性的维度,参数三:属性向量的数据类型,参数四:是否标准化;参数五,顶点位置属性的总字节长度,参数六:在缓冲数组中的偏移量,即起始位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);//启用属性0,因为默认是禁用的
GLuint vertexShader, fragmentShader;//ID
vertexShader = glCreateShader(GL_VERTEX_SHADER);//创建一个verterxShader
glShaderSource(vertexShader,1,&vertexShaderSource,NULL);//获取到shader的源代码资源
glCompileShader(vertexShader);//编译shader源代码
fragmentShader= glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram;
shaderProgram = glCreateProgram();//创建shader渲染程序
glAttachShader(shaderProgram,vertexShader);//附加vertexShader到渲染程序上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//链接上当前渲染程序
//顶点数组对象(Vertex Array Object, VAO)的好处就是,当配置顶点属性指针时,你只需要将上面的代码调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。如下文循环中的绑定再解绑
glBindVertexArray(0); // 解绑 VAO
// Game loop
while (!glfwWindowShouldClose(window))
{
// 检查事件,调用相应的回调函数,如下文的glfwInput函数
glfwInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//渲染颜色到后台缓冲
glClear(GL_COLOR_BUFFER_BIT);//清除前台缓冲
glBindVertexArray(VAO);//每次循环都调用,绑定函数绑定VAO
glUseProgram(shaderProgram);//使用渲染程序
glDrawArrays(GL_TRIANGLES, 0, 3);//开始绘制三角形从0起始,画三组数值
glBindVertexArray(0);//解绑
// 切换屏幕缓冲区
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate();//终止glfw
return 0;
}
// Is called whenever a key is pressed/released via GLFW
void glfwInput(GLFWwindow* window)
{
if (glfwGetKey(window,GLFW_KEY_ESCAPE)== GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
输出结果如下:
然后我们来画一个四边形。
由于OpenGL只能绘制三角形,所以如果要绘制四边形我们就得给出六个点,这样就很麻烦,于是我们便需要用到一个名叫EBO的东西,进行一下转换。
先修改一下顶点数组,并增加一个索引数组
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.8f, 0.5f, 0.0f
};
GLuint indices[] = { 0,1,3,1,2,3 };
然后声明一下EBO并使用
GLuint EBO;
glGenBuffers(1, &EBO);//创建一个缓冲区
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//绑定一个元素缓冲区
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//定义缓冲区中的数据,既对顶点数组的索引
while (!glfwWindowShouldClose(window))
{
glfwInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//绑定EBO
glUseProgram(shaderProgram);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//绘制三角形,根据索引数组绘制6个顶点,索引数组类型为GL_UNSIGNED_INT,偏移值为0
//glDrawArrays(GL_TRIANGLES, 0, 3);//开始绘制三角形从0起始,画三组数值
//glBindVertexArray(0);//解绑
glfwSwapBuffers(window);
glfwPollEvents();
}
后面与前面的不变。
然后就是看看效果图吧!
如果程序编译成功,却提示0xC0000005: 执行位置 0x00000000 时发生访问冲突。
就是少了下面两句
glewExperimental = GL_TRUE;
glewInit();
傅老师神笔镇楼:
借鉴自:
https://www.cnblogs.com/nazhizq/p/6582375.html
https://www.bilibili.com/video/av24353839/?p=8
https://learnopengl.com/Getting-started/Hello-Triangle