一、概述
之前的文章都是绘制一些纯色的三角形和正方形以及控制他们的相对位置。
在实际的开发中一般都需要给绘制出的图形贴上漂亮的纹理。
纹理贴图步骤:
1.创建纹理
glGenTextures(1, &texture);//参数1:创建纹理的数量,参数2:用户定义的纹理id,一般为unsigned int
2.绑定纹理
glBindTexture(GL_TEXTURE_2D, texture);//参数1:目标,2d纹理,参数2:上面创建的纹理对象
3.设置纹理环绕方式
//设置纹理环绕方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
4.设置纹理过滤方式(当纹理放大或缩小时应该如何采样)
//设置纹理过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5.创建纹理并将纹理数据copy给GPU
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D);
6.加载纹理图像使用的是stb_image.h,如果不太清楚的可以上网查一下,资料一大堆
二、代码示例
1.定义顶点数据和纹理数据(此处定义到一块,通过VBO一次性copy给GPU)
float vertices[] = { // ---- 位置 ---- - 纹理坐标 - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 右上 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 右下 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // 左下 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 };
2.定义索引缓冲数组,用于顶点数据的索引(绘制正方形)
unsigned int indices[] = { 0, 1, 3, // first triangle 1, 2, 3 // second triangle };
3.创建VAO、VBO、EBO,同时将顶点、纹理、缓冲区数据copy给GPU。ps:VBO和EBO是挂在VAO下的,VAO是管理者
//创建VAO、VBO、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); ////EBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
4.告知GPU如何解析顶点数据和纹理数据
////告知显卡顶点数据如何解析 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //// ////告知显卡纹理坐标如何解析 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1);
5.创建纹理并将纹理数据传递给GPU
////创建纹理 glGenTextures(1, &texture); 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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_set_flip_vertically_on_load(true); //生成纹理 int width, height, mChannels; QString path = getTexturePath("similing_face.png"); unsigned char* data = stbi_load(path.toStdString().c_str(), &width, &height, &mChannels, 0); if (data) { qDebug() << "图片加载成功,width=" << width << ",height=" << height; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { qDebug() << "图像数据加载失败"; } stbi_image_free(data);
6.定义顶点着色器和片元着色器
//定点着色器 #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 ourTexCoord; void main(void) { gl_Position = vec4(aPos,1.0f); ourTexCoord = aTexCoord; }
//片元着色器 #version 330 core out vec4 FragColor; in vec2 ourTexCoord; uniform sampler2D ourTexture; void main() { FragColor = texture(ourTexture,ourTexCoord); }
7.编译、连接顶点着色器和片元着色器
GLuint BaseOpenGLWindow::buildAttachShaderAndReturnProgramId(QString vertexResPath, QString fragmentResPath) { //编译顶点着色器和片元着色器 GLuint vertexShader = getShaderId(GL_VERTEX_SHADER, vertexResPath); GLuint fragmentShader = getShaderId(GL_FRAGMENT_SHADER, fragmentResPath); GLuint programId = glCreateProgram(); glAttachShader(programId, vertexShader); glAttachShader(programId, fragmentShader); glLinkProgram(programId); getLinkProgramErrorInfo(programId); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); return programId; } void BaseOpenGLWindow::getLinkProgramErrorInfo(GLuint programId) { int success; char infoLog[512]; glGetProgramiv(programId, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(programId, 512, NULL, infoLog); qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog; } } GLuint BaseOpenGLWindow::getShaderId(GLenum shaderType, QString resPath) { //创建顶点着色器 unsigned int shaderId = glCreateShader(shaderType); QFile vertexShaderFile(resPath); if (!vertexShaderFile.open(QIODevice::ReadOnly)) { qDebug() << "Cannot open vertex shader file for reading"; } QString verQStr = vertexShaderFile.readAll(); std::string verStdStr = verQStr.toStdString(); const char* vertexStr = verStdStr.c_str(); qDebug() << "vertexStr-------------" << vertexStr; vertexShaderFile.flush(); vertexShaderFile.close(); glShaderSource(shaderId, 1, &vertexStr, NULL); glCompileShader(shaderId); getCompileShaderErrorInfo(shaderId); return shaderId; } void BaseOpenGLWindow::getCompileShaderErrorInfo(GLuint shaderId) { int success; char infoLog[512]; glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shaderId, 512, NULL, infoLog); qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog; } }
programId = buildAttachShaderAndReturnProgramId(":/QtForOpenCV4Tool/shader/girl_face.vert", ":/QtForOpenCV4Tool/shader/girl_face.frag");
9.将纹理贴上去
glBindVertexArray(VAO); glActiveTexture(GL_TEXTURE0);//几乎第一个纹理 glBindTexture(GL_TEXTURE_2D, texture);//绑定第一个纹理 glUseProgram(programId); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
标签:贴图,1.0,QT,OpenGL,TEXTURE,纹理,2D,programId,GL From: https://www.cnblogs.com/tony-yang-flutter/p/18374242