序
查这段代码的时候:
无意中看到了一个这个链接:
(31条消息) 现代OpenGL学习笔记三:深入理解着色器_不想不努力的菜菜的博客-CSDN博客
里面讲了如何绘制一个彩色的三角形,还演示了index=0,1两种情况下,VBO与shader怎么呼应的,绘制有颜色的图形,很常用,值得学习。
链接的学习
这部分内容,来自上面那个链接。
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
图画的挺漂亮的:
// 位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);
明白了,去尝试自己写吧。
尝试
作为一个小白,报错是常态,所以,不要有心理负担。
之前做到了这样:
第一次运行,是这样:
改,在这一行里,少了个vec3,少了个;
坏消息是依旧报错,好消息是错少了
这个const float,和这个有关系吗?
实测,没关系……
经过重写对比,发现少了个“,”
这可能不是调试代码,这是比谁的眼更敏感……对我这种小白来说,太难搞了。。
正常了,这个就已经开始有点实用价值了
能正常运行出结果的完整代码
/***
* 例程 绘制三角形 (MAKE后运行时可删除ALL_BUILD,也可以将Task-triangle设为默认启动工程)
* 步骤:
* 1-初始化: GLFW窗口,GLAD。
* 2-数据处理: 给定顶点数据,生成并绑定VAO&VBO(准备在GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据)。
* 3-着色器: 给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序。
* 4-渲染: 清空缓冲,绑定纹理,使用着色器程序,绘制三角形,交换缓冲区检查触发事件后释放资源
*/
#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
// 三角形的顶点数据
//const float triangle[] = {
// // ---- 位置 ----
// -0.5f, -0.5f, 0.0f, // 左下
// 0.5f, -0.5f, 0.0f, // 右下
// 0.0f, 0.5f, 0.0f // 正上
//};
//
//const float triangle2[] = {
// // ---- 位置 ----
// 0.6f, -0.5f, 0.0f, // 左下
// 0.8f, -0.5f, 0.0f, // 右下
// 0.7f, 0.5f, 0.0f // 正上
//};
const float triangle[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
const float triangle2[] = {
// 位置 // 颜色
0.6f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
0.8f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.7f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
// 屏幕宽,高
int screen_width = 1280;
int screen_height = 720;
int main() {
// 第一部分,初始化GLFW和GLAD,分为4个步骤进行/
// 初始化GLFW
glfwInit(); // 初始化GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // OpenGL版本为3.3,主次版本号均设为3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式(无需向后兼容性)
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 如果使用的是Mac OS X系统,需加上这行
glfwWindowHint(GLFW_RESIZABLE, false); // 不可改变窗口大小
// 创建窗口(宽、高、窗口名称)
auto window = glfwCreateWindow(screen_width, screen_height, "Triangle", nullptr, nullptr);
if (window == nullptr) { // 如果窗口创建失败,输出Failed to Create OpenGL Context
std::cout << "Failed to Create OpenGL Context" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); // 将窗口的上下文设置为当前线程的主上下文
// 初始化GLAD,加载OpenGL函数指针地址的函数
// 在调用任何OpenGL函数之前
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
glViewport(0, 0, screen_width, screen_height);
// 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/
// 生成并绑定VAO和VBO
GLuint vertex_array_object; // == VAO 核心模式要求必须使用VAO
glGenVertexArrays(1, &vertex_array_object);//先生成
glBindVertexArray(vertex_array_object);//再绑定
GLuint vertex_buffer_object[2]; // == VBO
glGenBuffers(2, &vertex_buffer_object[0]);//先生成,相当于C里声明的指针
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);//绑定, 相当于声明指针指向的变量类型,同时设置一下状态机的状态(火车轨道变轨,变完了后面的车都得按变了的轨道走)
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW); // 将顶点数据绑定至当前默认的缓冲中
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 设置顶点属性指针——告知OpenGL,如何解释这些数据
//glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);//解绑
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);//再绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW); // 将顶点数据绑定至当前默认的缓冲中,可能是传数据到GPU吧
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 设置顶点属性指针——告知OpenGL,如何解释这些数据
//glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);//再绑定
// 解绑VAO和VBO 为了代码更规范
glBindVertexArray(0);
// 第三部分,着色器,用来处理GPU里的数据//
// 顶点着色器和片段着色器源码【GLSL】
const char* vertex_shader_source =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" // 位置变量的属性位置值为0
"layout (location = 1) in vec3 aColor; \n " 颜色变量的属性位置值为 1
"out vec3 ourColor; \n"// 向片段着色器输出一个颜色
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n" //内建变量
"ourColor=aColor;\n"
"}\n\0";
const char* fragment_shader_source =
"#version 330 core\n"
"in vec3 ourColor;\n"
"out vec4 FragColor;\n" // 输出的颜色向量
"void main()\n"
"{\n"
"FragColor = vec4(ourColor, 1.0f);\n"
"}\n\0";
// 生成并编译着色器
// 顶点着色器
int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
int success;
char info_log[512];
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
}
// 片段着色器
int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
}
// 链接顶点和片段着色器至一个着色器程序
int shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
// 检查着色器是否成功链接,如果链接失败,打印错误信息
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, 512, NULL, info_log);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
}
// 删除着色器 需要的着色器程序已经拿到了,这个没用了,就删除了
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
// 线框模式
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// 第4部分,渲染//
// 渲染循环
while (!glfwWindowShouldClose(window)) {
// 清空颜色缓冲
glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用着色器程序 【之前链接好的那个】
glUseProgram(shader_program);
// 绘制三角形
glBindVertexArray(vertex_array_object); // 绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); // 设置指针位置,以便后续从此处读取数据进行渲染
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float))); // 设置指针位置,以便后续从此处读取数据进行渲染
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); // 【渲染时告诉OpenGL如何解释这些数据】
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); // 【渲染时告诉OpenGL如何解释这些数据】
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形
glBindVertexArray(0); // 解除绑定
// 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);//双缓冲
glfwPollEvents();
}
// 第五部分,善后工作
// 删除VAO和VBO
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteBuffers(1, &vertex_buffer_object[0]);
// 清理所有的资源并正确退出程序
glfwTerminate();
return 0;
}
后记
那末,如果这个顶点数据,是可变的,应该咋写?
和STATIC_DRAW有关吗?
有关,但是没有想象里的关联那么大
引用:
(31条消息) STATIC_DRAW, DYNAMIC_DRAW, STREAM_DRAW的区别_me_badman的博客-CSDN博客
以后再说吧,暂时用不到。
小白而已,不能一次要求的太多……