OpenGL之纹理贴图(Texture)
学习自:
https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/
先上一波效果图:
实际上就是:画了一个矩形,然后贴了两张图,下面是一个木窗,上面一个笑脸。
首先放上这次教程所需要的贴图和库文件的百度云
链接:https://pan.baidu.com/s/1Ejn65QoYW11cDukiC6ZFjg
提取码:hl93
(1)添加需要的库文件
我们本次教程的流程,用到了本地资源中的图片,读取和使用本地图片,需要使用一个新的库:stb_image.h
这里我已经下载好了,你们可以直接下载我的百度云,找到需要的头文件,然后加到自己的项目目录中。
(2)编写需要的shader类:这里的shader类和我们上一节的教程中是一样的
#ifndef SHADER_H
#define SHADER_H #include <glad/glad.h> // 包含glad来获取所有的必须OpenGL头文件 #include <string>
#include <fstream>
#include <sstream>
#include <iostream> class Shader
{
public:
// 程序ID
unsigned int ID; // 构造器读取并构建着色器
Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
// 使用/激活程序
void use();
// uniform工具函数
void setBool(const std::string &name, bool value) const;
void setInt(const std::string &name, int value) const;
void setFloat(const std::string &name, float value) const;
private:
void checkCompileErrors(unsigned int shader, std::string type);
}; #endif
#include "shader_s.h" Shader::Shader(const GLchar * vertexPath, const GLchar * fragmentPath)
{
// 1. 从文件路径中获取顶点/片段着色器
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// 保证ifstream对象可以抛出异常:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// 读取文件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件处理器
vShaderFile.close();
fShaderFile.close();
// 转换数据流到string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. 编译着色器
unsigned int vertex, fragment;
// 顶点着色器 vs
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, , &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// 片段着色器 fs
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, , &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// 着色器程序
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了 glDeleteShader(vertex);
glDeleteShader(fragment);
} void Shader::use()
{
glUseProgram(ID);
} void Shader::setBool(const std::string & name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
} void Shader::setInt(const std::string & name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} void Shader::setFloat(const std::string & name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} void Shader::checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, , NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, , NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
(3)编写shader脚本,这里有三个版本,大家可以直接放上(三)然后写完主程序后,再调整(一)和(二)
文件目录可以像我这样创建:
(一)仅放一张贴图
a)texture.vs顶点着色器:
#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.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
b)texture.vs片段着色器:
#version 330 core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D ourTexture; void main()
{
FragColor = texture(ourTexture, TexCoord);
}
此时我们的运行结果是这样:
(二)第一张贴图的基础上再加上渐变色(上一个教程的三色渐变)
修改的地方是我们的片段着色器
texture.fs
#version core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D ourTexture; void main()
{
//我们只需把纹理颜色与顶点颜色在片段着色器中相乘来混合二者的颜色:
FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
}
此时效果图如下:
(三)贴两张纹理
顶点着色器texture.vs
#version core
layout (location = ) in vec3 aPos;
layout (location = ) in vec3 aColor;
layout (location = ) in vec2 aTexCoord; out vec3 ourColor;
out vec2 TexCoord; void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
片段着色器texture.fs
#version core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2; uniform sampler2D ourTexture; void main()
{
//GLSL内建的mix函数需要接受两个值作为参数,并对它们根据第三个参数进行线性插值。
//如果第三个值是0.0
,它会返回第一个输入;如果是1.0
,会返回第二个输入值。//0.2
会返回80%
的第一个输入颜色和20%
的第二个输入颜色,即返回两个纹理的混合色。
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
最终输出颜色现在是两个纹理的结合:
(4)编写主程序:
关键代码的注释我已经翻译并且加上去,一些常规代码可以忽略或者把英文注释翻一下吧
#include <glad/glad.h>
#include <GLFW/glfw3.h> #include "stb_image.h"
#include "shader_s.h"
#include <iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window); // settings
const unsigned int SCR_WIDTH = ;
const unsigned int SCR_HEIGHT = ; int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -;
} // build and compile our shader zprogram
// ------------------------------------
Shader ourShader("../res/textures/texture.vs", "../res/textures/texture.fs"); // set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
// 位置信息 // 颜色信息 // 纹理 coords
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.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
};
unsigned int indices[] = {
, , , // 第一个三角形
, , // 第二个三角形
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(, &VAO);
glGenBuffers(, &VBO);
glGenBuffers(, &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); // position attribute
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*));
glEnableVertexAttribArray();
// color attribute
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float)));
glEnableVertexAttribArray();
// texture coord attribute
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float)));
glEnableVertexAttribArray(); // 加载并创建纹理
// -------------------------
unsigned int texture1, texture2;
// 第一张纹理 glGenTextures(, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// 为当前绑定的纹理对象设置环绕、过滤方式
// 将纹理包装设置为GL_REPEAT(默认包装方法)
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;
stbi_set_flip_vertically_on_load(true); //告诉stb_image.h在y轴上翻转加载的纹理。 unsigned char *data = stbi_load("../res/textures/container.jpg", &width, &height, &nrChannels, );
if (data)
{
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, width, height, , GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data); // texture 2
glGenTextures(, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
data = stbi_load("../res/textures/awesomeface.png", &width, &height, &nrChannels, );
if (data)
{
//请注意,awesomeface.png具有透明度,因此具有alpha通道,
//因此请务必告诉OpenGL数据类型为GL_RGBA
glTexImage2D(GL_TEXTURE_2D, , GL_RGBA, width, height, , GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data); //告诉每个采样器的opengl它属于哪个纹理单元(只需要做一次)
ourShader.use(); //激活着色器
// either set it manually like so:
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), );
// or set it via the texture class
ourShader.setInt("texture2", ); // render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window); // render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); // bind textures on corresponding texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2); // render container
ourShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, , GL_UNSIGNED_INT, ); // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
} // optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(, &VAO);
glDeleteBuffers(, &VBO);
glDeleteBuffers(, &EBO); // glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return ;
} // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
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(, , width, height);
}
OpenGL之纹理贴图(Texture)的更多相关文章
- android ndk调用OpenGL 实现纹理贴图Texture
android ndk调用OpenGL 实现纹理贴图Texture 时间 2014-06-25 05:24:39 CSDN博客 原文 http://blog.csdn.net/chrisfxs/a ...
- OpenGL入门1.4:纹理/贴图Texture
每一个小步骤的源码都放在了Github 的内容为插入注释,可以先跳过 前言 游戏玩家对Texture这个词应该不陌生,我们已经知道了怎么为每个顶点添加颜色来增加图形的细节,但,如果想让图形看起来更真实 ...
- Android OpenGL ES 开发(九): OpenGL ES 纹理贴图
一.概念 一般说来,纹理是表示物体表面的一幅或几幅二维图形,也称纹理贴图(texture).当把纹理按照特定的方式映射到物体表面上的时候,能使物体看上去更加真实.当前流行的图形系统中,纹理绘制已经成为 ...
- opengl学习笔记(四):openCV读入图片,openGL实现纹理贴图
在opengl中实现三维物体的纹理贴图的第一步就是要读入图片,然后指定该图片为纹理图片. 首先利用opencv的cvLoadImage函数把图像读入到内存中 img = cvLoadImage(); ...
- OpenGL(二十二) gluBuild2DMipmaps 加载Mip纹理贴图
当纹理被用于渲染一个面积比它本身小很多的对象时,会由于纹理图像的降采样率不足而导致混叠现象,主要的表现特征是纹理图像的闪烁,出现纹理躁动.特别是在场景远近移动变换时,这种闪烁情况更为明显,严重可能会影 ...
- IOS 中openGL使用教程3(openGL ES 入门篇 | 纹理贴图(texture)使用)
在这篇文章中,我们将学习如何在openGL中使用纹理贴图. penGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类.由于本文将以一张图片为例,因此我们为我们的纹理对象 ...
- OpenGL 纹理贴图
前一节实例代码中有个贴图操作. 今天就简单说明一下纹理贴图... 为了使用纹理贴图.我们首先需要启用纹理贴图功能. 我们可以在Renderer实现的onSurfaceCreated中定义启用: // ...
- OpenGL ES: 纹理采样 texture sample
Sampler (GLSL) Sampler通常是在Fragment shader(片元着色器)内定义的,这是一个uniform类型的变量,即处理不同的片元时这个变量是一致不变的.一个sampler和 ...
- 用OpenGL进行立方体表面纹理贴图
一.目的 掌握OpenGL中纹理对象的创建.绑定与使用方法. 二.简单介绍 1,连接静态库 #pragma comment(lib, "glut32.lib") #pragma c ...
随机推荐
- SAM宏观生态学空间分析帮助文档
宏观生态学分析软件帮助文档: 引言: 该软件是由布鲁塞尔..大学开发,目的是提供一个综合的空间分析计算平台,主要针对的是宏观生态学数据.该软件可以从网站...上自由获取,该软件的主要特征以及发表在20 ...
- 最近在写h5的页面,发现有一款框架还不错给大家推荐一下
wui 说一下自己写项目的体会吧,自我感觉wui还不错,能够让自己很快地把页面布局好,而且里面一些js效果也不用自己去手写jQuery代码很方便,下面让我们一起来认识一下wui这个框架吧 1,acco ...
- 前端开发需要掌握的SEO的知识点
SEO 工作的目的 seo 的工作目的是为了让网站更利于让各大搜索引擎抓取和收录,增加产品的曝光率. SEO 注意事项 1. 网站 TDK 标签的设置.title,description,keywor ...
- filesystem type ntfs not configured in kernel
移动硬盘是NTFS格式的,挂载时候kernel不支持这格式 出现:filesystem type ntfs not configured in kernel 解决:通过sudo yum install ...
- python常用技巧
1,关于tab键与4个空格: 由于不同平台间,tab键值设置有所区别,据相关介绍,官方在缩进方面推荐使用4个空格.方便起见,可设置tab自动转换为4个空格. 1.1在pycharm中: 通过fi ...
- 在阿里云开源镜像站中下载centOS7
镜像的选择 第一步.下载镜像 阿里云开源镜像站:http://mirrors.aliyun.com/ 选择centos进入 如下图: 如下图:选择centos7 再选择isos(镜像目录) 继续下一步 ...
- Asp.net core 学习笔记 Razor Page
更新 2019-04-27 最近做了更多的 research 发现微软视乎有意发展 razor page. razor page 的定位是 mvvm, 现在还有个叫 blazor 的东西, 类似用 c ...
- shell脚本while read line的使用
#### 题目要求计算文档a.txt中每一行中出现的数字个数并且要计算一下整个文档中一共出现了几个数字.例如a.txt内容如下:12aa*lkjskdjalskdflkskdjflkjj我们脚本名字为 ...
- QTL定位相关
1.原理 https://www.sohu.com/a/211301179_278730 较为详细
- ionic2 获取dom节点
ionic2页面上面获取dom节点,可以直接用原生的方法,document.querySelector()等, 但是不建议这样使用,建议使用官方的.就是要在获取的节点上加上#name的属性(相当于ge ...