立即渲染模式(Immediate mode):
早期的OpenGL使用的模式(也就是固定渲染管线)
OpenGL的大多数功能都被库隐藏起来,容易使用和理解,但是效率太低
开发者很少能控制OpenGL如何进行计算
因此从OpenGL3.2开始,推出核心模式。
核心模式:
也叫可编程管线,提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程
glfw
glfw解决操作系统层面的不同
- 创建窗口
- 定义上下文
- 处理用户输入
glad
glad使得代码可以用于不同的OpenGL驱动
- OpenGL本身只是标准/规范
- 各个厂家具体实现方式可以不同
- 不同操作系统处理方式也不同
//1.获取vbo的index
//2.绑定vbo的index
//3.给vbo分配现存空间,传输数据
//4.告诉shader数据解析方式
//5.激活锚点
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
unsigned int VBO, VAO,shaderProgram;
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
void initModel() {
float vertices[] = { -0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.0f,0.5f,0.0f };
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);//1代表生成一个
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//param1:第0个锚定点;param2:包含几个数据(x,y,z),param5:步长,param6:读取位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);//将第0个锚定点启用
glBindBuffer(GL_ARRAY_BUFFER, 0);//解绑
glBindVertexArray(0);
}
void initShader(const char*_vertexPath,const char* _fragPath) {
std::string _vertexCode("");
std::string _fragCode("");
std::ifstream _vShaderFile;
std::ifstream _fShaderFile;
_vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
_fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
_vShaderFile.open(_vertexPath);
_fShaderFile.open(_fragPath);
std::stringstream _vShaderStream, _fShaderStream;
_vShaderStream << _vShaderFile.rdbuf();
_fShaderStream << _fShaderFile.rdbuf();
_vertexCode = _vShaderStream.str();
_fragCode = _fShaderStream.str();
}
catch(std::ifstream::failure e){
std::string errStr = "read shader fail";
std::cout << errStr << std::endl;
}
const char* _vShadeStr = _vertexCode.c_str();
const char* _fShadeStr = _fragCode.c_str();
std::cout << "vertexcode=" << _vShadeStr << std::endl;
std::cout << "fragcode=" << _fShadeStr << std::endl;
//shader的编译链接
unsigned int _vertexID = 0, _fragID = 0;
char _infoLog[512] = {};
int _succeesFlag = 0;
//编译
_vertexID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(_vertexID,1,&_vShadeStr,NULL);
glCompileShader(_vertexID);
glGetShaderiv(_vertexID, GL_COMPILE_STATUS, &_succeesFlag);
if (!_succeesFlag) {
glGetShaderInfoLog(_vertexID, 512, NULL, _infoLog);
std::string errStr(_infoLog);
std::cout << errStr << std::endl;
}
_fragID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(_fragID, 1, &_fShadeStr, NULL);
glCompileShader(_fragID);
glGetShaderiv(_fragID, GL_COMPILE_STATUS, &_succeesFlag);
if (!_succeesFlag) {
glGetShaderInfoLog(_fragID, 512, NULL, _infoLog);
std::string errStr(_infoLog);
std::cout << errStr << std::endl;
}
//链接
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram,_vertexID);
glAttachShader(shaderProgram,_fragID);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &_succeesFlag);
if (!_succeesFlag) {
glGetProgramInfoLog(shaderProgram, 512, NULL, _infoLog);
std::string errStr(_infoLog);
std::cout << errStr << std::endl;
}
glDeleteShader(_vertexID);
glDeleteShader(_fragID);
}
void render() {
glBindVertexArray(VAO);
glUseProgram(shaderProgram);
glDrawArrays(GL_TRIANGLES, 0, 3);//从第0个顶点开始话,起作用的是3个顶点
glUseProgram(0);
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* windows = glfwCreateWindow(800, 640, "learn oepngl", NULL, NULL);
if (windows == NULL) {
glfwTerminate();
std::cout << "Failed to create GLFW window" << std::endl;
return -1;
}
glfwMakeContextCurrent(windows);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "failed to initialize GLAD" << std::endl;
return -1;
}
initModel();
initShader("vertexShader.glsl","fragmentShader.glsl");
while (!glfwWindowShouldClose(windows)) {
processInput(windows);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//状态设置
glClear(GL_COLOR_BUFFER_BIT);//状态使用
//glDrawArrays(GL_TRIANGLES, 0, 3);
render();
glfwSwapBuffers(windows);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
顶点着色器处理后,顶点值应该是NDC坐标
编译定点着色器
#version 330 core
layout(location=0) in vec3 aPos;
void main(){
gl_Position=vec4(aPos.x,aPos,y,aPos.z,1.0);
}
gl_Position是顶点着色器的内置变量
片段着色器
#version 330 core
out vec4 FragColor;
void main(){
FragColor = vec4(1.0f,0.5f,0.2f,1.0f);
}
bilibili视频资源:
https://www.bilibili.com/video/BV1vU4y1w7Ke?p=6&spm_id_from=pageDriver&vd_source=a5875ea8ec83ce8d44c0383d088f16e4
OpenGL函数命名含义:
OpenGL库
- 包含115个基本函数
- 函数以gl开头
例: glColor3f(), glTranslate3f() - 完成图元的定义,几何变换,投影等功能
OpenGL实用库
- 实用函数43个
- 函数以glu开头
例: gluPerspective() - 完成更高层的图形处理如曲线曲面的生成,图像操作等
OpenGL辅助库
- 包括函数31个
- 函数以aux开头
例: auxInitWindow() - 主要用于窗口管理
命名规则
- OpenGL函数都遵循一个命名约定,即采用以下格式:
<库前缀><根命令><可选的参数个数><可选的参数类型> - void glVertex3fv(Glfloat *vertex)
前缀: - gl,glu,aux,glut 该函数属于哪个函数库
后缀: - 2,3,4 参数维数
- b,s,l,f,d,ub,us,ui 参数的数据类型
- v 以数组方式传递参数
数据类型
参考:
https://blog.youkuaiyun.com/qq_33934427/article/details/127046119