参考教程
LearnOpenGL强烈推荐,个人觉得比B站上的视频教程要好,讲的也更加清晰。
代码
顶点着色器
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 ainVColor;
layout (location = 2) in vec2 ainTextureCoord;
out vec3 aVColor;
out vec2 aVTextureCoord;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
aVColor=ainVColor;
aVTextureCoord=ainTextureCoord;
};
片段着色器
#version 460 core
in vec3 aVColor;
in vec2 aVTextureCoord;
uniform sampler2D textureUnit1;
uniform sampler2D textureUnit2;
out vec4 FragColor;
void main()
{
FragColor = mix(texture(textureUnit1,aVTextureCoord),texture(textureUnit2,aVTextureCoord),0.5) * vec4(aVColor,1.0);
};
着色器类
#ifndef SHADER_H
#define SHADER_H
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <glad/glad.h>
using namespace std;
class Shader
{
unsigned int id=-1;
public:
Shader(const char * vertexShaderSourceFile,const char * fragmentShaderSourceFile);
~ Shader();
void use();
void setBool(const char * uniformName, bool uniformValue) const;
void setInt(const char* uniformName, int uniformValue) const ;
void setFloat( const char* uniformName, float uniformValue) const;
unsigned int getId() const;
};
Shader:: Shader(const char* vertexShaderSourceFile, const char* fragmentShaderSourceFile)
{
// 1. 从文件路径中获取顶点/片段着色器
string vertexCode;
string fragmentCode;
ifstream vShaderFile;
ifstream fShaderFile;
// 保证ifstream对象可以抛出异常:
vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
try
{
// 打开文件
vShaderFile.open(vertexShaderSourceFile);
fShaderFile.open(fragmentShaderSourceFile);
std::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_SUCCESFULLY_READ" << endl;
}
unsigned int vertexShader;
unsigned int fragmentShader;
vertexShader= glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
glShaderSource(vertexShader, 1, &vShaderCode, NULL);
glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
int success;
char* infoLog = new char[512];
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
cout << "顶点着色器编译失败!" << endl;
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << infoLog << endl;
return;
}
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
cout << "片段着色器编译失败!" << endl;
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << infoLog << endl;
return;
}
unsigned shaderProgram;
shaderProgram= glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
cout << "着色器链接失败" << endl;
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << infoLog << endl;
return;
}
delete []infoLog;
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
this->id = shaderProgram;
}
Shader::~ Shader()
{
//释放着色器程序占用的资源
glDeleteProgram(this->id);
}
void Shader::use()
{
glUseProgram(this->id);
}
void Shader::setBool(const char* uniformName, bool uniformValue) const
{
int uniformLocation= glGetUniformLocation(this->id, uniformName);
if (uniformLocation == -1) {
cout << "This uniform variable does't exist in this shader program!" << endl;
return;
}
glUniform1i(uniformLocation, (int)uniformValue);
}
void Shader::setInt(const char* uniformName, int uniformValue) const
{
int uniformLocation = glGetUniformLocation(this->id, uniformName);
if (uniformLocation == -1) {
cout << "This uniform variable does't exist in this shader program!" << endl;
return;
}
glUniform1i(uniformLocation, uniformValue);
}
void Shader::setFloat(const char* uniformName, float uniformValue) const
{
int uniformLocation = glGetUniformLocation(this->id, uniformName);
if (uniformLocation == -1) {
cout << "This uniform variable does't exist in this shader program!" << endl;
return;
}
glUniform1f(uniformLocation, uniformValue);
}
unsigned int Shader::getId() const
{
return this->id;
}
#endif
主程序
#include <glad/glad.h>
#include <glfw3.h>
#include <iostream>
#include "stb_image.h"
#include "Shader.h"
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(1000, 1000, "Hello OpenGL", NULL, NULL);
if (window == NULL) {
cout << "创建窗口失败!" << endl;
glfwTerminate();
system("pause");
return 0;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
cout << "GLAD初始化失败!" << endl;
system("pause");
return 0;
}
//顶点数据:顶点坐标、顶点颜色、顶点纹理坐标
//注意这里的纹理坐标是基于图像坐标系,即坐标原点在左上角
float vertices[] = {
0.5f, 0.5f, 0.0f,1.0f, 0.0f, 0.0f,1.0f,0.0f, // 右上角
0.5f, -0.5f, 0.0f,0.0f, 1.0f, 0.0f,1.0f,1.0f, // 右下角
-0.5f, -0.5f, 0.0f,1.0f, 0.0f, 1.0f,0.0f,1.0f,// 左下角
-0.5f, 0.5f, 0.0f ,1.0f, 1.0f, 0.0f,0.0f,0.0f // 左上角
};
unsigned int indices[] = {
// 注意索引从0开始!
// 此例的索引(0,1,2,3)就是顶点数组vertices的下标,
// 这样可以由下标代表顶点组合成矩形
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
//初始化顶点数组合对象
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
//初始化顶点缓冲合对象
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//初始化着色器
Shader shaderProgram("./vertex.sha","./fragment.sha");
if (shaderProgram.getId() == -1) {
cout << "着色器生成失败!" << endl;
system("pause");
return 0;
}
//顶点数据与着色器顶点属性之间的链接关系
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);
//创建第一个纹理对象
//初始化纹理对象
int width, height, nChannels;
unsigned char* textureData1 = stbi_load("./texture.png",&width,&height,&nChannels,0);
if (!textureData1) {
cout << "载入纹理图像失败!" << endl;
system("pause");
return 0;
}
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
//设置纹理的缠绕方式
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//设置纹理的过滤(重采样方式)
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理图案
//注意四通道图像一定要以RGBA的形式读取
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData1);
//生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(textureData1);
//创建第二个纹理对象
unsigned char* textureData2 = stbi_load("./face.png", &width, &height, &nChannels, 0);
if (!textureData2) {
cout << "载入纹理图像失败!" << endl;
system("pause");
return 0;
}
unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
//设置纹理的缠绕方式
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//设置纹理的过滤(重采样方式)
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理图案
//注意四通道图像一定要以RGBA的形式读取
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData2);
//生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(textureData2);
//将片段着色器多个采样器与纹理对象一一对应起来
shaderProgram.use();
shaderProgram.setInt("textureUnit1", 0);
shaderProgram.setInt("textureUnit2", 1);
//恢复到初始化状态
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
while (!glfwWindowShouldClose(window)) {
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//激活纹理单元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texture1);
//激活纹理单元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
//激活着色器
shaderProgram.use();
glBindVertexArray(VAO);
//以线框模式进行绘制
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//以面模式进行绘制
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
//释放相关资源,退出程序
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram.getId());
glDeleteTextures(1, &texture1);
glDeleteTextures(1, &texture2);
glfwTerminate();
system("pause");
return 1;
}
实现效果
输入