OpenGL: Study Notes 3 - Shader 着色器
## 目标
使用自定义着色器画一个三角形
## 编写着色器程序的步骤
- 将着色器源码存入字符串
- 创建着色器对象
- 将源码字符串赋予着色器对象
- 编译着色器
- 创建着色器程序
- 将编译好的着色器附加到程序对象上
- 链接生成程序
## 着色器程序
```cpp
// 版本号, 模式(核心模式)
#version 400 core
// 表示输出的参数,类型,变量名
out vec4 FragColor;
void main()
{
// color, alpha
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
```
## 代码示例
```cpp
// glad must put before GLFW
#include
#include
#include
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;
float vertices[] = {
-0.5f, -0.5f, 0.0f, //left
0.5f, -0.5f, 0.0f, //right
0.0f, 0.5f, 0.0f //top
};
GLFWwindow* window;
int init();
void VOASet();
// 将着色器源码存入字符串
const char* fragmentShaderSource = "#version 400 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()
{
init();
// draw triangle
VOASet();
// 创建着色器对象
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// 将源码字符串赋予着色器对象
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
// 编译着色器
glCompileShader(fragmentShader);
// 创建着色器程序对象
int shaderProgram = glCreateProgram();
// 将编译好的着色器对象附加到程序对象上
glAttachShader(shaderProgram, fragmentShader);
// 链接生成着色器程序
glLinkProgram(shaderProgram);
// render loop
// -----------
while (!glfwWindowShouldClose(window)) {
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Use customized shader
// 使用自定义的着色器程序
glUseProgram(shaderProgram);
// Draw triangle
glDrawArrays(GL_TRIANGLES, 0, 3); // VBO 0->3
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// 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);
}
int init()
{
//设置OpenGL版本等信息
// 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
// --------------------
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGLExample", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//把OpenGL的函数指针导入给GLAD
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
}
void VOASet()
{
// ID
unsigned int VBO, VAO;
// 生成VAO
glGenVertexArrays(1, &VAO);
// 生成VBO
glGenBuffers(1, &VBO);
// 绑定VAO & VBO
glBindVertexArray(VAO);
// 指定这是一个VBO buffer,因为buffer的各类有很多种
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 开辟显存空间
// p1: 目标, p1: 写多少数据, p3: 写什么内容, p4: 表示以后不修改
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 告诉显卡值的结构
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
}
```
## 结果
No comments