可编程渲染管线OpenGL学习随笔(3)--着色器

前言

在前面几节的学习中,发现每次都需要编写着色程序,特别麻烦,还有没有更好的方法呢?答案是肯定的,本节内容主要就是将着色器程序分装为着色器类,以后需要用到时可以直接调用,就很方便。
本文主要参考:https://learnopenglcn.github.io/01%20Getting%20started/05%20Shaders/

一、着色器是什么?

GLSL着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。
着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。

二、着色器

1.着色器类


#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h> // 包含glad来获取所有的必须OpenGL头文件
#include<glm/glm.hpp>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;


class Shader
{
public:

	// 程序ID
	unsigned int ID;

	// 构造 读取并构建着色器
	Shader(const char* vertexPath, const char* fragmentPath,const char* geometryPath=nullptr)
	{
		//从路径中获取顶点或片段着色器
		string vertexCode,fragmentCode,geometryCode;
		ifstream vShaderFile;
		ifstream fShaderFile;
		ifstream geometryFile;
		
		//保证ifstream对象可以抛出异常
		vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
		fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
		geometryFile.exceptions(ifstream::failbit | 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();

			if (geometryPath != nullptr)
			{
				geometryFile.open(geometryPath);
				stringstream gShaderStream;
				gShaderStream << geometryFile.rdbuf();
				geometryFile.close();
				geometryCode = gShaderStream.str();
			}
		}
		catch (ifstream::failure &e)
		{
			cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << endl;
		}
		const char *vShaderCode = vertexCode.c_str();
		const char *fShaderCode = fragmentCode.c_str();

		//编译
		unsigned int vertex, fragment;
		int success;
		char infoLog[512];
		//顶点着色器
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vShaderCode, NULL);
		glCompileShader(vertex);

		glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			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, &success);
		if (!success)
		{
			glGetShaderInfoLog(fragment, 512, NULL, infoLog);
			cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
		}
		
		unsigned int geometry;
		if (geometryPath != nullptr)
		{
			const char *gShaderCode = geometryCode.c_str();
			geometry = glCreateShader(GL_GEOMETRY_SHADER);
			glShaderSource(geometry, 1, &gShaderCode, NULL);
			glCompileShader(geometry);

			glGetShaderiv(geometry, GL_COMPILE_STATUS, &success);
			if (!success)
			{
				glGetShaderInfoLog(geometry, 512, NULL, infoLog);
				cout << "ERROR::SHADER::GEOMRTRY::COMPILATION_FAILED\n" << infoLog << endl;
			}
		}

		//着色程序
		ID = glCreateProgram();
		glAttachShader(ID, vertex);
		glAttachShader(ID, fragment);
		if (geometryPath != nullptr)
			glAttachShader(ID, geometry);
		glLinkProgram(ID);

		//打印链接错误
		glGetProgramiv(ID, GL_LINK_STATUS, &success);
		if (!success)
		{
			glGetProgramInfoLog(ID, 512, NULL, infoLog);
			cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n" << infoLog << endl;
		}

		//删除顶点着色器、片段着色器
		glDeleteShader(vertex);
		glDeleteShader(fragment);
		if (geometryPath != nullptr)
			glDeleteShader(geometry);
	}
	
	// 使用/激活程序
	void use()
	{
		glUseProgram(ID);
	}
	// uniform工具函数
	void setBool(const string &name, bool value) const
	{
		glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
	}

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

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

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

	void setVec2(const string &name, float x,float y) const
	{
		glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
	}


	void setVec3(const string &name, const glm::vec3 &value) const
	{
		glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
	}

	void setVec3(const string &name, float x,float y,float z) const
	{
		glUniform3f(glGetUniformLocation(ID, name.c_str()), x,y,z);
	}

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

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

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

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

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

#endif

2.主程序(三个角颜色不同的三角形)

#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include"shader.h"
#include<iostream>
using namespace std;

const unsigned int SCR_HEIGHT = 600;
const unsigned int SCR_WIDTH = 800;

void framebuff_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()
{
	//GLFW初始化
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	//创建窗口
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenglLearn", NULL, NULL);
	if (window == NULL)
	{
		cout << "Failed to create GLFW window" << endl;
		glfwTerminate();
		return -1;
	}

	//窗口链接上下文
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuff_size_callback);

	//检测GLAD初始化
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		cout << "Failed to initialize GLAD" << endl;
		return -1;
	}

    //编译、链接的着色器程序
	Shader ourShader("shader.vs","shader.fs");

	//三角形坐标 
	float vertices[] = {
		-0.5f,-0.5f,0.0f, 1.0f,0.0f,0.0f,//第一个点为红色
		0.5f,-0.5f,0.0f, 0.0f,1.0f,0.0f,//第二个点为绿色
		0.0f, 0.5f,0.0f, 0.0f,0.0f,1.0f //第三个点为蓝色
	};

	//创建顶点数组对象,顶点缓冲对象
	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);


	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);

	//赋值,将数据从cpu发送到gpu的顶点缓存中
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//顶点属性
	//坐标
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//颜色属性
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);

	//解绑
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

	while (!glfwWindowShouldClose(window))
	{
		//输入
		processInput(window);

		//渲染
		//清除颜色缓冲
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

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

		//绘制三角形
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);

		//交互缓冲,以及有无触发事件
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	//删除顶点数组、顶点缓冲

	glDeleteVertexArrays(0, &VAO);
	glDeleteBuffers(0, &VBO);
	

	//释放内存
	glfwTerminate();
	system("pause");
	return 0;
}

结果展示

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值