当前位置:网站首页>OPENGL学习(五)Modern OpenGL 三角形绘制
OPENGL学习(五)Modern OpenGL 三角形绘制
2022-07-24 18:42:00 【季马宝宝】
和传统opengl相比,主要差别就是需要手写着色器,具体看这篇添加链接描述
底下是我的中文注释版
把shader写入main中
#include <iostream>
// GLEW
#define GLEW_STATIC //链接静态库需要宏定义
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// Window size
const int Width = 800, Height = 600;
// 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true,关闭应用程序
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
// Shaders
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main(int argc, char** argv)
{
// Init GLFW
glfwInit();
// 设置opengl基本设置
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//最高版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//最低版本
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//Core file
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);//不可以调整窗口大小
// 创建窗口
GLFWwindow* window = glfwCreateWindow(Width, Height, "A Triangle", nullptr, nullptr);
glfwMakeContextCurrent(window);
// 绑定按键回调函数
glfwSetKeyCallback(window, key_callback);
// 开启modern opengl
glewExperimental = GL_TRUE;
// 初始化glew(modern opengl)
glewInit();
// 设置窗口大小
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// 绑定源文件,第一个创建的着色器,第二个是绑定了多少个glsl,第三个是glsl源文件
// 最后一个是每个段占多少字符,因为就一个文件,所以可以不填
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
// 编译着色器对象
glCompileShader(vertexShader);
// 处理error
// 因为着色器很可能会写错,而着色器出错的log需要手动输出
GLint success;
GLchar 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
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for compile time 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;
}
// 链接 shaders
GLuint 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);
// 顶点buffer
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// VAO:Vertex Array Object
// 其实就是索引,因为可能会有很多不同的VBO,如果每个都生成一个索引太麻烦
// VBO:vertex buffer object
// 每个vertex的具体数据
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// 绑定VAO
glBindVertexArray(VAO);
// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 绑定数组
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 确定VAO具体参数
// 第一个参数是着色器中的layout,即这个数组对应着色器中的哪个属性
// 第二个参数是指定顶点属性大小,代表一个顶点三个数字vec3
// 第三个参数是数据类型
// 第四个参数确定是否将数据映射到0-1之间
// 第五个参数是步长,代表下一个数据在多少byte之后
// 第六个数据是偏移量,即数组开始的位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
// 开启VAO,参数是index,这个index其实就是绑定的VBO的layout
glEnableVertexAttribArray(0);
// 我觉得应该是VAO已经通过VBO绑定了,只有在更换VBO的时候才需要换绑
glBindBuffer(GL_ARRAY_BUFFER,0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind
// 可能绑定时会产生什么奇怪的状态导致出错,最好只在绘制时绑定
glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)
// main loop
while (!glfwWindowShouldClose(window))
{
// 轮询事件
glfwPollEvents();
// 清空颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用编译好的着色器程序
glUseProgram(shaderProgram);
// 绑定VAO
glBindVertexArray(VAO);
//绘制三角形,第二个参数是数组起始位置,第三个参数是定点数量
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// double buffer
glfwSwapBuffers(window);
}
// 删除VAO和VBO
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// 释放窗口资源
glfwTerminate();
return 0;
}
额外使用写一个shader类帮忙读取着色器
main:
#include <iostream>
#include <shader.h>
// GLEW
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// Window size
const int Width = 800, Height = 600;
// 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true,关闭应用程序
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
int main(int argc, char** argv)
{
// Init GLFW
glfwInit();
// 设置opengl基本设置
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//最高版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//最低版本
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//Core file
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);//不可以调整窗口大小
// 创建窗口
GLFWwindow* window = glfwCreateWindow(Width, Height, "A Triangle", nullptr, nullptr);
glfwMakeContextCurrent(window);
// 绑定按键回调函数
glfwSetKeyCallback(window, key_callback);
// 开启modern opengl
glewExperimental = GL_TRUE;
// 初始化glew(modern opengl)
glewInit();
// 设置窗口大小
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
Shader ourShader("Shaders/shader.vert", "Shaders/shader.frag");
// 顶点buffer
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// VAO:Vertex Array Object
// 其实就是索引,因为可能会有很多不同的VBO,如果每个都生成一个索引太麻烦
// VBO:vertex buffer object
// 每个vertex的具体数据
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// 绑定VAO
glBindVertexArray(VAO);
// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 绑定数组
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 确定VAO具体参数
// 第一个参数是着色器中的layout,即这个数组对应着色器中的哪个属性
// 第二个参数是指定顶点属性大小,代表一个顶点三个数字vec3
// 第三个参数是数据类型
// 第四个参数确定是否将数据映射到0-1之间
// 第五个参数是步长,代表下一个数据在多少byte之后
// 第六个数据是偏移量,即数组开始的位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
// 开启VAO,参数是index,这个index其实就是绑定的VBO的layout
glEnableVertexAttribArray(0);
// 我觉得应该是VAO已经通过VBO绑定了,只有在更换VBO的时候才需要换绑
glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind
// 可能绑定时会产生什么奇怪的状态导致出错,最好只在绘制时绑定
glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)
// main loop
while (!glfwWindowShouldClose(window))
{
// 轮询事件
glfwPollEvents();
// 清空颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用编译好的着色器程序
ourShader.Use();
// 绑定VAO
glBindVertexArray(VAO);
//绘制三角形,第二个参数是数组起始位置,第三个参数是定点数量
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// double buffer
glfwSwapBuffers(window);
}
// 删除VAO和VBO
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// 释放窗口资源
glfwTerminate();
return 0;
}
shader.vertx
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
};
shader.frag
#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
shader.h
#pragma once
#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>
class Shader
{
public:
GLuint Program;
// Constructor generates the shader on the fly
Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
{
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensures ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::badbit);
try
{
// Open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// Convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Shader Program
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
// Print linking errors if any
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// Uses the current shader
void Use()
{
glUseProgram(this->Program);
}
};
#endif
边栏推荐
猜你喜欢

9. BOM object?

Ionic4 learning notes 8 -- UI component 2 list (no practice, direct excerpt)

Cryptography knowledge - Introduction to encryption -1

Go Xiaobai implements a simple go mock server

Rookie colleagues cost me 2K. Did you recite the secret of salary increase? (collect it quickly!)

Attack and defense world novice zone PWN

Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag

为什么梯度是函数变化最快的方向

Mid year inventory | in 2022, PAAS will be upgraded again

Cf. bits and pieces (subset pressing DP + pruning)
随机推荐
缺失值处理
Vsftpd2.3.4-端口渗透 6200 irc_3281_backdoor
投资的新阶段
无关的表进行关联查询及null=null条件
Create parent-child projects in clion (cmake tool) and introduce the method of third-party libraries
Mid year inventory | in 2022, PAAS will be upgraded again
Typora 它依然是我心中的YYDS 最优美也是颜值最高的文档编辑神器 相信你永远不会抛弃它
middleware
EasyUI framework dialog repeated loading problem
[wechat applet development] custom tabbar case (custom message 99 + little hearts)
[Tkinter] common components (II)
Introduction to nipple music theory and personal perception
Getting started with MySQL database
Attack and defense world novice zone PWN
Data analysis of network security competition of national vocational college skills competition digital forensics-a
Cryptography knowledge - Introduction to encryption -1
epoch,batch_ size
core dump
Type-C PD protocol chip while charging and listening
Make C #