其他分享
首页 > 其他分享> > opengl2D的学习(最终版)

opengl2D的学习(最终版)

作者:互联网

着色器头文件Shader.h

#ifndef __SHADER_H__
#define __SHADER_H__

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>


class Shader {
public:
	unsigned int ID;

	//构造器读取并构建着色器
	Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr);
	//激活着色器程序
	void use();
	//释放着色器程序
	void del();

	//uniform工具函数
	void setBool(const std::string& name, bool value) const;
	void setInt(const std::string& name, int value) const;
	void setFloat(const std::string& name, float value) const;
	void setVec2(const std::string& name, const glm::vec2& value) const;
	void setVec2(const std::string& name, float x, float y) const;
    void setVec3(const std::string& name, const glm::vec3& value) const;
    void setVec3(const std::string& name, float x, float y, float z) const;
    void setVec4(const std::string& name, const glm::vec4& value) const;
    void setVec4(const std::string& name, float x, float y, float z, float w);
    void setMat2(const std::string& name, const glm::mat2& mat) const;
    void setMat3(const std::string& name, const glm::mat3& mat) const;
    void setMat4(const std::string& name, const glm::mat4& mat) const;
	//检测编译,链接是否成功
	void checkCompileErrors(unsigned int shader, std::string type);
};

#endif // __SHADER_H__

着色器头文件的实现Shader.cpp

#include "Shader.h"

//构造函数
Shader::Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath)
{
    //从文件路径中获取顶点/片段着色器
    std::string vertexCode;//存储顶点着色器的代码
    std::string fragmentCode;//存储片段着色器的代码
    std::string geometryCode;//存储几何着色器的代码
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;
    std::ifstream gShaderFile;
    
    //保证ifstream对象可以抛出异常
    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try
    {
        //打开文件
        vShaderFile.open(vertexPath);//打开存储顶点着色器代码的文件
        fShaderFile.open(fragmentPath);//打开存储片段着色器代码的文件

        std::stringstream vShaderStream, fShaderStream;

        //读取文件中的内容
        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();

        //关闭文件处理器
        vShaderFile.close();
        fShaderFile.close();

       
        //将读取的数据转换为string
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();

        //如果几何着色器也要改
        if (geometryPath != nullptr)
        {
            gShaderFile.open(geometryPath);
            std::stringstream gShaderStream;
            gShaderStream << gShaderFile.rdbuf();
            gShaderFile.close();
            geometryCode = gShaderStream.str();
        }
    }
    catch (std::ifstream::failure& e)
    {
        std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
    }
    const char* vShaderCode = vertexCode.c_str();//指向顶点着色器的代码
    const char* fShaderCode = fragmentCode.c_str();//指向片段着色器的代码
    
    //编译着色器
    unsigned int vertex, fragment, geometry;
    
    //编译顶点着色器
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);
    checkCompileErrors(vertex, "VERTEX");//检查编译是否成功
    
    //编译片段着色器
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);
    checkCompileErrors(fragment, "FRAGMENT");//检查编译是否成功

    //编译几何着色器
    if (geometryPath != nullptr)
    {
        const char* gShaderCode = geometryCode.c_str();
        geometry = glCreateShader(GL_GEOMETRY_SHADER);
        glShaderSource(geometry, 1, &gShaderCode, NULL);
        glCompileShader(geometry);
        checkCompileErrors(geometry, "GEOMETRY");
    }
    
    //着色器程序,把顶点,片段着色器链接起来
    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    if (geometryPath != nullptr)
        glAttachShader(ID, geometry);
    glLinkProgram(ID);
    checkCompileErrors(ID, "PROGRAM");//检查链接是否成功
    
    //销毁顶点,片段着色器,因为他们已经链接到程序中了
    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

//激活着色器程序
void Shader::use() {
    glUseProgram(ID);
}

//释放着色器程序
void Shader::del() {
    glDeleteProgram(ID);
}

//设置uniform的值
void Shader::setBool(const std::string& name, bool value) const {
    glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}

void Shader::setInt(const std::string& name, int value) const {
    glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}

void Shader::setFloat(const std::string& name, float value) const {
    glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}

void Shader::setVec2(const std::string& name, const glm::vec2& value) const
{
    glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void Shader::setVec2(const std::string& name, float x, float y) const
{
    glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}

void Shader::setVec3(const std::string& name, const glm::vec3& value) const
{
    glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void Shader::setVec3(const std::string& name, float x, float y, float z) const
{
    glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

void Shader::setVec4(const std::string& name, const glm::vec4& value) const
{
    glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}

void Shader::setVec4(const std::string& name, float x, float y, float z, float w)
{
    glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}

void Shader::setMat2(const std::string& name, const glm::mat2& mat) const
{
    glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void Shader::setMat3(const std::string& name, const glm::mat3& mat) const
{
    glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void Shader::setMat4(const std::string& name, const glm::mat4& mat) const
{
    glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}


//检查链接,编译是否成功
void Shader::checkCompileErrors(unsigned int shader, std::string type) {
    int success;
    char infoLog[1024];
    if (type != "PROGRAM"){
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success) {
            glGetShaderInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
                << infoLog
                << "\n -- --------------------------------------------------- -- "
                << std::endl;
        }
        
    }
    else {
        glGetProgramiv(shader, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
                << infoLog
                << "\n -- --------------------------------------------------- -- "
                << std::endl;
        }
    }
}



顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec4 ourColor;
out vec2 TexCoord;

uniform mat4 transform4;
uniform mat4 transform3;

void main()
{
    
    gl_Position = transform4 * vec4(aPos, 1.0f);
    ourColor =  transform3 * vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

片段着色器

#version 330 core
out vec4 FragColor;

in vec4 ourColor;
in vec2 TexCoord;


uniform sampler2D texture1;
uniform sampler2D texture2;

uniform float mixValue;



void main()
{
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), mixValue) * ourColor;
}

main文件

#include <iostream>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

void framebuffer_size_callback(GLFWwindow* window, int width, int height);//当窗口大小改变的处理
void processInput(GLFWwindow* window);//监控用户的输入

unsigned int const WIND_WIDTH = 800;//窗口的宽
unsigned int const WIND_HEIGHT = 600;//窗口的高
char const* WIND_NAME = "container";//窗口的名字

int main() {
	glfwInit();//激活GLFW库:在使用大部分GLFW函数之前你得激活它
	//因为我用的是opengl3.3 (点号前是主版本,点号后是副版本)
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置opengl主版本号, 3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置opengl副版本号, 3
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//配置opengl的模式
	//GLFW_OPENGL_CORE_PROFILE代表核心模式

	//创建窗口,获取句柄
	GLFWwindow* window = glfwCreateWindow(WIND_WIDTH, WIND_HEIGHT, WIND_NAME, nullptr, nullptr);//最后两个参数一个代表显示模式,一个代表是否共享.
	if (window == NULL) {
		std::cout << "打开窗口失败!" << std::endl;
		glfwTerminate();//回收分配的资源
		return -1;
	}
	glfwMakeContextCurrent(window);//设置当前上下文
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//设置监控窗口大小的回调函数
	//第一个是窗口的句柄, 第二个是处理的函数(也就是回调函数).

	//初始化GLAD库,大部分GLAD函数被使用前,都要先激活GLAD库
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "初始化GLAD库失败了" << std::endl;
		return -1;
	}

	//自定义着色器
	Shader myShader("shader.vs", "shader.fs");

	//矩形顶点数组
	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, 3,
		1, 2, 3
	};

	unsigned int VAO, VBO, EBO;
	glGenVertexArrays(1, &VAO);//为VAO创建一个顶点数组对象
	glGenBuffers(1, &VBO);//为VBO创建一个缓冲区对象
	glGenBuffers(1, &EBO);//为EBO创建一个缓存区对象

	glBindVertexArray(VAO);//当前绑定的顶点数组是VAO

	glBindBuffer(GL_ARRAY_BUFFER, VBO);//当前绑定的缓存区对象是VBO
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//设置VBO的数据

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//当前绑定的缓存区对象是EBO
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//设置EBO的数据

	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);//激活上面的设置

	unsigned int texture1, texture2;

	glGenTextures(1, &texture1);//为texture1创建一个纹理对象
	glBindTexture(GL_TEXTURE_2D, texture1);//将texture1绑定为2D纹理对象

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//让纹理图片在x轴上重复贴
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//让纹理图片在y轴上重复帖

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//图片缩小时,用线性过滤
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//图片放大是,用线性过滤

	int width, height, nrChannels;
	std::string imageName = "container.jpg";
	stbi_set_flip_vertically_on_load(true);//让图片上下颠倒
	unsigned char* data = stbi_load(imageName.c_str(), &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 << "获取图片container.jpg失败" << std::endl;
	}
	stbi_image_free(data);//释放纹理图片信息的内存(因为已经绑定完成了)

	glGenTextures(1, &texture2);//为texture2创建一个纹理对象
	glBindTexture(GL_TEXTURE_2D, texture2);//把texture2绑定为2D纹理对象

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//让纹理图片在x轴上重复
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//让纹理图片在y轴上重复

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//纹理图片放大时,线性过滤
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//纹理图片缩小是,线性过滤

	imageName = "awesomeface.png";
	data = stbi_load(imageName.c_str(), &width, &height, &nrChannels, 0);
	if (data) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//把纹理图片与当前纹理对象链接
		glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
	}
	stbi_image_free(data);//释放图片资源

	myShader.use();//激活着色器程序(设置uniform之前必须激活)
	myShader.setInt("texture1", 0);//uniform采样器texture1属于纹理单元0
	myShader.setInt("texture2", 1);//uniform采样器texture1属于纹理单元1


	//循环渲染
	while (!glfwWindowShouldClose(window)/*检测窗口是否关闭*/)
	{
		processInput(window);

		//red,green,blue,alpha 最后一个参数代表透明度,alpha
		glClearColor(0.2f, 0.3f, 0.4f, 1.0f);//设置背景颜色,也就是:设置颜色缓存的清除值
		glClear(GL_COLOR_BUFFER_BIT);//将缓存清除为预先的设置值。(因为缓存之前可能是别的颜色)

		glActiveTexture(GL_TEXTURE0);//纹理单元0
		glBindTexture(GL_TEXTURE_2D, texture1);//绑定texture1上
		
		glActiveTexture(GL_TEXTURE1);//纹理单元1
		glBindTexture(GL_TEXTURE_2D, texture2);//绑定在texture2上

		

		myShader.use();//激活着色器程序

		float timeValue = glfwGetTime();//获取当前时间
		float change1 = sin(timeValue) / 2;//变化差值
		float change2 = cos(timeValue) / 2;//变化差值

		glm::mat4 transform3 = glm::mat4(1.0f);//4x4的矩阵 改图形的颜色
		transform3 = glm::translate(transform3, glm::vec3(change1, change2, change2));

		glm::mat4 transform4 = glm::mat4(1.0f);//4x4的矩阵 改图形的大小,位置,旋转
		transform4 = glm::translate(transform4, glm::vec3(change1, change2, 0.0f));//改位置
		transform4 = glm::scale(transform4, glm::vec3(change1, change1, 0.0f));//改大小
		transform4 = glm::rotate(transform4, float(timeValue), glm::vec3(0.0f, 0.0f, 1.0f));//旋转

		myShader.setMat4("transform4", transform4);//更新uniform的值
		myShader.setMat4("transform3", transform3);//更新uniform的值
		myShader.setFloat("mixValue", change1);//更新uniform的值
		
		
		glBindVertexArray(VAO);//启用VAO中介
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//以索引的形式画

		glfwSwapBuffers(window);//交换缓冲区(因为是双缓冲)
		glfwPollEvents();//处理响应事件,没有这个函数,回调函数不会被调用。
	}

	glDeleteVertexArrays(1, &VAO);//回收分配给VAO的资源
	glDeleteBuffers(1, &VBO);//回收分配给VBO的资源
	glDeleteBuffers(1, &EBO);//回收分配给EBO的资源
	myShader.del();//释放着色器程序

	glfwTerminate();//回收所有资源
	return 0;
}

//处理窗口大小被改变时的响应的回调函数
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) {//如果用户按下ESC键
		glfwSetWindowShouldClose(window, true);//关闭窗口
	}
}

标签:std,const,string,void,学习,最终版,include,着色器,opengl2D
来源: https://blog.csdn.net/qq_58665528/article/details/120929575