通过对 LearnOpenGL CN——入门——纹理 章节的学习,实现将数组转为纹理,代码所需的头文件和着色器文件都可以从 LearnOpenGL CN 的纹理章节找到。
一维数据
代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader_s.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 640;
const unsigned int SCR_HEIGHT = 300;
int main()
{
int nrChannels = 3;
主要修改部分/
int width = 6, height = 1;
unsigned char data[] = {
220, 235, 245, 190, 215, 238, 160, 195, 230,
100, 155, 205, 45, 115, 180, 30, 75, 120,
};
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
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "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;
}
Shader ourShader("./texture.vs", "./texture.fs");
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
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);
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);
unsigned int texture0;
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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;
ourShader.use(); // don't forget to activate/use the shader before setting uniforms!
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
ourShader.use();
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 processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
运行结果
二维数据
宽度为3
如果只是简单修改上面代码中的输入数据尺寸,将 “int width = 6, height = 1;” 改为 “int width = 3, height = 2;”,运行结果
发现上面一行错位一个颜色块,故应将输入数据也作修改,在第一行后面补零,修改部分代码
int width = 3, height = 2;
unsigned char data[] = {
220, 235, 245, 190, 215, 238, 160, 195, 230, 0,0,0,
100, 155, 205, 45, 115, 180, 30, 75, 120, 0,0,0,
};
运行结果
宽度为2
每个颜色块都由 RGB 三个数字表示,那么对于二维数据只要在每行后面补 3 个 0 就可以了吗?经测试不是的,此时需要补 2 个 0,修改部分代码
int width = 2, height = 3;
unsigned char data[] = {
220, 235, 245, 190, 215, 238, 0,0,
160, 195, 230, 100, 155, 205, 0,0,
45, 115, 180, 30, 75, 120, 0,0,
};
运行结果
宽度为1
相信你已经看出规律了,修改部分代码
int width = 1, height = 6;
unsigned char data[] = {
220, 235, 245, 0,
190, 215, 238, 0,
160, 195, 230, 0,
100, 155, 205, 0,
45, 115, 180, 0,
30, 75, 120, 0,
};
运行结果
规律
OpenGL默认内存中每个像素行以 4 字节对齐,所以需要将 data 每行补充若干 0 使得 width 能被 4 整除(什么!居然不是每行补充 width 个 0?)。
不想补 0 也可以,在代码中 glTexImage2D 前加入一句
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
以 1 字节对齐,这样无论宽度为多少都可以了,以损失效率为代价。