/* 引入相应的库 */
#include <iostream>
using namespace std;
#define GLEW_STATIC
#include"Shader.h"
#include <GLFW/glfw3.h>
#include <GL/glew.h>
#include <SOIL2/stb_image.h>
#include <SOIL2/SOIL2.h>
int width, height;
//* (样例一:木板) 编写各顶点位置 + 读取纹理 */
GLfloat vertices_1[] =
{
//position // color // texture coords(纹理坐标)
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 2.0f, // 右上顶点 编号0
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, // 右下顶点 编号1
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 左下顶点 编号2
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f // 左上顶点 编号3
};
unsigned char* image = SOIL_load_image("T_image3.png", &width, &height, 0, SOIL_LOAD_RGBA); // 获取图片
/* 四个顶点的连接信息给出来 */
GLuint indices_1[] =
{
0, 1, 3, // 序号为 0、1、3 的顶点组合成一个三角形
1, 2, 3 // 序号为 1、2、3 的顶点组合成一个三角形
};
const GLint WIDTH = 600, HEIGHT = 600;
int main()
{
glfwInit();
GLFWwindow* window_1 = glfwCreateWindow(WIDTH, HEIGHT, "Learn OpenGL Texture test", nullptr, nullptr);
int screenWidth_1, screenHeight_1;
glfwGetFramebufferSize(window_1, &screenWidth_1, &screenHeight_1);
cout << "screenWidth_1 = " << screenWidth_1 << ", screenHeight = " << screenHeight_1 << endl;
glfwMakeContextCurrent(window_1);
glewInit();
/* 将我们自己设置的着色器文本传进来 */
Shader ourShader = Shader("shader_v.txt", "shader_f.txt"); // 相对路径
/* 设置顶点缓冲对象(VBO) + 设置顶点数组对象(VAO) + 索引缓冲对象(EBO) */
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_1), vertices_1, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices_1), indices_1, GL_STATIC_DRAW);
/* 设置链接顶点属性 */
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0); // 通道 0 打开
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1); // 通道 1 打开
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2); // 通道 2 打开
/* 生成纹理 */
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); // 读取图片信息
glGenerateMipmap(GL_TEXTURE_2D); // 多层渐进纹理
SOIL_free_image_data(image);
/* 纹理环绕方式 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); // S 坐标
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); // T 坐标
/* 纹理过滤 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* 纹理单元:下一节重点使用 */
ourShader.Use(); // don't forget to activate/use the shader before setting uniforms!
int textureLocation = glGetUniformLocation(ourShader.Program, "ourTexture"); // 找到着色器中 uniform 属性的名为"ourTexture"的纹理的索引
glUniform1i(textureLocation, 0); // 告诉 OpenGL 的着色器采样器属于哪个纹理单元
/* draw loop 画图循环 */
while (!glfwWindowShouldClose(window_1))
{
/* 视口 + 时间 */
glViewport(0, 0, screenWidth_1, screenHeight_1);
glfwPollEvents();
/* 渲染 + 清除颜色缓冲 */
glClearColor(0.5f, 0.8f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
/* 生成纹理 */
glActiveTexture(GL_TEXTURE0); // 激活 0 号纹理单元。最多 16 个通道
glBindTexture(GL_TEXTURE_2D, texture); // 绑定这个纹理到当前激活的纹理目标
/* 绘制图形 */
ourShader.Use();
glBindVertexArray(VAO); // 绑定 VAO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // 绑定 EBO
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 画两个三角形 从第0个顶点开始 一共画6次
glBindVertexArray(0); // 解绑定 VAO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑定 EBO
glBindTexture(GL_TEXTURE_2D, 0); // 解绑定 纹理
/* 交换缓冲 */
glfwSwapBuffers(window_1);
}
/* 释放资源 */
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate(); // 结束
return 0;
}
片段着色器代码
#version 330 core // 3.30版本
in vec3 ourColor;
in vec2 ourTextureCoords; // 将纹理坐标引入(从顶点着色器过来的)
out vec4 FragColor; // 输出是四个浮点数构成的一个向量 RGB+aerfa
uniform sampler2D ourTexture; // 纹理对象引入(从主函数过来的)
void main()
{
// FragColor = vec4(ourColor, 1.0f);
FragColor = texture(ourTexture, ourTextureCoords); // 采样获得纹理坐标
}
顶点着色器代码
#version 330 core // 3.30版本
layout(location = 0) in vec3 position; // 位置变量的顶点属性位置值为 0
layout(location = 1) in vec3 color; // 颜色变量的顶点属性位置值为 1
layout(location = 2) in vec2 textureCoords; // 纹理坐标只有两个浮点数 (s,t), 属性位置值为 2
out vec3 ourColor;
out vec2 ourTextureCoords; // 将纹理坐标传到片元着色器
void main()
{
gl_Position = vec4(position, 1.0f); // 核心函数(位置信息赋值)
// ourColor = color;
ourTextureCoords = vec2(textureCoords.x, 1-textureCoords.y);
}
着色器类
#pragma once // 为了避免同一个头文件被包含(include)多次
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
using namespace std;
#include <GL\glew.h>
#include <GLFW\glfw3.h>
// 我们自己的着色器
class Shader
{
private:
unsigned int vertex, fragment; // 顶点着色器 和 片元着色器
public:
unsigned int Program; // 着色器程序的ID
// Constructor(着色器构造函数)
Shader(const char* vertexPath, const char* fragmentPath)
{
// 文件读取系列的变量定义
string vertexCode;
string fragmentCode;
ifstream vShaderFile;
ifstream fShaderFile;
// 异常机制处理:保证ifstream对象可以抛出异常:
vShaderFile.exceptions(ifstream::badbit);
fShaderFile.exceptions(ifstream::badbit);
try
{
// 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
stringstream vShaderStream, fShaderStream;
// 读取文件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件处理器
vShaderFile.close();
fShaderFile.close();
// 转换数据流到string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (ifstream::failure e) { // 发生异常时输出
cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << endl;
}
/* 将 string 类型的字符串转化为 char数组 类型 */
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
/* 顶点着色器 */
vertex = glCreateShader(GL_VERTEX_SHADER); // 创建顶点着色器对象
glShaderSource(vertex, 1, &vShaderCode, NULL); // 将顶点着色器的内容传进来
glCompileShader(vertex); // 编译顶点着色器
int flag; // 用于判断编译是否成功
char infoLog[512];
glGetShaderiv(vertex, GL_COMPILE_STATUS, &flag); // 获取编译状态
if (!flag)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
}
/* 片元着色器 */
fragment = glCreateShader(GL_FRAGMENT_SHADER); // 创建片元着色器对象
glShaderSource(fragment, 1, &fShaderCode, NULL); // 将片元着色器的内容传进来
glCompileShader(fragment); // 编译顶点着色器
glGetShaderiv(fragment, GL_COMPILE_STATUS, &flag); // 获取编译状态
if (!flag)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
}
/* 着色器程序 */
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
if (!flag)
{
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
}
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// Deconstructor(析构函数)
~Shader()
{
glDetachShader(this->Program, vertex);
glDetachShader(this->Program, fragment);
glDeleteShader(vertex);
glDeleteShader(fragment);
glDeleteProgram(this->Program);
}
void Use()
{
glUseProgram(this->Program);
}
};
纹理坐标是作为0.0到1.0范围内的浮点值指定的。纹理坐标命名为s,t,r,q,支持从一维到三位的纹理坐标,并且可以选择一种对坐标进行缩放的方法。
纹理参数通过glTexParameter函数的变量来进行设置。该函数第一个参数指定这些参数将要应用在哪个纹理模式上,第二个参数指定了需要设置哪个纹理参数,最后一个参数用于设置特定的纹理参数的值。
纹理过滤是根据一个拉伸或收缩的纹理贴图计算颜色片段的过程。
不使用Shader.h时的代码
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL2/SOIL2.h>
#include <SOIL2/stb_image.h>
#include <sstream>
#include <string>
#include <fstream>
//顶点数组
GLfloat vertex[] =
{
0.5f,0.5f,0.0f, 0.0f,0.0f,0.0f, 2.0f,2.0f,
0.5f,-0.5f,0.0f, 0.0f,0.0f,0.0f, 2.0f,0.0f,
-0.5f,-0.5f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,
-0.5f,0.5f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.2f
};
int height, width;
//获取图片
unsigned char* image = SOIL_load_image("T_image3.png", &width, &height, 0, SOIL_LOAD_RGBA);
//索引数组
unsigned int index[] =
{
0,1,3,
1,2,3
};
//创建着色器
unsigned int createshader(std::string vertexshaderPath,std::string flagshaderPath)
{
//着色器代码
std::string vertexcode;
std::string flagcode;
//着色器代码流
std::stringstream vertexstream;
std::stringstream flagstream;
//着色器文件
std::ifstream vertexfile;
std::ifstream flagfile;
//打开着色器文件
vertexfile.open(vertexshaderPath);
flagfile.open(flagshaderPath);
//读取文件中流
vertexstream << vertexfile.rdbuf();
flagstream << flagfile.rdbuf();
//获取着色器代码
vertexcode = vertexstream.str();
flagcode = flagstream.str();
//转化为数组型
const char* vertexch = vertexcode.c_str();
const char* flagch = flagcode.c_str();
//编译着色器
unsigned int vertex, flag;
vertex = glCreateShader(GL_VERTEX_SHADER);
flag = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex,1,&vertexch,NULL);
glShaderSource(flag,1,&flagch,NULL);
glCompileShader(vertex);
glCompileShader(flag);
unsigned int program;
program=glCreateProgram();
glAttachShader(program,vertex);
glAttachShader(program,flag);
glLinkProgram(program);
return program;
}
int main()
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(600,600,"OPENGL2",NULL,NULL);
int screenWidth, screenHeight;
glfwGetFramebufferSize(window, &screenWidth, &screenHeight);
if (!window)
{
glfwTerminate();
}
glfwMakeContextCurrent(window);
//glfwSwapInterval(1);
glewInit();
//缓冲区
unsigned int VAO, VBO, EBO;
glGenBuffers(1,&VAO);
glGenBuffers(1,&VBO);
glGenBuffers(1,&EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertex),vertex,GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(index),index,GL_STATIC_DRAW);
//连接顶点
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
unsigned int shader;
shader = createshader("shader_v.txt", "shader_f.txt");
//纹理
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glUseProgram(shader);
int textureLocation = glGetUniformLocation(shader, "ourTexture");
glUniform1i(textureLocation, 0);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.5f, 0.8f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//生成纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//生成图形
glUseProgram(shader);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwDestroyWindow(window);
glfwTerminate();
}