1.纹理采样:根据纹理坐标获取像素值
2.纹理环绕:当纹理坐标超出默认范围时纹理的重复方式,OpenGL提供了以下几种方式
对纹理环绕方式进行设置:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
3.纹理过滤:纹理坐标不依赖于分辨率,可以是任意浮点值,纹理像素映射到纹理坐标称为过滤。
两种纹理过滤方式:
(1) GL_NEAREST:选取中心点距离纹理坐标最近的像素值作为纹理的颜色
(2) GL_LINEAR: 它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色
设置纹理被放大或缩小时的过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
4.多级渐远纹理: 它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个(仅用于纹理被缩小时)
多级渐远纹理的过滤方式:
设置多级渐远纹理的过滤方式:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5.加载纹理:使用文件图像加载库stb_image.h,在源文件中引入stb_image.h并定义 STB_IMAGE_IMPLEMENTATION即可使用
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
main(){
int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
//释放图像内存
stbi_image_free(data);
}
6.创建纹理对象并配置:
(1)创建纹理对象,使用ID进行引用
unsigned int texture;
glGenTextures(1,&texture);
(2)绑定纹理到target,之后的任何纹理指令都会配置当前绑定的纹理(使用多个纹理时,需要配置完一个纹理之后,再绑定别的纹理进行配置)
glBindTexture(GL_TEXTURE_2D,texture);
(3)设置纹理参数
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);
(4)翻转y轴
stbi_set_flip_vertically_on_load(true);
(5)使用图像数据生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
(6)自动生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data)
第一个参数指定了纹理目标(Target)。设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。
第二个参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们也把纹理储存为RGB值。
第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
下个参数应该总是被设为0(历史遗留的问题)。
第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为char(byte)数组,我们将会传入对应值。
最后一个参数是真正的图像数据
7.使用纹理
(1)主程序中:在绘制前将纹理绑定至target
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
(2)shader中:
顶点着色器将纹理坐标传出给片元着色器
layout (location = 2) in vec2 aTexCoord;
out vec2 TexCoord;
void main() {
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
片元着色器中根据纹理target和纹理坐标进行采样
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main() {
FragColor = texture(ourTexture, TexCoord);
}
8.使用纹理单元:纹理在shader中定义类型为uniform,通过uniform1i我们可以将纹理绑定至不同纹理单元,在绘制前激活不同的纹理单元并绑定至target即可使用,默认激活纹理单元是GL_TEXTURE0
//设置纹理单元
unsigned int tex1Location = glGetUniformLocation(shaderProgram,"ourTexture1");
glUniform1i(tex1Location,0);
unsigned int tex2Location = glGetUniformLocation(shaderProgram,"ourTexture2");
glUniform1i(tex2Location,1);
//激活纹理单元
glActiveTexture(GL_TEXTURE0);
//绑定至target
glBindTexture(GL_TEXTURE_2D,texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,texture2);
9.使用两幅纹理进行混合:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include
#include
#include
extern void framebuffer_size_callback(GLFWwindow* window, int width, int height);
extern void processInput(GLFWwindow *window);
extern unsigned int SCR_WIDTH = 800;
extern unsigned int SCR_HEIGHT = 600;
const char * vertexShaderSource_TextureTest =
"#version 330 core\n"
"layout(location = 0)in vec3 aPos;\n"
"layout(location = 2)in vec2 aTexCoord;\n "
"layout(location = 1)in vec3 aColor;\n"
"out vec3 myColor;\n"
"out vec2 TexCoord;\n"
"void main(){\n"
"gl_Position = vec4(aPos,1.0f);\n"
"TexCoord = vec2(aTexCoord.x,aTexCoord.y);\n"
"myColor = aColor;\n"
"}\n";
const char * fragementShaderSource_TextureTest =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"in vec3 myColor;\n"
"uniform sampler2D ourTexture1;\n"
"uniform sampler2D ourTexture2;\n"
"void main(){\n"
"FragColor = mix(texture(ourTexture1,TexCoord),texture(ourTexture2,TexCoord),0.2);\n"
"}\n";
int DrawATexture(){
//初始化窗口和OpenGL
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
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);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//顶点着色器
//创建着色器对象
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
//着色器填充源代码
glShaderSource(vertexShader,1,&vertexShaderSource_TextureTest,NULL);
//编译着色器
glCompileShader(vertexShader);
//检测着色器是否编译成功,并查看错误信息
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" << infoLog << std::endl;
}
//片元着色器
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader,1,&fragementShaderSource_TextureTest,NULL);
glCompileShader(fragmentShader);
//检测着色器是否编译成功,并查看错误信息
int success_f;
char infoLog_f[512];
glGetShaderiv(fragmentShader,GL_COMPILE_STATUS,&success_f); //检测是否编译成功
if(!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog_f);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//创建程序对象
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::PROGRAM::LINK_FAILED"<