第三课,OpenGL的着色器

优化

首先将着色器的编译链接进行优化

//Shader.h
#pragma once
#include <glad/glad.h>
class Shader{
public:
	//程序ID
	unsigned int ID;
	//构造器读取并构建着色器
	Shader(const GLchar*, const GLchar*);
	//使用、激活程序
	void use();
	//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;
    
};
//Shader.cpp
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "Shader.h"
GLuint CreateFragmentShaders(GLchar* ShaderSource);
GLuint CreateVertexShaders(GLchar* ShaderSource);
GLuint LinkShaderPrograms(const GLuint& vertexShader, const GLuint& fragmentShader);
Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
	std::string vertexCode;
	std::string fragmentCode;
	std::ifstream vShaderFile;//输入文件流 in from file stream
	std::ifstream fShaderFile;
	vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fShaderFile.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();
	}
	catch (std::ifstream::failure e) {
		std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
	}
	const char* vshaderCode = vertexCode.c_str();//返回一个正规的指向c字符串的指针,主要为了c兼容
	const char* fshaderCode = fragmentCode.c_str();

	/*使用顶点着色器*/
	GLuint vertexShader = CreateVertexShaders((GLchar*)vshaderCode);

	/*使用片段着色器*/
	GLuint fragmentShader = CreateFragmentShaders((GLchar*)fshaderCode);

	/*链接为着色器程序对象*/
	ID = LinkShaderPrograms(vertexShader, fragmentShader);

	//把着色器对象链接到程序对象以后,我们就不再需要它们了
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
}

void Shader::use() {
    glUseProgram(ID);
}

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]);
//}

GLuint LinkShaderPrograms(const GLuint& vertexShader, const GLuint& fragmentShader) {
    GLuint shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    //检查链接状态
    GLint success;
    GLchar infoLog[512];
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::PROGRAM::SHADER::LINK_FAILED\\n" << infoLog << std::endl;
    }
    return shaderProgram;
}

GLuint CreateFragmentShaders(GLchar* ShaderSource) {
    GLuint fragmentShader;
    GLint success;
    GLchar infoLog[512];//存储错误信息
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &ShaderSource, NULL);
    glCompileShader(fragmentShader);

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

GLuint CreateVertexShaders(GLchar* ShaderSource) {
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &ShaderSource, NULL);
    glCompileShader(vertexShader);
    //判断编译是否成功
    GLint success;
    GLchar infoLog[512];//存储错误信息
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    //检查是否编译成功
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        //获取错误消息
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\\n" << infoLog << std::endl;
    }
    return vertexShader;
}

其中:

1.Shader的构造器(Shader::Shader)传入参数(顶点着色器文件地址,片段着色器文件地址),构建链接为着色器程序对象,保存该着色器程序对象—-命名为ID。

2.uniform工具函数中,首先需要使用

glGetUniformLocation(着色器程序对象, 全局变量名称)

获取该名称全局变量的地址。
然后使用

glUniform**(全局变量的地址, 改变的值*);

改变该变量的值。

将上方两式联合使用:

glUniform1i( glGetUniformLocation( ID , name ), value1, value2, ~ );

在OpenGL主函数中用

Shader ShaderProgram1("./vertex1.vs","./fragment1.fs");
Shader ShaderProgram2("./vertex2.vs","./fragment2.fs");

来设置图形管线。

着色器内部参数传递

在顶点着色器中传入的参数由out传入后续的着色器中。
每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用。

例如:

//vertexShader
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec3 outColor;
void main(){
    gl_Position = vec4(position, 1.0);
    outColor = color;
}

该顶点着色器将1号位的数据传入color,再将color传入输出参数outColor.
在另一边有

//fragmentShader
in vec3 outColor;
out vec4 FragColor;
void main(){
	FragColor = vec4(outColor,1.0f);
}

接收outcolor。


在主函数中,有:

GLfloat vertices[] = {
        //location          color
        -1.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
         0.0f,  0.0f, 0.0f, 0.3f, 0.3f, 0.3f,
        -1.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
    };
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(0);//启用顶点属性
glEnableVertexAttribArray(1);

对不同顶点属性传不同类型的值。

uniform全局变量

若在着色器中有uniform vec3 Color;
现需要对着色器内参数Color传值。
有:

ShaderProgram.use();//设置uniform值前必须先使用程序。
ShaderProgram.set*参数类型(全局变量名称, value1,value2,~);

value由主函数内计算给定。

全部代码

#include <iostream>
//包含命名空间std

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

#include "Shader.h"
//glad需要在glfw之前,因为GLAD的头文件包含了正确的OpenGL头文件,glfw依赖于OpenGL

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode){
    // 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true
    // 关闭应用程序
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    glViewport(0, 0, width, height);
}

int main(){
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
    if (window == nullptr) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
     glfwMakeContextCurrent(window);
     glfwSetKeyCallback(window, key_callback);
     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    //glad初始化(GLAD是用来管理OpenGL的函数指针的)
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);

    //生成着色器
    Shader PVPCShader("./Normal.vs","./setcolor.fs");
    Shader ChangingColorShader("./Normal.vs", "./Changing.fs");

    /*使用顶点缓冲将顶点储存在显卡的内存中,用VBO顶点缓冲对象管理*/
    GLfloat vertices[] = {
        //location          color
        -1.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
         0.0f,  0.0f, 0.0f, 0.3f, 0.3f, 0.3f,
        -1.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
    };

    GLuint VBO, VAO;
    glGenBuffers(1, &VBO);
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));
    glEnableVertexAttribArray(0);//启用顶点属性
    glEnableVertexAttribArray(1);

    /*使用索引数据存储点的顺序,用IBO索引缓冲对象管理*/
    GLfloat vertices1[] = {
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
    };
    unsigned int indices1[] = { // 注意索引从0开始! 
        0, 1, 3, // 第一个三角形
        1, 2, 3  // 第二个三角形
    };
    
    

    GLuint VBO1,EBO1,VAO1;
    //生成三类对象,不分先后顺序
    glGenBuffers(1, &EBO1);
    glGenBuffers(1, &VBO1);
    glGenVertexArrays(1, &VAO1);
    //绑定三类对象
    glBindVertexArray(VAO1);//VAO必须为第一
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    //绑定缓冲数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//设置为线框模式
    //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//设置为填充模式(默认)
    //设置为一类,在后续将一直为该类,直到再次修改

    while (!glfwWindowShouldClose(window)){//检查glfw是否被要求退出
        glfwPollEvents();
        //检查有没有触发什么事件,然后调用对应的回调函数.
        
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
  
        PVPCShader.use();
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//设置为填充模式(默认)
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 2*3);//数量必须为3的倍数

        float timeValue = glfwGetTime();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
        ChangingColorShader.use();//设置uniform值前必须先使用程序。
        ChangingColorShader.setVec3("Color", 0.0f, greenValue, 0.0f);
        
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//设置为线框模式
        glBindVertexArray(VAO1);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        //交换颜色缓冲
    }
    //Game Loop

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO1);
    glDeleteBuffers(1, &VBO1);
    glDeleteBuffers(1, &EBO1);
    glDeleteProgram(PVPCShader.ID);

    glfwTerminate();
    //释放GLFW分配的内存。

    return 0;
}

//vertexShader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;

out vec3 outColor;

void main(){
    gl_Position = vec4(position, 1.0);
    outColor = color;
}
//fragmentShader
//1
#version 330 core
out vec4 FragColor;
uniform vec3 Color;
void main(){
    FragColor = vec4(Color,1.0f);
}

//2
#version 330 core
in vec3 outColor;
out vec4 FragColor;
void main(){
	FragColor = vec4(outColor,1.0f);
}
 
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 共2条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片