OpenGL学习笔记1-渲染绑定纹理的矩形
前言
使用glad库和glfw库绘制一个绑定纹理的矩形
最终效果如下
知识点
1. 图形渲染管线
图形渲染管线:3D坐标转为2D坐标实际的有颜色的像素的处理过程
着色器:在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据
GLSL:OpenGL着色器语言,代替固定渲染管线的一部分
GLSL有两种容器类型:向量和矩阵
顶点数据:一系列顶点的集合
顶点着色器:确定坐标在3D空间中的位置关系
图元装配:把所有的点装配成指定图元的形状
几何着色器:通过产生新顶点构造出新的(或是其它的)图元来生成其他形状
光栅化:把图元映射为最终屏幕上相应的像素,生成片段(Fragment)供片段着色器(Fragment Shader)使用
片段着色器:
Alpha测试和混合:检测片段的对应的深度(和模板(Stencil))值,用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。正面(逆时针)
现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)
2. VAO,VBO,EBO
顶点数组对象:Vertex Array Object,VAO 存储状态配置,能提高GPU执行的效率
顶点缓冲对象:Vertex Buffer Object,VBO 存储顶点数据
元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO 不能提高GPU执行的效率
3.生成一个VBO对象
unsigned int VBO;
glGenBuffers(1, &VBO);//生成一个VBO对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); //绑定缓冲
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//填充缓冲
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
显卡管理给定的数据的三种形式:
GL_STATIC_DRAW :数据不会或几乎不会改变。
GL_DYNAMIC_DRAW:数据会被改变很多。
GL_STREAM_DRAW :数据每次绘制时都会改变。
4.纹理
纹理是一个2D图片(甚至也有1D和3D的纹理),用来添加物体的细节
采样:使用纹理坐标获取纹理颜色
采样器:以纹理类型作为后缀,比如sampler1D、sampler2D、sampler3D等
纹理环绕方式:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);//2D纹理,应用的纹理轴,环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
纹理过滤:
GL_NEAREST也叫邻近过滤
GL_LINEAR也叫线性过滤
多级渐远纹理:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
邻近过滤:
线性过滤:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5.加载与创建纹理
//文件图像加载库
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//生成纹理
unsigned int texture;
glGenTextures(1, &texture);//1为生成纹理的数量,
glBindTexture(GL_TEXTURE_2D, texture);
// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 加载并生成纹理
int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);//纹理目标,为纹理指定多级渐远纹理的级别0是基本级别,纹理储存为RGB值,纹理的宽度,纹理的高度,该参数总是被设为0(历史遗留的问题),源图的格式,源图的数据类型,真正的图像数据
glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
6.应用纹理
添加了一个额外的顶点属性纹理坐标,所以要更新新的顶点格式。
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));//属性的位置(layout=2),顶点属性大小vec2即s和t,数据类型,是否归一化,步长,偏移量
glEnableVertexAttribArray(2);//启用顶点属性2
修改顶点着色器和片段着色器见:二、给矩形绑定纹理
为什么sampler2D变量是个uniform,不用glUniform给它赋值?
因为使用glUniform1i,我们可以给纹理采样器分配一个位置值,这样的话我们能够在一个片段着色器中设置多个纹理。
纹理单元:纹理的位置值。
在着色器中可以使用多于一个的纹理,通过把纹理单元赋值给采样器,就可以一次绑定多个纹理。
glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture);
OpenGL至少保证有16个纹理单元使用
一、绘制一个矩形
可以有两种方法:
- 绘制两个三角形_矩形
- 使用EBO
运行效果如下
1. 绘制两个三角形_矩形
完整代码如下
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
//顶点着色器
const char *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);"
"gl_PointSize = 20.0f;"
"}\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);"//输出橘黄色
"FragColor = vec4(0.0f, 0.0f,0.0f, 0.0f);"//输出黑色
"}";
// settings
// 设置窗体的宽度和高度
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main()
{
glfwInit();
// 设置主要和次要版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建窗口对象
GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
// 定义顶点数组
float vertices[] = {
// 第一个三角形
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, 0.5f, 0.0f, // 左上角
// 第二个三角形
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
// 创建缓冲对象
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// 绑定VAO缓冲对象
glBindVertexArray(VAO);
// 绑定VBO缓对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 填充VBO数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
// 创建顶点和片段着色器
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// 附加着色器代码
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);//编译
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);//编译
// 检测是否编译成功
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR:SHADER::VERTEX::COMPILATION_FAILED\n"
<< std::endl;
}
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR:SHADER::FRAGMENT::COMPILATION_FAILED\n"
<< std::endl;
}
// 创建程序对象
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
// 将着色器附加到程序对象上
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
// 链接
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR:SHADER_PROGRAM_LINK_FAILED" << std::endl;
}
// 使用着色器程序
glUseProgram(shaderProgram);
// 删除着色器
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
while (!glfwWindowShouldClose(window))
{
processInput(window);
// 渲染
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//渲染三角形
glUseProgram(shaderProgram);
glBindVertexArray(VAO);//绑定
glDrawArrays(GL_TRIANGLES, 0, 3);//绘制第一个三角形
glDrawArrays(GL_TRIANGLES, 3, 3);//绘制第二个三角形
glBindVertexArray(0);
glBindVertexArray(0);//解绑
glfwSwapBuffers(window);//双缓冲
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
2.使用EBO
完整代码如下
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);"
"gl_PointSize = 20.0f;"
"}\n";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{"
"FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);"//输出白色
"}";
// settings窗口大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main()
{
// 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);
// glfw window creation
// --------------------
// 创建窗口对象
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();//结束函数(释放内存)
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 注册窗口变化监听
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
// 定义顶点数组
float vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角(重复的坐标1)
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角(重复的坐标2)
};
unsigned int indexes[] = {
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
// 创建缓冲对象
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 绑定VAO缓冲对象
glBindVertexArray(VAO);
// 绑定VBO缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 填充VBO数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 绑定EBO对象
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// 填充EBO数据
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
// 创建顶点和片段着色器
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// 附加着色器代码
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);//编译
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);//编译
// 检测是否编译成功
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR:SHADER::VERTEX::COMPILATION_FAILED\n"
<< std::endl;
}
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR:SHADER::FRAGMENT::COMPILATION_FAILED\n"
<< std::endl;
}
// 创建程序对象
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
// 将着色器附加到程序对象上
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
// 链接
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR:SHADER_PROGRAM_LINK_FAILED" << std::endl;
}
// 使用着色器程序
glUseProgram(shaderProgram);
// 删除着色器对象
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
设置线框绘制模式
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
while (!glfwWindowShouldClose(window))
{
processInput(window);
// 渲染矩形
glClearColor(25.0 / 255.0, 25.0 / 255.0, 25.0 / 255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO); // 绑定
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);//解绑
glfwSwapBuffers(window);//双缓冲
glfwPollEvents();//立即处理已经到位的事件
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
glfwTerminate();//释放内存
return 0;
}
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);
}
二、给矩形绑定纹理
完整代码如下
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <shader.h>
#include <iostream>
using namespace std;
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
//-------------------放v.txt
//#version 330 core
//layout(location = 0) in vec3 aPos;
//layout(location = 1) in vec3 aColor;
//layout(location = 2) in vec2 aTexCoord;
//
//out vec3 ourColor;//定义颜色输出变量
//out vec2 TexCoord;//定义纹理输出对象
//
//void main() {
// gl_Position = vec4(aPos, 1.0f);
// ourColor = aColor;//颜色赋值
// TexCoord = aTexCoord;//纹理赋值
//}
//--------------------放f.txt
//#version 330 core
//out vec4 FragColor;
//in vec3 ourColor;
//in vec2 TexCoord;
//
//uniform sampler2D texture1;
//uniform sampler2D texture2;
//
//uniform float factor;
//
//void main() {
// FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), abs(sin(factor * 0.2)));
// // FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
//}
int main(int argc, char* argv[])
{
// 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);
// 创建窗口对象
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
Shader ourShader("v.txt", "f.txt");
// 顶点数据
float vertices[] = {
// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
};
// 索引数据
unsigned int indices[] = {
0, 1, 3, // 三角形一
1, 2, 3 // 三角形二
};
// 创建缓冲对象
unsigned int VBO, EBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 绑定VAO缓冲对象
glBindVertexArray(VAO);
// 绑定VBO缓对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 填充VBO数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 设置顶点位置属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 设置顶点颜色属性指针
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 设置顶点纹理坐标属性指针
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
// 生成纹理
unsigned int texture1;
glGenTextures(1, &texture1);//创建纹理
glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理
// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
图像y轴翻转
stbi_set_flip_vertically_on_load(true);
// 加载图片并生成纹理
int width, height, nrChannels;
unsigned char* data = stbi_load("a.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
ourShader.use();
ourShader.setInt("texture1", 0);
float factor = 0.0;
while (!glfwWindowShouldClose(window))
{
processInput(window);
// 渲染指令
// ...
glClearColor(25.0 / 255.0, 25.0 / 255.0, 25.0 / 255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
factor = glfwGetTime();
ourShader.setFloat("factor", factor);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
总结
渲染绑定纹理的矩形
首先绘制一个矩形再给该矩形贴上纹理