加载与创建纹理:引入stb_image.h库(加载纹理图片用)
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
创建纹理并绑定:
GLuint TexBufferA;
glGenTextures(1,&TexBufferA);
//激活纹理
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,TexBufferA);
加载图片
int width,height,nrChannel;
stbi_set_flip_vertically_on_load(true);
unsigned char* data=stbi_load("wall.jpg",&width,&height,&nrChannel,0);
if (data)
{
// 生成纹理
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,data);
//生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
printf("load image fail1");
}
//释放图片
stbi_image_free(data);
注意:如果导入的图没有α通道,生成要用的是GL_RGB,不然程序会崩溃
更新纹理坐标数据
float vertices[] = {
// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
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 // 左上
};
纹理坐标在0-1之间
解析纹理顶点坐标属性
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
layout位置属性是2,顶点属性长度是2,数据类型是float,不需要归一化,一个顶点的所有数据是8个,步长是6
顶点着色器接受纹理坐标,并将坐标输出到片元着色器
layout(location=0) in vec3 aPos;
layout(location=1) in vec3 aColor ;
layout(location=2) in vec2 aTexCoord ;
out vec4 vertexColor;
//纹理uv坐标
out vec2 TexCoord;
void main(){
gl_Position=vec4(aPos.x,aPos.y,aPos.z,1.0f);
vertexColor=vec4(aColor.x,aColor.y,aColor.z,1.0f);
TexCoord=aTexCoord;
}
片元着色器接受顶点数据,定义纹理采样器
#version 330 core
in vec4 vertexColor;
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D ourTexture;
uniform sampler2D ourFace;
void main(){
FragColor=texture(ourTexture,TexCoord)*texture(ourFace,TexCoord);
}
回到主函数,在绘制循环中激活绑定纹理
//先激活再绑定
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,TexBufferA);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, TexBufferB);
设置采样器
//告诉采样器属于哪个纹理单元
glUniform1i(glGetUniformLocation(myShader->ID,"ourTexture"),1);
glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3);
纹理单元数字与定义纹理缓冲时绑定的纹理单元有关
main函数全部代码:
#include<iostream>
#define GLEW_STATIC
#include<GL/glew.h>
#include<GLFW/glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
float vertices[] = {
// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
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[] =
{
0,1,2,
2,3,0
};
int main()
{
//testShader->test();
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置核心模式
glfwInitHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗口
GLFWwindow* window = glfwCreateWindow(800, 800, "test", NULL, NULL);
if (window == NULL)
{
printf("failed");
glfwTerminate();
return -1;
}
//联系上下文
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
printf("failed");
glfwTerminate();
return -1;
}
glViewport(0, 0, 800, 800);
Shader* myShader = new Shader("vertexSource.txt", "fragmentSource.txt");
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//写入数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//使用索引绘制顶点
GLuint EBO;
glGenBuffers(1, &EBO);
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);
//创建纹理并绑定
GLuint TexBufferA;
glGenTextures(1,&TexBufferA);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,TexBufferA);
//加载图片
int width,height,nrChannel;
stbi_set_flip_vertically_on_load(true);
unsigned char* data=stbi_load("wall.jpg",&width,&height,&nrChannel,0);
if (data)
{
// 生成纹理
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,data);
//生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
printf("load image fail1");
}
//释放图片
stbi_image_free(data);
GLuint TexBufferB;
glGenTextures(1, &TexBufferB);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, TexBufferB);
unsigned char* data2 = stbi_load("awesomeface.png", &width, &height, &nrChannel, 0);
if (data2)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
printf("load image fail2");
}
stbi_image_free(data2);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,TexBufferA);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, TexBufferB);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
myShader->use();
//告诉采样器属于哪个纹理单元
glUniform1i(glGetUniformLocation(myShader->ID,"ourTexture"),1);
glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
注:这处没有封装的着色器代码