#include "stb_image.h"
用于对不同格式图片的读取。
纹理坐标为载入纹理的范围位置,即图片的宽高范围都在0~1之间,根据填入的小数来确定纹理载入的位置
GLfloat vertices[] = {
//location(顶点坐标) color texture coords(纹理坐标)
-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, //左中--左上
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, //左下--左下
0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //中下--右下
};
若 纹理坐标 >1.0, 或 纹理坐标 < 0.0 ,则会以设定的纹理围绕方式重复。(纹理围绕方式将在下方解释)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
GLuint texture1;
glGenTextures(1, &texture1);//将texture1定义为纹理
glBindTexture(GL_TEXTURE_2D, texture1);//将texture与2D纹理绑定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
第一个参数: 纹理目标
GL_TEXTURE_1D, GL_TEXTURE_1D_ARRAY,
GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY,
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP,
GL_TEXTURE_CUBE_MAP_ARRAY, or GL_TEXTURE_RECTANGLE.
第二个参数: 设置的选项与应用的纹理轴
GL_DEPTH_STENCIL_TEXTURE_MODE,
GL_TEXTURE_BASE_LEVEL,
GL_TEXTURE_COMPARE_FUNC, GL_TEXTURE_COMPARE_MODE,
GL_TEXTURE_LOD_BIAS,
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
//过滤方式 在下方会说明
GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_MAX_LEVEL,
GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G,
GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A,
GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, or GL_TEXTURE_WRAP_R.
//WRAP选项–纹理围绕轴 为该小结(设置纹理围绕方式)内容
第三个参数: 设置的选项与应用的纹理轴
WRAP选项–纹理围绕轴围绕方式
环绕方式 | 描述 |
---|---|
GL_REPEAT | 对纹理的默认行为。重复纹理图像。 |
GL_MIRRORED_REPEAT | 和GL_REPEAT一样,但每次重复图片是镜像放置的。 |
GL_CLAMP_TO_EDGE | 纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。 |
GL_CLAMP_TO_BORDER | 超出的坐标为用户指定的边缘颜色。 |
更多查看https://khronos.org/registry/OpenGL-Refpages/gl4/官方文档
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
filter 过滤器 , linear 线性的(非官方)。
第一二个参数同上
第三个参数:
参数 | 描述 |
---|---|
GL_NEAREST | 返回距离指定纹理坐标最近的纹理元素的值。 |
GL_LINEAR | 返回最接近指定纹理坐标的纹理元素的加权平均值。根据GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T的值,以及确切的映射,这些可以包括从纹理的其他部分包装或重复的项。 |
flip 翻转 ,vertically垂直的
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // y轴翻转纹理
//水平翻转要在片段着色器中设置。
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);
//当前绑定的纹理对象就会被附加上纹理图像。
glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理。
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
glTexImage2D(纹理目标,多级渐远纹理的级别,储存为何种格式,宽,高,0,源图的格式,数据类型,真正的图像数据)
stbi_image_free(data);
GLuint texture2;
glGenTextures(1, &texture2);//传入引用,初始化texture2
glBindTexture(GL_TEXTURE_2D, texture2);
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);
//glTexParameteri(纹理维度,改变类型,改变值);
stbi_set_flip_vertically_on_load(true);
data = stbi_load("./awesomeface.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//png格式加载为GL_RGBA格式
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
给纹理采样器分配一个位置值(默认纹理单元是0,所以多个纹理单元需要分配)
OpenGL至少保证有16个纹理单元供你使用 (对着色器的操作)
PVPCShader.use(); //激活要绑定的着色器后才可分配
PVPCShader.setInt("sampler1", 0);//将着色器中texture1采样器分配到GL_TEXTURE0
PVPCShader.setInt("sampler2", 1);//将着色器中texture2采样器分配到GL_TEXTURE1
将纹理与纹理单元联系(与着色器无关)
不需要在联系时激活着色器,在使用时激活即可。(即PVPCShader.use()可在此代码之后)
glActiveTexture(GL_TEXTURE0);// 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture1);//绑定这个纹理到当前激活的纹理单元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
PVPCShader.use();
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 2*3);//数量必须为3的倍数
在glDrawArray函数中调用着色器。以GL_TRIANGLES绘制顶点,从第0个数据开始向后绘制2*3个顶点。
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 outColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
outColor = aColor;
TexCoord = aTexCoord;
}
#version 330 core
out vec4 FragColor;
in vec3 outColor;
in vec2 TexCoord;
uniform sampler2D sampler1;//保证在分配采样器时的名称与该名称一致
uniform sampler2D sampler2;//否则会出现一些无提示的错误,不容易发现
void main()
{
FragColor = mix(texture(sampler1, TexCoord), texture(sampler2, TexCoord),0.8) * vec4(outColor, 1.0f);
}
FragColor 输出的最终片段颜色
mix(texture1,texture2, double). //以double的比例混合两个纹理
texture(sampler1, TexCoord);// texture纹理(图片处理方式,图片纹理覆盖点);
*号 用于颜色和纹理的混合。
#include
//包含命名空间std
#include
#include
//glad需要在glfw之前,因为GLAD的头文件包含了正确的OpenGL头文件,glfw依赖于OpenGL
#include "stb_image.h"
#include "Shader.h"//着色器设置
#include "call_back.h"//回调函数设置
int main(){
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(800, 600, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//glad初始化(GLAD是用来管理OpenGL的函数指针的)
//load all OpenGL function pointers
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
设置视口
//int width, height;
//glfwGetFramebufferSize(window, &width, &height);
//glViewport(0, 0, width, height);
//生成着色器
Shader PVPCShader("./Normal.vs","./setcolor.fs");
Shader ChangingColorShader("./Normal.vs", "./Changing.fs");
/*
第一组数据处理----两个填充三角形************************
*/
//添加顶点数据
GLfloat vertices[] = {
//location(顶点坐标) color texture coords(纹理坐标)
-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, //左中--左上
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, //左下--左下
0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //中下--右下
0.0f, 0.0f, 0.0f, 0.3f, 0.3f, 0.3f, 1.0f, 2.0f, //居中--右上
-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, //左中--左上
0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //中下--右下
};
//set up buffers and configure vertex attributes
//设置缓存区配置顶点属性
GLuint VBO, VAO;
glGenBuffers(1, &VBO);//获取一个buffer名为VBO
glGenVertexArrays(1, &VAO); // 获取一个VertexArrays名为VAO
glBindVertexArray(VAO);//绑定VAO为当前使用顶点数组
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0));
glEnableVertexAttribArray(0);//启用顶点属性,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);
//加载创建纹理
//------------
GLuint texture1;
//texture 1
//-----------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
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(纹理映射)
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // y轴翻转纹理
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);
//glTexImage2D(纹理目标,多级渐远纹理的级别,储存为何种格式,宽,高,0,源图的格式,数据类型,真正的图像数据)
//当前绑定的纹理对象就会被附加上纹理图像。
glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理。
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);//释放图像的内存
//纹理2
GLuint texture2;
glGenTextures(1, &texture2);//传入引用,初始化texture2
glBindTexture(GL_TEXTURE_2D, texture2);
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);
//glTexParameteri(纹理维度,改变类型,改变值);
stbi_set_flip_vertically_on_load(true);
unsigned char* data2 = stbi_load("./awesomeface.png", &width, &height, &nrChannels, 0);
if (data2)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);//png格式加载为GL_RGBA格式
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data2);
//给纹理采样器分配一个位置值(默认纹理单元是0,所以多个纹理单元需要分配)
//OpenGL至少保证有16个纹理单元供你使用
PVPCShader.use(); //激活要绑定的着色器后才可分配
PVPCShader.setInt("sampler1", 0);//将着色器中texture1采样器分配到GL_TEXTURE0
PVPCShader.setInt("sampler2", 1);//将着色器中texture2采样器分配到GL_TEXTURE1
/*
第二组数据处理----两个线框三角形************************************
*/
//使用索引数据存储点的顺序,用IBO索引缓冲对象管理
GLfloat vertices1[] = {
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 indices1[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
//设置缓存区配置顶点属性
GLuint VBO1,EBO1,VAO1;
//生成三类对象,不分先后顺序
glGenBuffers(1, &EBO1);
glGenBuffers(1, &VBO1);
glGenVertexArrays(1, &VAO1);
//绑定三类对象
glBindVertexArray(VAO1);//VAO必须为第一
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
glBindBuffer(GL_ARRAY_BUFFER, VBO1);
//绑定缓冲数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
//Loop
while (!glfwWindowShouldClose(window)){//检查glfw是否被要求退出
glfwPollEvents();
//检查有没有触发什么事件,然后调用对应的回调函数.
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
PVPCShader.use();
glActiveTexture(GL_TEXTURE0);// 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture1);//绑定这个纹理到当前激活的纹理单元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//设置为填充模式(默认)
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 2*3);//数量必须为3的倍数
float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
ChangingColorShader.use();//设置uniform值前必须先使用程序。
ChangingColorShader.setVec3("Color", 0.0f, greenValue, 0.0f);//Color赋值RGB
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//设置为线框模式
glBindVertexArray(VAO1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
//交换颜色缓冲
}
//Game Loop
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO1);
glDeleteBuffers(1, &VBO1);
glDeleteBuffers(1, &EBO1);
glDeleteProgram(PVPCShader.ID);
glfwTerminate();
//释放GLFW分配的内存。
return 0;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
使用glBlendFunc的三种alpha处理方式可以处理不同情况的计算。
具体使用细节还待完善!!!